aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib')
-rw-r--r--host/lib/convert/convert_fc32_item32.cpp17
-rw-r--r--host/lib/convert/convert_pack_sc12.cpp2
-rw-r--r--host/lib/convert/convert_unpack_sc12.cpp63
-rw-r--r--host/lib/convert/sse2_fc32_to_sc16.cpp38
-rw-r--r--host/lib/convert/sse2_sc16_to_fc32.cpp38
-rw-r--r--host/lib/transport/libusb1_base.cpp23
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp99
-rw-r--r--host/lib/transport/super_recv_packet_handler.hpp3
-rw-r--r--host/lib/transport/super_send_packet_handler.hpp2
-rw-r--r--host/lib/transport/udp_zero_copy.cpp3
-rw-r--r--host/lib/types/CMakeLists.txt3
-rw-r--r--host/lib/types/tune.cpp7
-rw-r--r--host/lib/types/wb_iface.cpp (renamed from host/lib/usrp/cores/wb_iface.cpp)7
-rw-r--r--host/lib/usrp/README15
-rw-r--r--host/lib/usrp/b100/b100_impl.cpp6
-rw-r--r--host/lib/usrp/b100/b100_impl.hpp2
-rw-r--r--host/lib/usrp/b100/usb_zero_copy_wrapper.cpp1
-rw-r--r--host/lib/usrp/b200/b200_iface.cpp314
-rw-r--r--host/lib/usrp/b200/b200_iface.hpp18
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp21
-rw-r--r--host/lib/usrp/b200/b200_impl.hpp16
-rw-r--r--host/lib/usrp/b200/b200_io_impl.cpp34
-rw-r--r--host/lib/usrp/common/fifo_ctrl_excelsior.hpp5
-rw-r--r--host/lib/usrp/common/fx2_ctrl.cpp6
-rw-r--r--host/lib/usrp/cores/CMakeLists.txt1
-rw-r--r--host/lib/usrp/cores/gpio_core_200.hpp6
-rw-r--r--host/lib/usrp/cores/i2c_core_100.hpp4
-rw-r--r--host/lib/usrp/cores/i2c_core_100_wb32.hpp4
-rw-r--r--host/lib/usrp/cores/i2c_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/radio_ctrl_core_3000.cpp130
-rw-r--r--host/lib/usrp/cores/radio_ctrl_core_3000.hpp7
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.cpp5
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_3000.cpp5
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_3000.hpp4
-rw-r--r--host/lib/usrp/cores/rx_frontend_core_200.cpp4
-rw-r--r--host/lib/usrp/cores/rx_frontend_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/rx_vita_core_3000.hpp4
-rw-r--r--host/lib/usrp/cores/spi_core_100.hpp4
-rw-r--r--host/lib/usrp/cores/spi_core_3000.hpp4
-rw-r--r--host/lib/usrp/cores/time64_core_200.cpp1
-rw-r--r--host/lib/usrp/cores/time64_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/time_core_3000.hpp4
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_200.cpp3
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_3000.cpp3
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_3000.hpp4
-rw-r--r--host/lib/usrp/cores/tx_frontend_core_200.cpp2
-rw-r--r--host/lib/usrp/cores/tx_frontend_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/tx_vita_core_3000.hpp4
-rw-r--r--host/lib/usrp/cores/user_settings_core_200.cpp2
-rw-r--r--host/lib/usrp/cores/user_settings_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/wb_iface.hpp75
-rw-r--r--host/lib/usrp/dboard/db_dbsrx.cpp22
-rw-r--r--host/lib/usrp/dboard/db_dbsrx2.cpp6
-rw-r--r--host/lib/usrp/dboard/db_sbx_common.cpp132
-rw-r--r--host/lib/usrp/dboard/db_sbx_common.hpp28
-rw-r--r--host/lib/usrp/dboard/db_sbx_version3.cpp118
-rw-r--r--host/lib/usrp/dboard/db_sbx_version4.cpp120
-rw-r--r--host/lib/usrp/dboard/db_tvrx.cpp2
-rw-r--r--host/lib/usrp/dboard/db_wbx_common.hpp2
-rw-r--r--host/lib/usrp/e100/e100_impl.hpp2
-rw-r--r--host/lib/usrp/gps_ctrl.cpp2
-rw-r--r--host/lib/usrp/usrp1/io_impl.cpp2
-rw-r--r--host/lib/usrp/usrp1/usrp1_iface.cpp12
-rw-r--r--host/lib/usrp/usrp1/usrp1_iface.hpp7
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp8
-rw-r--r--host/lib/usrp/usrp2/usrp2_clk_regs.hpp14
-rw-r--r--host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp5
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp2
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp7
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp4
-rw-r--r--host/lib/utils/paths.cpp27
-rw-r--r--host/lib/utils/tasks.cpp99
74 files changed, 1057 insertions, 615 deletions
diff --git a/host/lib/convert/convert_fc32_item32.cpp b/host/lib/convert/convert_fc32_item32.cpp
index 29bfefd46..641fc2608 100644
--- a/host/lib/convert/convert_fc32_item32.cpp
+++ b/host/lib/convert/convert_fc32_item32.cpp
@@ -28,7 +28,7 @@ typedef boost::uint32_t (*to32_type)(boost::uint32_t);
template <typename type, to32_type tohost>
struct convert_fc32_item32_1_to_star_1 : public converter
{
- convert_fc32_item32_1_to_star_1(void)
+ convert_fc32_item32_1_to_star_1(void):_scalar(0.0)
{
//NOP
}
@@ -48,9 +48,9 @@ struct convert_fc32_item32_1_to_star_1 : public converter
{
const item32_t i32 = tohost(input[i++]);
const item32_t q32 = tohost(input[i++]);
- const float i_f32 = reinterpret_cast<const float &>(i32);
- const float q_f32 = reinterpret_cast<const float &>(q32);
- output[o] = std::complex<type>(type(i_f32*_scalar), type(q_f32*_scalar));
+ const float *i_f32p = reinterpret_cast<const float *>(&i32);
+ const float *q_f32p = reinterpret_cast<const float *>(&q32);
+ output[o] = std::complex<type>(type((*i_f32p)*_scalar), type((*q_f32p)*_scalar));
}
}
@@ -60,7 +60,7 @@ struct convert_fc32_item32_1_to_star_1 : public converter
template <typename type, to32_type towire>
struct convert_star_1_to_fc32_item32_1 : public converter
{
- convert_star_1_to_fc32_item32_1(void)
+ convert_star_1_to_fc32_item32_1(void):_scalar(0.0)
{
//NOP
}
@@ -80,9 +80,10 @@ struct convert_star_1_to_fc32_item32_1 : public converter
{
const float i_f32 = type(input[i].real()*_scalar);
const float q_f32 = type(input[i].imag()*_scalar);
- const item32_t i32 = towire(reinterpret_cast<const item32_t &>(i_f32));
- const item32_t q32 = towire(reinterpret_cast<const item32_t &>(q_f32));
- output[o++] = i32; output[o++] = q32;
+ const item32_t *i32p = reinterpret_cast<const item32_t *>(&i_f32);
+ const item32_t *q32p = reinterpret_cast<const item32_t *>(&q_f32);
+ output[o++] = towire(*i32p);
+ output[o++] = towire(*q32p);
}
}
diff --git a/host/lib/convert/convert_pack_sc12.cpp b/host/lib/convert/convert_pack_sc12.cpp
index 680814994..92cd5d152 100644
--- a/host/lib/convert/convert_pack_sc12.cpp
+++ b/host/lib/convert/convert_pack_sc12.cpp
@@ -67,7 +67,7 @@ void convert_star_4_to_sc12_item32_3
template <typename type, towire32_type towire>
struct convert_star_1_to_sc12_item32_1 : public converter
{
- convert_star_1_to_sc12_item32_1(void)
+ convert_star_1_to_sc12_item32_1(void):_scalar(0.0)
{
//NOP
}
diff --git a/host/lib/convert/convert_unpack_sc12.cpp b/host/lib/convert/convert_unpack_sc12.cpp
index f578b6c95..a2aec2ae5 100644
--- a/host/lib/convert/convert_unpack_sc12.cpp
+++ b/host/lib/convert/convert_unpack_sc12.cpp
@@ -32,6 +32,17 @@ struct item32_sc12_3x
item32_t line2;
};
+/*
+ * convert_sc12_item32_3_to_star_4 takes in 3 lines with 32 bit each
+ * and converts them 4 samples of type 'std::complex<type>'.
+ * The structure of the 3 lines is as follows:
+ * _ _ _ _ _ _ _ _
+ * |_ _ _1_ _ _|_ _|
+ * |_2_ _ _|_ _ _3_|
+ * |_ _|_ _ _4_ _ _|
+ *
+ * The numbers mark the position of one complex sample.
+ */
template <typename type, tohost32_type tohost>
void convert_sc12_item32_3_to_star_4
(
@@ -73,7 +84,7 @@ void convert_sc12_item32_3_to_star_4
template <typename type, tohost32_type tohost>
struct convert_sc12_item32_1_to_star_1 : public converter
{
- convert_sc12_item32_1_to_star_1(void)
+ convert_sc12_item32_1_to_star_1(void):_scalar(0.0)
{
//NOP
}
@@ -84,17 +95,48 @@ struct convert_sc12_item32_1_to_star_1 : public converter
_scalar = scalar/unpack_growth;
}
+ /*
+ * This converter takes in 24 bits complex samples, 12 bits I and 12 bits Q, and converts them to type 'std::complex<type>'.
+ * 'type' is usually 'float'.
+ * For the converter to work correctly the used managed_buffer which holds all samples of one packet has to be 32 bits aligned.
+ * We assume 32 bits to be one line. This said the converter must be aware where it is supposed to start within 3 lines.
+ *
+ */
void operator()(const input_type &inputs, const output_type &outputs, const size_t nsamps)
{
- const item32_sc12_3x *input = reinterpret_cast<const item32_sc12_3x *>(size_t(inputs[0]) & ~0x3);
+ /*
+ * Looking at the line structure above we can identify 4 cases.
+ * Each corresponds to the start of a different sample within a 3 line block.
+ * head_samps derives the number of samples left within one block.
+ * Then the number of bytes the converter has to rewind are calculated.
+ */
+ const size_t head_samps = size_t(inputs[0]) & 0x3;
+ size_t rewind = 0;
+ switch(head_samps)
+ {
+ case 0: break;
+ case 1: rewind = 9; break;
+ case 2: rewind = 6; break;
+ case 3: rewind = 3; break;
+ }
+
+ /*
+ * The pointer *input now points to the head of a 3 line block.
+ */
+ const item32_sc12_3x *input = reinterpret_cast<const item32_sc12_3x *>(size_t(inputs[0]) - rewind);
std::complex<type> *output = reinterpret_cast<std::complex<type> *>(outputs[0]);
//helper variables
std::complex<type> dummy0, dummy1, dummy2;
size_t i = 0, o = 0;
- //handle the head case
- const size_t head_samps = size_t(inputs[0]) & 0x3;
+ /*
+ * handle the head case
+ * head_samps holds the number of samples left in a block.
+ * The 3 line converter is called for the whole block and already processed samples are dumped.
+ * We don't run into the risk of a SIGSEGV because input will always point to valid memory within a managed_buffer.
+ * Furthermore the bytes in a buffer remain unchanged after they have been copied into it.
+ */
switch (head_samps)
{
case 0: break; //no head
@@ -111,7 +153,18 @@ struct convert_sc12_item32_1_to_star_1 : public converter
i++; o += 4;
}
- //handle the tail case
+ /*
+ * handle the tail case
+ * The converter can be called with any number of samples to be converted.
+ * This can end up in only a part of a block to be converted in one call.
+ * We never have to worry about SIGSEGVs here as long as we end in the middle of a managed_buffer.
+ * If we are at the end of managed_buffer there are 2 precautions to prevent SIGSEGVs.
+ * Firstly only a read operation is performed.
+ * Secondly managed_buffers allocate a fixed size memory which is always larger than the actually used size.
+ * e.g. The current sample maximum is 2000 samples in a packet over USB.
+ * With sc12 samples a packet consists of 6000kb but managed_buffers allocate 16kb each.
+ * Thus we don't run into problems here either.
+ */
const size_t tail_samps = nsamps - o;
switch (tail_samps)
{
diff --git a/host/lib/convert/sse2_fc32_to_sc16.cpp b/host/lib/convert/sse2_fc32_to_sc16.cpp
index 90bf0ed04..69786d7ce 100644
--- a/host/lib/convert/sse2_fc32_to_sc16.cpp
+++ b/host/lib/convert/sse2_fc32_to_sc16.cpp
@@ -27,6 +27,7 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_le, 1, PRIORITY_SIMD){
const __m128 scalar = _mm_set_ps1(float(scale_factor));
+ // this macro converts values faster by using SSE intrinsics to convert 4 values at a time
#define convert_fc32_1_to_item32_1_nswap_guts(_al_) \
for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
@@ -48,17 +49,25 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_le, 1, PRIORITY_SIMD){
size_t i = 0;
- //dispatch according to alignment
+ // need to dispatch according to alignment for fastest conversion
switch (size_t(input) & 0xf){
- case 0x8:
- xx_to_item32_sc16<uhd::htowx>(input, output, 1, scale_factor); i++;
case 0x0:
+ // the data is 16-byte aligned, so do the fast processing of the bulk of the samples
+ convert_fc32_1_to_item32_1_nswap_guts(_)
+ break;
+ case 0x8:
+ // the first sample is 8-byte aligned - process it to align the remainder of the samples to 16-bytes
+ xx_to_item32_sc16<uhd::htowx>(input, output, 1, scale_factor);
+ i++;
+ // do faster processing of the bulk of the samples now that we are 16-byte aligned
convert_fc32_1_to_item32_1_nswap_guts(_)
break;
- default: convert_fc32_1_to_item32_1_nswap_guts(u_)
+ default:
+ // we are not 8 or 16-byte aligned, so do fast processing with the unaligned load
+ convert_fc32_1_to_item32_1_nswap_guts(u_)
}
- //convert remainder
+ // convert any remaining samples
xx_to_item32_sc16<uhd::htowx>(input+i, output+i, nsamps-i, scale_factor);
}
@@ -68,6 +77,7 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_be, 1, PRIORITY_SIMD){
const __m128 scalar = _mm_set_ps1(float(scale_factor));
+ // this macro converts values faster by using SSE intrinsics to convert 4 values at a time
#define convert_fc32_1_to_item32_1_bswap_guts(_al_) \
for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
@@ -88,16 +98,24 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_be, 1, PRIORITY_SIMD){
size_t i = 0;
- //dispatch according to alignment
+ // need to dispatch according to alignment for fastest conversion
switch (size_t(input) & 0xf){
- case 0x8:
- xx_to_item32_sc16<uhd::htonx>(input, output, 1, scale_factor); i++;
case 0x0:
+ // the data is 16-byte aligned, so do the fast processing of the bulk of the samples
+ convert_fc32_1_to_item32_1_bswap_guts(_)
+ break;
+ case 0x8:
+ // the first value is 8-byte aligned - process it and prepare the bulk of the data for fast conversion
+ xx_to_item32_sc16<uhd::htonx>(input, output, 1, scale_factor);
+ i++;
+ // do faster processing of the remaining samples now that we are 16-byte aligned
convert_fc32_1_to_item32_1_bswap_guts(_)
break;
- default: convert_fc32_1_to_item32_1_bswap_guts(u_)
+ default:
+ // we are not 8 or 16-byte aligned, so do fast processing with the unaligned load
+ convert_fc32_1_to_item32_1_bswap_guts(u_)
}
- //convert remainder
+ // convert any remaining samples
xx_to_item32_sc16<uhd::htonx>(input+i, output+i, nsamps-i, scale_factor);
}
diff --git a/host/lib/convert/sse2_sc16_to_fc32.cpp b/host/lib/convert/sse2_sc16_to_fc32.cpp
index c03e41585..0ac7f1798 100644
--- a/host/lib/convert/sse2_sc16_to_fc32.cpp
+++ b/host/lib/convert/sse2_sc16_to_fc32.cpp
@@ -28,6 +28,7 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_SIMD){
const __m128 scalar = _mm_set_ps1(float(scale_factor)/(1 << 16));
const __m128i zeroi = _mm_setzero_si128();
+ // this macro converts values faster by using SSE intrinsics to convert 4 values at a time
#define convert_item32_1_to_fc32_1_nswap_guts(_al_) \
for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
@@ -50,17 +51,25 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_SIMD){
size_t i = 0;
- //dispatch according to alignment
+ // need to dispatch according to alignment for fastest conversion
switch (size_t(output) & 0xf){
- case 0x8:
- item32_sc16_to_xx<uhd::htowx>(input, output, 1, scale_factor); i++;
case 0x0:
+ // the data is 16-byte aligned, so do the fast processing of the bulk of the samples
+ convert_item32_1_to_fc32_1_nswap_guts(_)
+ break;
+ case 0x8:
+ // the first sample is 8-byte aligned - process it to align the remainder of the samples to 16-bytes
+ item32_sc16_to_xx<uhd::htowx>(input, output, 1, scale_factor);
+ i++;
+ // do faster processing of the bulk of the samples now that we are 16-byte aligned
convert_item32_1_to_fc32_1_nswap_guts(_)
break;
- default: convert_item32_1_to_fc32_1_nswap_guts(u_)
+ default:
+ // we are not 8 or 16-byte aligned, so do fast processing with the unaligned load and store
+ convert_item32_1_to_fc32_1_nswap_guts(u_)
}
- //convert remainder
+ // convert any remaining samples
item32_sc16_to_xx<uhd::htowx>(input+i, output+i, nsamps-i, scale_factor);
}
@@ -71,6 +80,7 @@ DECLARE_CONVERTER(sc16_item32_be, 1, fc32, 1, PRIORITY_SIMD){
const __m128 scalar = _mm_set_ps1(float(scale_factor)/(1 << 16));
const __m128i zeroi = _mm_setzero_si128();
+ // this macro converts values faster by using SSE intrinsics to convert 4 values at a time
#define convert_item32_1_to_fc32_1_bswap_guts(_al_) \
for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
@@ -92,16 +102,24 @@ DECLARE_CONVERTER(sc16_item32_be, 1, fc32, 1, PRIORITY_SIMD){
size_t i = 0;
- //dispatch according to alignment
+ // need to dispatch according to alignment for fastest conversion
switch (size_t(output) & 0xf){
- case 0x8:
- item32_sc16_to_xx<uhd::htonx>(input, output, 1, scale_factor); i++;
case 0x0:
+ // the data is 16-byte aligned, so do the fast processing of the bulk of the samples
+ convert_item32_1_to_fc32_1_bswap_guts(_)
+ break;
+ case 0x8:
+ // the first sample is 8-byte aligned - process it to align the remainder of the samples to 16-bytes
+ item32_sc16_to_xx<uhd::htonx>(input, output, 1, scale_factor);
+ i++;
+ // do faster processing of the bulk of the samples now that we are 16-byte aligned
convert_item32_1_to_fc32_1_bswap_guts(_)
break;
- default: convert_item32_1_to_fc32_1_bswap_guts(u_)
+ default:
+ // we are not 8 or 16-byte aligned, so do fast processing with the unaligned load and store
+ convert_item32_1_to_fc32_1_bswap_guts(u_)
}
- //convert remainder
+ // convert any remaining samples
item32_sc16_to_xx<uhd::htonx>(input+i, output+i, nsamps-i, scale_factor);
}
diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp
index 0ef53db0a..8bd0f4354 100644
--- a/host/lib/transport/libusb1_base.cpp
+++ b/host/lib/transport/libusb1_base.cpp
@@ -19,10 +19,12 @@
#include <uhd/exception.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/utils/log.hpp>
+#include <uhd/utils/tasks.hpp>
#include <uhd/types/dict.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/foreach.hpp>
+#include <boost/bind.hpp>
#include <cstdlib>
#include <iostream>
@@ -37,9 +39,11 @@ public:
libusb_session_impl(void){
UHD_ASSERT_THROW(libusb_init(&_context) == 0);
libusb_set_debug(_context, debug_level);
+ task_handler = task::make(boost::bind(&libusb_session_impl::libusb_event_handler_task, this, _context));
}
~libusb_session_impl(void){
+ task_handler.reset();
libusb_exit(_context);
}
@@ -49,6 +53,21 @@ public:
private:
libusb_context *_context;
+ task::sptr task_handler;
+
+ /*
+ * Task to handle libusb events. There should only be one thread per libusb_context handling events.
+ * Using more than one thread can result in excessive CPU usage in kernel space (presumably from locking/waiting).
+ * The libusb documentation says it is safe, which it is, but it neglects to state the cost in CPU usage.
+ * Just don't do it!
+ */
+ UHD_INLINE void libusb_event_handler_task(libusb_context *context)
+ {
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ libusb_handle_events_timeout(context, &tv);
+ }
};
libusb::session::sptr libusb::session::get_global_session(void){
@@ -274,6 +293,10 @@ public:
return libusb::device_descriptor::make(this->get_device())->get().idProduct;
}
+ bool firmware_loaded() {
+ return (get_manufacturer() == "Ettus Research LLC");
+ }
+
private:
libusb::device::sptr _dev; //always keep a reference to device
};
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp
index 197e257da..2d18e1623 100644
--- a/host/lib/transport/libusb1_zero_copy.cpp
+++ b/host/lib/transport/libusb1_zero_copy.cpp
@@ -73,6 +73,15 @@ struct lut_result_t
int completed;
libusb_transfer_status status;
int actual_length;
+ boost::mutex mut;
+ boost::condition_variable usb_transfer_complete;
+};
+
+// Created to be used as an argument to boost::condition_variable::timed_wait() function
+struct lut_result_completed {
+ const lut_result_t& _result;
+ lut_result_completed(const lut_result_t& result):_result(result) {}
+ bool operator()() const {return (_result.completed ? true : false);}
};
/*!
@@ -84,48 +93,11 @@ struct lut_result_t
static void LIBUSB_CALL libusb_async_cb(libusb_transfer *lut)
{
lut_result_t *r = (lut_result_t *)lut->user_data;
- r->completed = 1;
+ boost::lock_guard<boost::mutex> lock(r->mut);
r->status = lut->status;
r->actual_length = lut->actual_length;
-}
-
-/*!
- * Wait for a managed buffer to become complete.
- *
- * This routine processes async events until the transaction completes.
- * We must call the libusb handle events in a loop because the handler
- * may complete managed buffers other than the one we are waiting on.
- *
- * We cannot determine if handle events timed out or processed an event.
- * Therefore, the timeout condition is handled by using boost system time.
- *
- * \param ctx the libusb context structure
- * \param timeout the wait timeout in seconds
- * \param completed a reference to the completed flag
- * \return true for completion, false for timeout
- */
-UHD_INLINE bool wait_for_completion(libusb_context *ctx, const double timeout, int &completed)
-{
- //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_completed(ctx, &tv, &completed);
- 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;
- tv.tv_usec = 10000; /*10ms*/
- libusb_handle_events_timeout_completed(ctx, &tv, &completed);
- }
-
- return completed;
+ r->completed = 1;
+ r->usb_transfer_complete.notify_one(); // wake up thread waiting in wait_for_completion() member function below
}
/***********************************************************************
@@ -154,7 +126,7 @@ public:
template <typename buffer_type>
UHD_INLINE typename buffer_type::sptr get_new(const double timeout)
{
- if (wait_for_completion(_ctx, timeout, result.completed))
+ if (wait_for_completion(timeout))
{
if (result.status != LIBUSB_TRANSFER_COMPLETED) throw uhd::runtime_error(str(boost::format(
"usb %s transfer status: %d") % _name % int(result.status)));
@@ -164,9 +136,31 @@ public:
return typename buffer_type::sptr();
}
+ // This is public because it is accessed from the libusb_zero_copy_single constructor
lut_result_t result;
+ /*!
+ * Wait for a managed buffer to become complete.
+ *
+ * \param timeout the wait timeout in seconds. A negative value will wait forever.
+ * \return true for completion, false for timeout
+ */
+ UHD_INLINE bool wait_for_completion(const double timeout)
+ {
+ boost::unique_lock<boost::mutex> lock(result.mut);
+ if (!result.completed) {
+ if (timeout < 0.0) {
+ result.usb_transfer_complete.wait(lock);
+ } else {
+ const boost::system_time timeout_time = boost::get_system_time() + boost::posix_time::microseconds(long(timeout*1000000));
+ result.usb_transfer_complete.timed_wait(lock, timeout_time, lut_result_completed(result));
+ }
+ }
+ return result.completed;
+ }
+
private:
+
boost::function<void(libusb_zero_copy_mb *)> _release_cb;
const bool _is_recv;
const std::string _name;
@@ -252,8 +246,6 @@ public:
~libusb_zero_copy_single(void)
{
- libusb_context *ctx = libusb::session::get_global_session()->get_context();
-
//cancel all transfers
BOOST_FOREACH(libusb_transfer *lut, _all_luts)
{
@@ -261,8 +253,10 @@ public:
}
//process all transfers until timeout occurs
- int completed = 0;
- wait_for_completion(ctx, 0.01, completed);
+ BOOST_FOREACH(libusb_zero_copy_mb *mb, _enqueued)
+ {
+ mb->wait_for_completion(0.01);
+ }
//free all transfers
BOOST_FOREACH(libusb_transfer *lut, _all_luts)
@@ -276,19 +270,18 @@ public:
{
typename buffer_type::sptr buff;
libusb_zero_copy_mb *front = NULL;
+ boost::mutex::scoped_lock lock(_mutex);
+ if (_enqueued.empty())
{
- boost::mutex::scoped_lock l(_mutex);
- if (_enqueued.empty())
- {
- _cond.timed_wait(l, boost::posix_time::microseconds(long(timeout*1e6)));
- }
- if (_enqueued.empty()) return buff;
- front = _enqueued.front();
+ _cond.timed_wait(lock, boost::posix_time::microseconds(long(timeout*1e6)));
}
+ if (_enqueued.empty()) return buff;
+ front = _enqueued.front();
+ lock.unlock();
buff = front->get_new<buffer_type>(timeout);
+ lock.lock();
- boost::mutex::scoped_lock l(_mutex);
if (buff) _enqueued.pop_front();
this->submit_what_we_can();
return buff;
diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp
index 688228e49..5080182d6 100644
--- a/host/lib/transport/super_recv_packet_handler.hpp
+++ b/host/lib/transport/super_recv_packet_handler.hpp
@@ -246,7 +246,8 @@ private:
struct xport_chan_props_type{
xport_chan_props_type(void):
packet_count(0),
- handle_overflow(&handle_overflow_nop)
+ handle_overflow(&handle_overflow_nop),
+ fc_update_window(0)
{}
get_buff_type get_buff;
issue_stream_cmd_type issue_stream_cmd;
diff --git a/host/lib/transport/super_send_packet_handler.hpp b/host/lib/transport/super_send_packet_handler.hpp
index 41f030ea6..ae483d1f3 100644
--- a/host/lib/transport/super_send_packet_handler.hpp
+++ b/host/lib/transport/super_send_packet_handler.hpp
@@ -239,7 +239,7 @@ private:
size_t _header_offset_words32;
double _tick_rate, _samp_rate;
struct xport_chan_props_type{
- xport_chan_props_type(void):has_sid(false){}
+ xport_chan_props_type(void):has_sid(false),sid(0){}
get_buff_type get_buff;
bool has_sid;
boost::uint32_t sid;
diff --git a/host/lib/transport/udp_zero_copy.cpp b/host/lib/transport/udp_zero_copy.cpp
index 166177177..7b6a476f5 100644
--- a/host/lib/transport/udp_zero_copy.cpp
+++ b/host/lib/transport/udp_zero_copy.cpp
@@ -68,7 +68,7 @@ static void check_registry_for_fast_send_threshold(const size_t mtu){
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):
- _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size) { /*NOP*/ }
+ _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size), _len(0) { /*NOP*/ }
void release(void){
_claimer.release();
@@ -87,6 +87,7 @@ public:
if (wait_for_recv_ready(_sock_fd, timeout)){
_len = ::recv(_sock_fd, (char *)_mem, _frame_size, 0);
+ UHD_ASSERT_THROW(_len > 0); // TODO: Handle case of recv error
index++; //advances the caller's buffer
return make(this, _mem, size_t(_len));
}
diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt
index 2ca0faef7..b69c8e487 100644
--- a/host/lib/types/CMakeLists.txt
+++ b/host/lib/types/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2011 Ettus Research LLC
+# Copyright 2011-2013 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
@@ -88,4 +88,5 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/time_spec.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tune.cpp
${CMAKE_CURRENT_SOURCE_DIR}/types.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/wb_iface.cpp
)
diff --git a/host/lib/types/tune.cpp b/host/lib/types/tune.cpp
index 154f0990f..7697bd966 100644
--- a/host/lib/types/tune.cpp
+++ b/host/lib/types/tune.cpp
@@ -24,7 +24,9 @@ using namespace uhd;
tune_request_t::tune_request_t(double target_freq):
target_freq(target_freq),
rf_freq_policy(POLICY_AUTO),
- dsp_freq_policy(POLICY_AUTO)
+ rf_freq(0.0),
+ dsp_freq_policy(POLICY_AUTO),
+ dsp_freq(0.0)
{
/* NOP */
}
@@ -33,7 +35,8 @@ tune_request_t::tune_request_t(double target_freq, double lo_off):
target_freq(target_freq),
rf_freq_policy(POLICY_MANUAL),
rf_freq(target_freq + lo_off),
- dsp_freq_policy(POLICY_AUTO)
+ dsp_freq_policy(POLICY_AUTO),
+ dsp_freq(0.0)
{
/* NOP */
}
diff --git a/host/lib/usrp/cores/wb_iface.cpp b/host/lib/types/wb_iface.cpp
index 9aa6d18d4..6edfdfe2f 100644
--- a/host/lib/usrp/cores/wb_iface.cpp
+++ b/host/lib/types/wb_iface.cpp
@@ -15,11 +15,16 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <uhd/exception.hpp>
using namespace uhd;
+wb_iface::~wb_iface(void)
+{
+ //NOP
+}
+
void wb_iface::poke64(const wb_iface::wb_addr_type, const boost::uint64_t)
{
throw uhd::not_implemented_error("poke64 not implemented");
diff --git a/host/lib/usrp/README b/host/lib/usrp/README
deleted file mode 100644
index 344209179..000000000
--- a/host/lib/usrp/README
+++ /dev/null
@@ -1,15 +0,0 @@
-########################################################################
-# lib USRP directories:
-########################################################################
-
-dboard:
- Daughterboard implementation code for all USRP daughterboards
-
-usrp1:
- Implementation code for the USB-based USRP Classic motherboard.
-
-usrp2:
- Implementation code for USRP2, USRP-N200, and USRP-N210.
-
-usrp_e100:
- Implementation code for USRP-E100.
diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp
index 19df3d6af..305ba42a7 100644
--- a/host/lib/usrp/b100/b100_impl.cpp
+++ b/host/lib/usrp/b100/b100_impl.cpp
@@ -310,12 +310,14 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
_tree->create<std::string>(rx_codec_path / "name").set("ad9522");
_tree->create<meta_range_t>(rx_codec_path / "gains/pga/range").set(b100_codec_ctrl::rx_pga_gain_range);
_tree->create<double>(rx_codec_path / "gains/pga/value")
- .coerce(boost::bind(&b100_impl::update_rx_codec_gain, this, _1));
+ .coerce(boost::bind(&b100_impl::update_rx_codec_gain, this, _1))
+ .set(0.0);
_tree->create<std::string>(tx_codec_path / "name").set("ad9522");
_tree->create<meta_range_t>(tx_codec_path / "gains/pga/range").set(b100_codec_ctrl::tx_pga_gain_range);
_tree->create<double>(tx_codec_path / "gains/pga/value")
.subscribe(boost::bind(&b100_codec_ctrl::set_tx_pga_gain, _codec_ctrl, _1))
- .publish(boost::bind(&b100_codec_ctrl::get_tx_pga_gain, _codec_ctrl));
+ .publish(boost::bind(&b100_codec_ctrl::get_tx_pga_gain, _codec_ctrl))
+ .set(0.0);
////////////////////////////////////////////////////////////////////
// and do the misc mboard sensors
diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp
index f81aa3568..ab83c80a3 100644
--- a/host/lib/usrp/b100/b100_impl.hpp
+++ b/host/lib/usrp/b100/b100_impl.hpp
@@ -67,7 +67,7 @@ static const std::string B100_EEPROM_MAP_KEY = "B100";
//! Make a b100 dboard interface
uhd::usrp::dboard_iface::sptr make_b100_dboard_iface(
- wb_iface::sptr wb_iface,
+ uhd::wb_iface::sptr wb_iface,
uhd::i2c_iface::sptr i2c_iface,
uhd::spi_iface::sptr spi_iface,
b100_clock_ctrl::sptr clock,
diff --git a/host/lib/usrp/b100/usb_zero_copy_wrapper.cpp b/host/lib/usrp/b100/usb_zero_copy_wrapper.cpp
index 2096e4ef4..451cdae50 100644
--- a/host/lib/usrp/b100/usb_zero_copy_wrapper.cpp
+++ b/host/lib/usrp/b100/usb_zero_copy_wrapper.cpp
@@ -167,6 +167,7 @@ public:
usb_zero_copy_wrapper(zero_copy_if::sptr usb_zc, const size_t frame_boundary):
_internal_zc(usb_zc),
_frame_boundary(frame_boundary),
+ _last_recv_offset(0),
_next_recv_buff_index(0)
{
for (size_t i = 0; i < this->get_num_recv_frames(); i++){
diff --git a/host/lib/usrp/b200/b200_iface.cpp b/host/lib/usrp/b200/b200_iface.cpp
index 1d05e159c..5d799bf01 100644
--- a/host/lib/usrp/b200/b200_iface.cpp
+++ b/host/lib/usrp/b200/b200_iface.cpp
@@ -17,6 +17,7 @@
#include "b200_iface.hpp"
+#include <uhd/config.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/exception.hpp>
#include <boost/functional/hash.hpp>
@@ -62,6 +63,7 @@ const static boost::uint8_t B200_VREQ_FX3_RESET = 0x99;
const static boost::uint8_t B200_VREQ_EEPROM_WRITE = 0xBA;
const static boost::uint8_t B200_VREQ_EEPROM_READ = 0xBB;
+const static boost::uint8_t FX3_STATE_UNDEFINED = 0x00;
const static boost::uint8_t FX3_STATE_FPGA_READY = 0x01;
const static boost::uint8_t FX3_STATE_CONFIGURING_FPGA = 0x02;
const static boost::uint8_t FX3_STATE_BUSY = 0x03;
@@ -69,6 +71,11 @@ const static boost::uint8_t FX3_STATE_RUNNING = 0x04;
const static boost::uint8_t FX3_STATE_UNCONFIGURED = 0x05;
const static boost::uint8_t FX3_STATE_ERROR = 0x06;
+const static int VREQ_MAX_SIZE_USB2 = 64;
+const static int VREQ_MAX_SIZE_USB3 = 512;
+const static int VREQ_DEFAULT_SIZE = VREQ_MAX_SIZE_USB2;
+const static int VREQ_MAX_SIZE = VREQ_MAX_SIZE_USB3;
+
typedef boost::uint32_t hash_type;
@@ -83,6 +90,9 @@ typedef boost::uint32_t hash_type;
*/
static hash_type generate_hash(const char *filename)
{
+ if (filename == NULL)
+ return hash_type(0);
+
std::ifstream file(filename);
if (not file){
throw uhd::io_error(std::string("cannot open input file ") + filename);
@@ -115,15 +125,15 @@ static hash_type generate_hash(const char *filename)
* \param record a line from an Intel HEX file
* \return true if record is valid, false otherwise
*/
-bool checksum(std::string *record) {
+bool checksum(const std::string& record) {
- size_t len = record->length();
+ size_t len = record.length();
unsigned int i;
unsigned char sum = 0;
unsigned int val;
for (i = 1; i < len; i += 2) {
- std::istringstream(record->substr(i, 2)) >> std::hex >> val;
+ std::istringstream(record.substr(i, 2)) >> std::hex >> val;
sum += val;
}
@@ -144,22 +154,25 @@ bool checksum(std::string *record) {
* \param data output data
* \return true if record is sucessfully read, false on error
*/
-bool parse_record(std::string *record, boost::uint16_t &len, \
+bool parse_record(const std::string& record, boost::uint16_t &len, \
boost::uint16_t &addr, boost::uint16_t &type, unsigned char* data) {
unsigned int i;
std::string _data;
unsigned int val;
- if (record->substr(0, 1) != ":")
+ if (record.substr(0, 1) != ":")
return false;
- std::istringstream(record->substr(1, 2)) >> std::hex >> len;
- std::istringstream(record->substr(3, 4)) >> std::hex >> addr;
- std::istringstream(record->substr(7, 2)) >> std::hex >> type;
+ std::istringstream(record.substr(1, 2)) >> std::hex >> len;
+ std::istringstream(record.substr(3, 4)) >> std::hex >> addr;
+ std::istringstream(record.substr(7, 2)) >> std::hex >> type;
+
+ if (len > (2 * (record.length() - 9))) // sanity check to prevent buffer overrun
+ return false;
for (i = 0; i < len; i++) {
- std::istringstream(record->substr(9 + 2 * i, 2)) >> std::hex >> val;
+ std::istringstream(record.substr(9 + 2 * i, 2)) >> std::hex >> val;
data[i] = (unsigned char) val;
}
@@ -174,19 +187,16 @@ class b200_iface_impl : public b200_iface{
public:
b200_iface_impl(usb_control::sptr usb_ctrl):
- _usb_ctrl(usb_ctrl)
- {
+ _usb_ctrl(usb_ctrl) {
//NOP
}
-
int fx3_control_write(boost::uint8_t request,
boost::uint16_t value,
boost::uint16_t index,
unsigned char *buff,
boost::uint16_t length,
- boost::int32_t timeout = 0)
- {
+ boost::int32_t timeout = 0) {
return _usb_ctrl->submit(VRT_VENDOR_OUT, // bmReqeustType
request, // bRequest
value, // wValue
@@ -196,14 +206,12 @@ public:
timeout); // timeout
}
-
int fx3_control_read(boost::uint8_t request,
boost::uint16_t value,
boost::uint16_t index,
unsigned char *buff,
boost::uint16_t length,
- boost::int32_t timeout = 0)
- {
+ boost::int32_t timeout = 0) {
return _usb_ctrl->submit(VRT_VENDOR_IN, // bmReqeustType
request, // bRequest
value, // wValue
@@ -213,37 +221,45 @@ public:
timeout); // timeout
}
-
- void write_i2c(boost::uint16_t addr, const byte_vector_t &bytes)
+ void write_i2c(UHD_UNUSED(boost::uint16_t addr), UHD_UNUSED(const byte_vector_t &bytes))
{
throw uhd::not_implemented_error("b200 write i2c");
}
- byte_vector_t read_i2c(boost::uint16_t addr, size_t num_bytes)
+ byte_vector_t read_i2c(UHD_UNUSED(boost::uint16_t addr), UHD_UNUSED(size_t num_bytes))
{
throw uhd::not_implemented_error("b200 read i2c");
}
void write_eeprom(boost::uint16_t addr, boost::uint16_t offset,
- const byte_vector_t &bytes)
- {
- fx3_control_write(B200_VREQ_EEPROM_WRITE,
+ const byte_vector_t &bytes) {
+ int ret = fx3_control_write(B200_VREQ_EEPROM_WRITE,
0, offset | (boost::uint16_t(addr) << 8),
(unsigned char *) &bytes[0],
bytes.size());
+
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to write EEPROM (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if ((size_t)ret != bytes.size())
+ throw uhd::io_error((boost::format("Short write on write EEPROM (expecting: %d, returned: %d)") % bytes.size() % ret).str());
}
byte_vector_t read_eeprom(
boost::uint16_t addr,
boost::uint16_t offset,
- size_t num_bytes
- ){
+ size_t num_bytes) {
byte_vector_t recv_bytes(num_bytes);
- fx3_control_read(B200_VREQ_EEPROM_READ,
+ int bytes_read = fx3_control_read(B200_VREQ_EEPROM_READ,
0, offset | (boost::uint16_t(addr) << 8),
(unsigned char*) &recv_bytes[0],
num_bytes);
+
+ if (bytes_read < 0)
+ throw uhd::io_error((boost::format("Failed to read EEPROM (%d: %s)") % bytes_read % libusb_error_name(bytes_read)).str());
+ else if ((size_t)bytes_read != num_bytes)
+ throw uhd::io_error((boost::format("Short read on read EEPROM (expecting: %d, returned: %d)") % num_bytes % bytes_read).str());
+
return recv_bytes;
}
@@ -251,8 +267,7 @@ public:
unsigned char *tx_data,
size_t num_tx_bits,
unsigned char *rx_data,
- size_t num_rx_bits
- ){
+ size_t num_rx_bits) {
int ret = 0;
boost::uint16_t tx_length = num_tx_bits / 8;
@@ -264,9 +279,10 @@ public:
0x00, tx_data, tx_length);
}
- if(ret < 0) {
- throw uhd::io_error("transact_spi: fx3_control_write failed!");
- }
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to write SPI (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != tx_length)
+ throw uhd::io_error((boost::format("Short write on write SPI (expecting: %d, returned: %d)") % tx_length % ret).str());
if(num_rx_bits) {
@@ -275,25 +291,38 @@ public:
ret = fx3_control_read(B200_VREQ_LOOP, 0x00, \
0x00, rx_data, total_length);
- if(ret < 0) {
- throw uhd::io_error("transact_spi: readback failed!");
- }
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to readback (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != total_length)
+ throw uhd::io_error((boost::format("Short read on readback (expecting: %d, returned: %d)") % total_length % ret).str());
}
}
void ad9361_transact(const unsigned char in_buff[64], unsigned char out_buff[64]) {
- fx3_control_write(B200_VREQ_AD9361_CTRL_WRITE, 0x00, 0x00, (unsigned char *)in_buff, 64);
- int ret = 0;
- for (size_t i = 0; i < 30; i++)
+ const int bytes_to_write = 64;
+ const int bytes_to_read = 64;
+ const size_t read_retries = 30;
+
+ int ret = fx3_control_write(B200_VREQ_AD9361_CTRL_WRITE, 0x00, 0x00, (unsigned char *)in_buff, bytes_to_write);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to write AD9361 (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_write)
+ throw uhd::io_error((boost::format("Short write on write AD9361 (expecting: %d, returned: %d)") % bytes_to_write % ret).str());
+
+ for (size_t i = 0; i < read_retries; i++)
{
- ret = fx3_control_read(B200_VREQ_AD9361_CTRL_READ, 0x00, 0x00, out_buff, 64, 1000);
- if (ret == 64) return;
+ ret = fx3_control_read(B200_VREQ_AD9361_CTRL_READ, 0x00, 0x00, out_buff, bytes_to_read, 1000);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to read AD9361 (%d: %s)") % ret % libusb_error_name(ret)).str());
+
+ if (ret == bytes_to_read)
+ return;
}
- throw uhd::io_error(str(boost::format("ad9361_transact failed with usb error: %d") % ret));
- }
+ throw uhd::io_error(str(boost::format("Failed to read complete AD9361 (expecting: %d, last read: %d)") % bytes_to_read % ret));
+ }
- void load_firmware(const std::string filestring, bool force = false)
+ void load_firmware(const std::string filestring, UHD_UNUSED(bool force) = false)
{
const char *filename = filestring.c_str();
@@ -323,8 +352,11 @@ public:
std::string record;
file >> record;
+ if (!(record.length() > 0))
+ continue;
+
/* Check for valid Intel HEX record. */
- if (!checksum(&record) || !parse_record(&record, len, \
+ if (!checksum(record) || !parse_record(record, len, \
lower_address_bits, type, data)) {
throw uhd::io_error("fx3_load_firmware: bad intel hex record checksum");
}
@@ -397,46 +429,75 @@ public:
throw uhd::io_error("fx3_load_firmware: No EOF record found.");
}
-
void reset_fx3(void) {
unsigned char data[4];
memset(data, 0x00, sizeof(data));
+ const int bytes_to_send = sizeof(data);
- fx3_control_write(B200_VREQ_FX3_RESET, 0x00, 0x00, data, 4);
+ int ret = fx3_control_write(B200_VREQ_FX3_RESET, 0x00, 0x00, data, bytes_to_send);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to reset FX3 (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_send)
+ throw uhd::io_error((boost::format("Short write on reset FX3 (expecting: %d, returned: %d)") % bytes_to_send % ret).str());
}
void reset_gpif(void) {
unsigned char data[4];
memset(data, 0x00, sizeof(data));
+ const int bytes_to_send = sizeof(data);
- fx3_control_write(B200_VREQ_GPIF_RESET, 0x00, 0x00, data, 4);
+ int ret = fx3_control_write(B200_VREQ_GPIF_RESET, 0x00, 0x00, data, bytes_to_send);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to reset GPIF (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_send)
+ throw uhd::io_error((boost::format("Short write on reset GPIF (expecting: %d, returned: %d)") % bytes_to_send % ret).str());
}
- void set_fpga_reset_pin(const bool reset)
- {
+ void set_fpga_reset_pin(const bool reset) {
unsigned char data[4];
memset(data, (reset)? 0xFF : 0x00, sizeof(data));
UHD_THROW_INVALID_CODE_PATH();
- fx3_control_write(B200_VREQ_FPGA_RESET, 0x00, 0x00, data, 4);
+ // Below is dead code as long as UHD_THROW_INVALID_CODE_PATH(); is declared above.
+ // It is preserved here in a comment in case it is needed later:
+ /*
+ const int bytes_to_send = sizeof(data);
+
+ int ret = fx3_control_write(B200_VREQ_FPGA_RESET, 0x00, 0x00, data, bytes_to_send);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to reset FPGA (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_send)
+ throw uhd::io_error((boost::format("Short write on reset FPGA (expecting: %d, returned: %d)") % bytes_to_send % ret).str());
+ */
}
boost::uint8_t get_usb_speed(void) {
unsigned char rx_data[1];
+ memset(rx_data, 0x00, sizeof(rx_data));
+ const int bytes_to_recv = sizeof(rx_data);
- fx3_control_read(B200_VREQ_GET_USB, 0x00, 0x00, rx_data, 1);
+ int ret = fx3_control_read(B200_VREQ_GET_USB, 0x00, 0x00, rx_data, bytes_to_recv);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to get USB speed (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_recv)
+ throw uhd::io_error((boost::format("Short read on get USB speed (expecting: %d, returned: %d)") % bytes_to_recv % ret).str());
return boost::lexical_cast<boost::uint8_t>(rx_data[0]);
}
-
boost::uint8_t get_fx3_status(void) {
unsigned char rx_data[1];
+ memset(rx_data, 0x00, sizeof(rx_data));
+ const int bytes_to_recv = sizeof(rx_data);
- fx3_control_read(B200_VREQ_GET_STATUS, 0x00, 0x00, &rx_data[0], 1);
+ int ret = fx3_control_read(B200_VREQ_GET_STATUS, 0x00, 0x00, rx_data, bytes_to_recv);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to get FX3 status (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_recv)
+ throw uhd::io_error((boost::format("Short read on get FX3 status (expecting: %d, returned: %d)") % bytes_to_recv % ret).str());
return boost::lexical_cast<boost::uint8_t>(rx_data[0]);
}
@@ -444,40 +505,72 @@ public:
boost::uint16_t get_compat_num(void) {
unsigned char rx_data[2];
+ memset(rx_data, 0x00, sizeof(rx_data));
+ const int bytes_to_recv = sizeof(rx_data);
- fx3_control_read(B200_VREQ_GET_COMPAT , 0x00, 0x00, rx_data, 2);
-
- boost::uint16_t compat = 0x0000;
- compat |= (((uint16_t) rx_data[0]) << 8);
- compat |= (rx_data[1] & 0x00FF);
+ int ret = fx3_control_read(B200_VREQ_GET_COMPAT , 0x00, 0x00, rx_data, bytes_to_recv);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to get compat num (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_recv)
+ throw uhd::io_error((boost::format("Short read on get compat num (expecting: %d, returned: %d)") % bytes_to_recv % ret).str());
- return compat;
+ return (((uint16_t)rx_data[0]) << 8) | rx_data[1];
}
void usrp_get_firmware_hash(hash_type &hash) {
- fx3_control_read(B200_VREQ_GET_FW_HASH, 0x00, 0x00,
- (unsigned char*) &hash, 4, 500);
+ const int bytes_to_recv = 4;
+ if (sizeof(hash_type) != bytes_to_recv)
+ throw uhd::type_error((boost::format("hash_type is %d bytes but transfer length is %d bytes") % sizeof(hash_type) % bytes_to_recv).str());
+
+ int ret = fx3_control_read(B200_VREQ_GET_FW_HASH, 0x00, 0x00, (unsigned char*) &hash, bytes_to_recv, 500);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to get firmware hash (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_recv)
+ throw uhd::io_error((boost::format("Short read on get firmware hash (expecting: %d, returned: %d)") % bytes_to_recv % ret).str());
}
void usrp_set_firmware_hash(hash_type hash) {
- fx3_control_write(B200_VREQ_SET_FW_HASH, 0x00, 0x00,
- (unsigned char*) &hash, 4);
+ const int bytes_to_send = 4;
+ if (sizeof(hash_type) != bytes_to_send)
+ throw uhd::type_error((boost::format("hash_type is %d bytes but transfer length is %d bytes") % sizeof(hash_type) % bytes_to_send).str());
+
+ int ret = fx3_control_write(B200_VREQ_SET_FW_HASH, 0x00, 0x00, (unsigned char*) &hash, bytes_to_send);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to set firmware hash (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_send)
+ throw uhd::io_error((boost::format("Short write on set firmware hash (expecting: %d, returned: %d)") % bytes_to_send % ret).str());
}
void usrp_get_fpga_hash(hash_type &hash) {
- fx3_control_read(B200_VREQ_GET_FPGA_HASH, 0x00, 0x00,
- (unsigned char*) &hash, 4, 500);
+ const int bytes_to_recv = 4;
+ if (sizeof(hash_type) != bytes_to_recv)
+ throw uhd::type_error((boost::format("hash_type is %d bytes but transfer length is %d bytes") % sizeof(hash_type) % bytes_to_recv).str());
+
+ int ret = fx3_control_read(B200_VREQ_GET_FPGA_HASH, 0x00, 0x00, (unsigned char*) &hash, bytes_to_recv, 500);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to get FPGA hash (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_recv)
+ throw uhd::io_error((boost::format("Short read on get FPGA hash (expecting: %d, returned: %d)") % bytes_to_recv % ret).str());
}
void usrp_set_fpga_hash(hash_type hash) {
- fx3_control_write(B200_VREQ_SET_FPGA_HASH, 0x00, 0x00,
- (unsigned char*) &hash, 4);
+ const int bytes_to_send = 4;
+ if (sizeof(hash_type) != bytes_to_send)
+ throw uhd::type_error((boost::format("hash_type is %d bytes but transfer length is %d bytes") % sizeof(hash_type) % bytes_to_send).str());
+
+ int ret = fx3_control_write(B200_VREQ_SET_FPGA_HASH, 0x00, 0x00, (unsigned char*) &hash, bytes_to_send);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to set FPGA hash (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_send)
+ throw uhd::io_error((boost::format("Short write on set FPGA hash (expecting: %d, returned: %d)") % bytes_to_send % ret).str());
}
boost::uint32_t load_fpga(const std::string filestring) {
boost::uint8_t fx3_state = 0;
boost::uint32_t wait_count;
+ int ret = 0;
+ int bytes_to_xfer = 0;
const char *filename = filestring.c_str();
@@ -485,9 +578,27 @@ public:
hash_type loaded_hash; usrp_get_fpga_hash(loaded_hash);
if (hash == loaded_hash) return 0;
- unsigned char out_buff[64];
- memset(out_buff, 0x00, sizeof(out_buff));
- fx3_control_write(B200_VREQ_FPGA_CONFIG, 0, 0, out_buff, 1, 1000);
+ // Establish default largest possible control request transfer size based on operating USB speed
+ int transfer_size = VREQ_DEFAULT_SIZE;
+ int current_usb_speed = get_usb_speed();
+ if (current_usb_speed == 3)
+ transfer_size = VREQ_MAX_SIZE_USB3;
+ else if (current_usb_speed != 2)
+ throw uhd::io_error("load_fpga: get_usb_speed returned invalid USB speed (not 2 or 3).");
+
+ UHD_ASSERT_THROW(transfer_size <= VREQ_MAX_SIZE);
+
+ unsigned char out_buff[VREQ_MAX_SIZE];
+
+ // Request loopback read, which will indicate the firmware's current control request buffer size
+ // Make sure that if operating as USB2, requested length is within spec
+ int ntoread = std::min(transfer_size, (int)sizeof(out_buff));
+ int nread = fx3_control_read(B200_VREQ_LOOP, 0, 0, out_buff, ntoread, 1000);
+ if (nread < 0)
+ throw uhd::io_error((boost::format("load_fpga: unable to complete firmware loopback request (%d: %s)") % nread % libusb_error_name(nread)).str());
+ else if (nread != ntoread)
+ throw uhd::io_error((boost::format("load_fpga: short read on firmware loopback request (expecting: %d, returned: %d)") % ntoread % nread).str());
+ transfer_size = std::min(transfer_size, nread); // Select the smaller value
size_t file_size = 0;
{
@@ -498,15 +609,26 @@ public:
std::ifstream file;
file.open(filename, std::ios::in | std::ios::binary);
- if(!file.good()) {
+ if (!file.good()) {
throw uhd::io_error("load_fpga: cannot open FPGA input file.");
}
+ // Zero the hash, in case we abort programming another image and revert to the previously programmed image
+ usrp_set_fpga_hash(0);
+
+ memset(out_buff, 0x00, sizeof(out_buff));
+ bytes_to_xfer = 1;
+ ret = fx3_control_write(B200_VREQ_FPGA_CONFIG, 0, 0, out_buff, bytes_to_xfer, 1000);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to start FPGA config (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_xfer)
+ throw uhd::io_error((boost::format("Short write on start FPGA config (expecting: %d, returned: %d)") % bytes_to_xfer % ret).str());
+
wait_count = 0;
do {
fx3_state = get_fx3_status();
- if((wait_count >= 500) || (fx3_state == FX3_STATE_ERROR)) {
+ if((wait_count >= 500) || (fx3_state == FX3_STATE_ERROR) || (fx3_state == FX3_STATE_UNDEFINED)) {
return fx3_state;
}
@@ -518,13 +640,18 @@ public:
if (load_img_msg) UHD_MSG(status) << "Loading FPGA image: " \
<< filestring << "..." << std::flush;
- fx3_control_write(B200_VREQ_FPGA_START, 0, 0, out_buff, 1, 1000);
+ bytes_to_xfer = 1;
+ ret = fx3_control_write(B200_VREQ_FPGA_START, 0, 0, out_buff, bytes_to_xfer, 1000);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to start FPGA bitstream (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_xfer)
+ throw uhd::io_error((boost::format("Short write on start FPGA bitstream (expecting: %d, returned: %d)") % bytes_to_xfer % ret).str());
wait_count = 0;
do {
fx3_state = get_fx3_status();
- if((wait_count >= 1000) || (fx3_state == FX3_STATE_ERROR)) {
+ if((wait_count >= 1000) || (fx3_state == FX3_STATE_ERROR) || (fx3_state == FX3_STATE_UNDEFINED)) {
return fx3_state;
}
@@ -534,15 +661,20 @@ public:
} while(fx3_state != FX3_STATE_CONFIGURING_FPGA);
size_t bytes_sent = 0;
- while(!file.eof()) {
- file.read((char *) out_buff, sizeof(out_buff));
+ while (!file.eof()) {
+ file.read((char *) out_buff, transfer_size);
const std::streamsize n = file.gcount();
- if(n == 0) continue;
+ if(n == 0)
+ continue;
boost::uint16_t transfer_count = boost::uint16_t(n);
/* Send the data to the device. */
- fx3_control_write(B200_VREQ_FPGA_DATA, 0, 0, out_buff, transfer_count, 5000);
+ int nwritten = fx3_control_write(B200_VREQ_FPGA_DATA, 0, 0, out_buff, transfer_count, 5000);
+ if (nwritten < 0)
+ throw uhd::io_error((boost::format("load_fpga: cannot write bitstream to FX3 (%d: %s)") % nwritten % libusb_error_name(nwritten)).str());
+ else if (nwritten != transfer_count)
+ throw uhd::io_error((boost::format("load_fpga: short write while transferring bitstream to FX3 (expecting: %d, returned: %d)") % transfer_count % nwritten).str());
if (load_img_msg)
{
@@ -563,7 +695,7 @@ public:
do {
fx3_state = get_fx3_status();
- if((wait_count >= 500) || (fx3_state == FX3_STATE_ERROR)) {
+ if((wait_count >= 500) || (fx3_state == FX3_STATE_ERROR) || (fx3_state == FX3_STATE_UNDEFINED)) {
return fx3_state;
}
@@ -574,7 +706,8 @@ public:
usrp_set_fpga_hash(hash);
- if (load_img_msg) UHD_MSG(status) << "\b\b\b\b done" << std::endl;
+ if (load_img_msg)
+ UHD_MSG(status) << "\b\b\b\b done" << std::endl;
return 0;
}
@@ -583,6 +716,29 @@ private:
usb_control::sptr _usb_ctrl;
};
+
+std::string b200_iface::fx3_state_string(boost::uint8_t state)
+{
+ switch (state)
+ {
+ case FX3_STATE_FPGA_READY:
+ return std::string("Ready");
+ case FX3_STATE_CONFIGURING_FPGA:
+ return std::string("Configuring FPGA");
+ case FX3_STATE_BUSY:
+ return std::string("Busy");
+ case FX3_STATE_RUNNING:
+ return std::string("Running");
+ case FX3_STATE_UNCONFIGURED:
+ return std::string("Unconfigured");
+ case FX3_STATE_ERROR:
+ return std::string("Error");
+ default:
+ break;
+ }
+ return std::string("Unknown");
+}
+
/***********************************************************************
* Make an instance of the implementation
**********************************************************************/
diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp
index 1247d1f86..20b4a7a89 100644
--- a/host/lib/usrp/b200/b200_iface.hpp
+++ b/host/lib/usrp/b200/b200_iface.hpp
@@ -25,7 +25,17 @@
#include <boost/utility.hpp>
#include "ad9361_ctrl.hpp"
-class b200_iface: boost::noncopyable, public virtual uhd::i2c_iface,
+const static boost::uint16_t B200_VENDOR_ID = 0x2500;
+const static boost::uint16_t B200_PRODUCT_ID = 0x0020;
+const static boost::uint16_t FX3_VID = 0x04b4;
+const static boost::uint16_t FX3_DEFAULT_PID = 0x00f3;
+const static boost::uint16_t FX3_REENUM_PID = 0x00f0;
+
+static const std::string B200_FW_FILE_NAME = "usrp_b200_fw.hex";
+static const std::string B200_FPGA_FILE_NAME = "usrp_b200_fpga.bin";
+static const std::string B210_FPGA_FILE_NAME = "usrp_b210_fpga.bin";
+
+class UHD_API b200_iface: boost::noncopyable, public virtual uhd::i2c_iface,
public ad9361_ctrl_iface_type {
public:
typedef boost::shared_ptr<b200_iface> sptr;
@@ -64,6 +74,12 @@ public:
//! send SPI through the FX3
virtual void transact_spi( unsigned char *tx_data, size_t num_tx_bits, \
unsigned char *rx_data, size_t num_rx_bits) = 0;
+
+ virtual void write_eeprom(boost::uint16_t addr, boost::uint16_t offset, const uhd::byte_vector_t &bytes) = 0;
+
+ virtual uhd::byte_vector_t read_eeprom(boost::uint16_t addr, boost::uint16_t offset, size_t num_bytes) = 0;
+
+ static std::string fx3_state_string(boost::uint8_t state);
};
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp
index 0da388b93..132b1198d 100644
--- a/host/lib/usrp/b200/b200_impl.cpp
+++ b/host/lib/usrp/b200/b200_impl.cpp
@@ -37,10 +37,6 @@ using namespace uhd;
using namespace uhd::usrp;
using namespace uhd::transport;
-const boost::uint16_t B200_VENDOR_ID = 0x2500;
-const boost::uint16_t B200_PRODUCT_ID = 0x0020;
-const boost::uint16_t INIT_PRODUCT_ID = 0x00f0;
-
static const boost::posix_time::milliseconds REENUMERATION_TIMEOUT_MS(3000);
//! mapping of frontend to radio perif index
@@ -99,7 +95,7 @@ static device_addrs_t b200_find(const device_addr_t &hint)
catch(const uhd::exception &){continue;} //ignore claimed
//check if fw was already loaded
- if (handle->get_manufacturer() != "Ettus Research LLC")
+ if (!(handle->firmware_loaded()))
{
b200_iface::make(control)->load_firmware(b200_fw_image);
}
@@ -160,8 +156,15 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
const fs_path mb_path = "/mboards/0";
//try to match the given device address with something on the USB bus
+ uint16_t vid = B200_VENDOR_ID;
+ uint16_t pid = B200_PRODUCT_ID;
+ if (device_addr.has_key("vid"))
+ sscanf(device_addr.get("vid").c_str(), "%x", &vid);
+ if (device_addr.has_key("pid"))
+ sscanf(device_addr.get("pid").c_str(), "%x", &pid);
+
std::vector<usb_device_handle::sptr> device_list =
- usb_device_handle::get_device_list(B200_VENDOR_ID, B200_PRODUCT_ID);
+ usb_device_handle::get_device_list(vid, pid);
//locate the matching handle in the device list
usb_device_handle::sptr handle;
@@ -252,7 +255,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
////////////////////////////////////////////////////////////////////
_async_task_data.reset(new AsyncTaskData());
_async_task_data->async_md.reset(new async_md_type(1000/*messages deep*/));
- _async_task = uhd::task::make(boost::bind(&b200_impl::handle_async_task, this, _ctrl_transport, _async_task_data));
+ _async_task = uhd::msg_task::make(boost::bind(&b200_impl::handle_async_task, this, _ctrl_transport, _async_task_data));
////////////////////////////////////////////////////////////////////
// Local control endpoint
@@ -474,7 +477,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
b200_impl::~b200_impl(void)
{
- UHD_SAFE_CALL
+ UHD_SAFE_CALL
(
_async_task.reset();
)
@@ -612,7 +615,7 @@ void b200_impl::setup_radio(const size_t dspno)
/***********************************************************************
* loopback tests
**********************************************************************/
-
+
void b200_impl::register_loopback_self_test(wb_iface::sptr iface)
{
bool test_fail = false;
diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp
index 818906e60..bee42679b 100644
--- a/host/lib/usrp/b200/b200_impl.hpp
+++ b/host/lib/usrp/b200/b200_impl.hpp
@@ -44,13 +44,9 @@
#include <uhd/transport/bounded_buffer.hpp>
#include <boost/weak_ptr.hpp>
#include "recv_packet_demuxer_3000.hpp"
-
-static const std::string B200_FW_FILE_NAME = "usrp_b200_fw.hex";
-static const std::string B200_FPGA_FILE_NAME = "usrp_b200_fpga.bin";
-static const std::string B210_FPGA_FILE_NAME = "usrp_b210_fpga.bin";
-static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 0x03;
+static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 0x04;
static const boost::uint8_t B200_FW_COMPAT_NUM_MINOR = 0x00;
-static const boost::uint16_t B200_FPGA_COMPAT_NUM = 0x02;
+static const boost::uint16_t B200_FPGA_COMPAT_NUM = 0x03;
static const double B200_LINK_RATE_BPS = (5e9)/8; //practical link rate (5 Gbps)
static const double B200_BUS_CLOCK_RATE = 100e6;
static const double B200_DEFAULT_TICK_RATE = 32e6;
@@ -120,7 +116,7 @@ struct b200_impl : public uhd::device
boost::weak_ptr<uhd::tx_streamer> _tx_streamer;
//async ctrl + msgs
- uhd::task::sptr _async_task;
+ uhd::msg_task::sptr _async_task;
typedef uhd::transport::bounded_buffer<uhd::async_metadata_t> async_md_type;
struct AsyncTaskData
{
@@ -130,10 +126,10 @@ struct b200_impl : public uhd::device
b200_uart::sptr gpsdo_uart;
};
boost::shared_ptr<AsyncTaskData> _async_task_data;
- void handle_async_task(uhd::transport::zero_copy_if::sptr, boost::shared_ptr<AsyncTaskData>);
+ boost::optional<uhd::msg_task::msg_type_t> handle_async_task(uhd::transport::zero_copy_if::sptr, boost::shared_ptr<AsyncTaskData>);
- void register_loopback_self_test(wb_iface::sptr iface);
- void codec_loopback_self_test(wb_iface::sptr iface);
+ void register_loopback_self_test(uhd::wb_iface::sptr iface);
+ void codec_loopback_self_test(uhd::wb_iface::sptr iface);
void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &);
void check_fw_compat(void);
void check_fpga_compat(void);
diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp
index d643ef855..4768aa37b 100644
--- a/host/lib/usrp/b200/b200_io_impl.cpp
+++ b/host/lib/usrp/b200/b200_io_impl.cpp
@@ -139,27 +139,44 @@ bool b200_impl::recv_async_msg(
return _async_task_data->async_md->pop_with_timed_wait(async_metadata, timeout);
}
-void b200_impl::handle_async_task(
+/*
+ * This method is constantly called in a msg_task loop.
+ * Incoming messages are dispatched in to the hosts radio_ctrl_cores.
+ * The radio_ctrl_core queues are accessed via a weak_ptr to them, stored in AsyncTaskData.
+ * During shutdown the radio_ctrl_core dtor's are called.
+ * An empty peek32(0) is sent out to flush pending async messages.
+ * The response to those messages can't be delivered to the ctrl_core queues anymore
+ * because the shared pointer corresponding to the weak_ptrs is no longer valid.
+ * Those stranded messages are put into a dump_queue implemented in msg_task.
+ * A radio_ctrl_core can search for missing messages there.
+ */
+boost::optional<uhd::msg_task::msg_type_t> b200_impl::handle_async_task(
uhd::transport::zero_copy_if::sptr xport,
boost::shared_ptr<AsyncTaskData> data
)
{
managed_recv_buffer::sptr buff = xport->get_recv_buff();
- if (not buff or buff->size() < 8) return;
+ if (not buff or buff->size() < 8)
+ return NULL;
+
const boost::uint32_t sid = uhd::wtohx(buff->cast<const boost::uint32_t *>()[1]);
- switch (sid)
- {
+ switch (sid) {
//if the packet is a control response
case B200_RESP0_MSG_SID:
case B200_RESP1_MSG_SID:
case B200_LOCAL_RESP_SID:
{
- radio_ctrl_core_3000::sptr ctrl;
+ radio_ctrl_core_3000::sptr ctrl;
if (sid == B200_RESP0_MSG_SID) ctrl = data->radio_ctrl[0].lock();
if (sid == B200_RESP1_MSG_SID) ctrl = data->radio_ctrl[1].lock();
if (sid == B200_LOCAL_RESP_SID) ctrl = data->local_ctrl.lock();
- if (ctrl) ctrl->push_response(buff->cast<const boost::uint32_t *>());
+ if (ctrl){
+ ctrl->push_response(buff->cast<const boost::uint32_t *>());
+ }
+ else{
+ return std::make_pair(sid, uhd::msg_task::buff_to_vector(buff->cast<boost::uint8_t *>(), buff->size() ) );
+ }
break;
}
@@ -204,6 +221,7 @@ void b200_impl::handle_async_task(
default:
UHD_MSG(error) << "Got a ctrl packet with unknown SID " << sid << std::endl;
}
+ return NULL;
}
/***********************************************************************
@@ -231,14 +249,14 @@ rx_streamer::sptr b200_impl::get_rx_stream(const uhd::stream_args_t &args_)
//calculate packet size
static const size_t hdr_size = 0
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
- + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
+ //+ sizeof(vrt::if_packet_info_t().tlr) //no longer using trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
- sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
const size_t bpp = _data_transport->get_recv_frame_size() - hdr_size;
const size_t bpi = convert::get_bytes_per_item(args.otw_format);
size_t spp = unsigned(args.args.cast<double>("spp", bpp/bpi));
- spp = std::min<size_t>(2000, spp); //magic maximum for framing at full rate
+ spp = std::min<size_t>(4092, spp); //FPGA FIFO maximum for framing at full rate
//make the new streamer given the samples per packet
if (not my_streamer) my_streamer = boost::make_shared<sph::recv_packet_streamer>(spp);
diff --git a/host/lib/usrp/common/fifo_ctrl_excelsior.hpp b/host/lib/usrp/common/fifo_ctrl_excelsior.hpp
index c3ef65a2c..bd7777ffa 100644
--- a/host/lib/usrp/common/fifo_ctrl_excelsior.hpp
+++ b/host/lib/usrp/common/fifo_ctrl_excelsior.hpp
@@ -24,7 +24,7 @@
#include <uhd/transport/zero_copy.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
@@ -40,7 +40,8 @@ struct fifo_ctrl_excelsior_config
/*!
* Provide access to peek, poke, spi, and async messages.
*/
-class fifo_ctrl_excelsior : public wb_iface, public uhd::spi_iface{
+class fifo_ctrl_excelsior : public uhd::wb_iface, public uhd::spi_iface
+{
public:
typedef boost::shared_ptr<fifo_ctrl_excelsior> sptr;
diff --git a/host/lib/usrp/common/fx2_ctrl.cpp b/host/lib/usrp/common/fx2_ctrl.cpp
index 6111efea9..6552f1b2d 100644
--- a/host/lib/usrp/common/fx2_ctrl.cpp
+++ b/host/lib/usrp/common/fx2_ctrl.cpp
@@ -119,6 +119,9 @@ bool parse_record(std::string *record, unsigned int &len,
std::istringstream(record->substr(3, 4)) >> std::hex >> addr;
std::istringstream(record->substr(7, 2)) >> std::hex >> type;
+ if (len > (2 * (record->length() - 9))) // sanity check to prevent buffer overrun
+ return false;
+
for (i = 0; i < len; i++) {
std::istringstream(record->substr(9 + 2 * i, 2)) >> std::hex >> val;
data[i] = (unsigned char) val;
@@ -181,6 +184,9 @@ public:
std::string record;
file >> record;
+ if (!(record.length() > 0))
+ continue;
+
//check for valid record
if (not checksum(&record) or not parse_record(&record, len, addr, type, data)) {
throw uhd::io_error("usrp_load_firmware: bad record checksum");
diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt
index f526319bc..f28ae040f 100644
--- a/host/lib/usrp/cores/CMakeLists.txt
+++ b/host/lib/usrp/cores/CMakeLists.txt
@@ -22,7 +22,6 @@
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
LIBUHD_APPEND_SOURCES(
- ${CMAKE_CURRENT_SOURCE_DIR}/wb_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/gpio_core_200.cpp
${CMAKE_CURRENT_SOURCE_DIR}/i2c_core_100.cpp
${CMAKE_CURRENT_SOURCE_DIR}/i2c_core_200.cpp
diff --git a/host/lib/usrp/cores/gpio_core_200.hpp b/host/lib/usrp/cores/gpio_core_200.hpp
index a3edf5454..15fe5f2dd 100644
--- a/host/lib/usrp/cores/gpio_core_200.hpp
+++ b/host/lib/usrp/cores/gpio_core_200.hpp
@@ -23,7 +23,7 @@
#include <boost/cstdint.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class gpio_core_200 : boost::noncopyable{
public:
@@ -33,7 +33,7 @@ public:
typedef uhd::usrp::dboard_iface::atr_reg_t atr_reg_t;
//! makes a new GPIO core from iface and slave base
- static sptr make(wb_iface::sptr iface, const size_t base, const size_t rb_addr);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base, const size_t rb_addr);
//! 1 = ATR
virtual void set_pin_ctrl(const unit_t unit, const boost::uint16_t value) = 0;
@@ -56,7 +56,7 @@ public:
typedef uhd::usrp::dboard_iface::atr_reg_t atr_reg_t;
- static sptr make(wb_iface::sptr iface, const size_t);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t);
virtual void set_atr_reg(const atr_reg_t atr, const boost::uint32_t value) = 0;
diff --git a/host/lib/usrp/cores/i2c_core_100.hpp b/host/lib/usrp/cores/i2c_core_100.hpp
index f7a5ae4f7..4e7a2874b 100644
--- a/host/lib/usrp/cores/i2c_core_100.hpp
+++ b/host/lib/usrp/cores/i2c_core_100.hpp
@@ -22,14 +22,14 @@
#include <uhd/types/serial.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class i2c_core_100 : boost::noncopyable, public uhd::i2c_iface{
public:
typedef boost::shared_ptr<i2c_core_100> sptr;
//! makes a new i2c core from iface and slave base
- static sptr make(wb_iface::sptr iface, const size_t base);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base);
};
#endif /* INCLUDED_LIBUHD_USRP_I2C_CORE_100_HPP */
diff --git a/host/lib/usrp/cores/i2c_core_100_wb32.hpp b/host/lib/usrp/cores/i2c_core_100_wb32.hpp
index f2ac98292..b5912ba9a 100644
--- a/host/lib/usrp/cores/i2c_core_100_wb32.hpp
+++ b/host/lib/usrp/cores/i2c_core_100_wb32.hpp
@@ -22,14 +22,14 @@
#include <uhd/types/serial.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class i2c_core_100_wb32 : boost::noncopyable, public uhd::i2c_iface{
public:
typedef boost::shared_ptr<i2c_core_100_wb32> sptr;
//! makes a new i2c core from iface and slave base
- static sptr make(wb_iface::sptr iface, const size_t base);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base);
virtual void set_clock_rate(const double rate) = 0;
};
diff --git a/host/lib/usrp/cores/i2c_core_200.hpp b/host/lib/usrp/cores/i2c_core_200.hpp
index 508855985..1b20455d3 100644
--- a/host/lib/usrp/cores/i2c_core_200.hpp
+++ b/host/lib/usrp/cores/i2c_core_200.hpp
@@ -22,14 +22,14 @@
#include <uhd/types/serial.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/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);
+ static sptr make(uhd::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/radio_ctrl_core_3000.cpp b/host/lib/usrp/cores/radio_ctrl_core_3000.cpp
index 5298fd213..27fac3471 100644
--- a/host/lib/usrp/cores/radio_ctrl_core_3000.cpp
+++ b/host/lib/usrp/cores/radio_ctrl_core_3000.cpp
@@ -35,35 +35,27 @@ using namespace uhd::transport;
static const double ACK_TIMEOUT = 2.0; //supposed to be worst case practical timeout
static const double MASSIVE_TIMEOUT = 10.0; //for when we wait on a timed command
-static const size_t SR_READBACK = 32;
+static const size_t SR_READBACK = 32;
-class radio_ctrl_core_3000_impl : public radio_ctrl_core_3000
+class radio_ctrl_core_3000_impl: public radio_ctrl_core_3000
{
public:
- radio_ctrl_core_3000_impl(
- const bool big_endian,
- uhd::transport::zero_copy_if::sptr ctrl_xport,
- uhd::transport::zero_copy_if::sptr resp_xport,
- const boost::uint32_t sid,
- const std::string &name
- ):
- _link_type(vrt::if_packet_info_t::LINK_TYPE_CHDR),
- _packet_type(vrt::if_packet_info_t::PACKET_TYPE_CONTEXT),
- _bige(big_endian),
- _ctrl_xport(ctrl_xport),
- _resp_xport(resp_xport),
- _sid(sid),
- _name(name),
- _seq_out(0),
- _timeout(ACK_TIMEOUT),
- _resp_queue(128/*max response msgs*/),
- _resp_queue_size(_resp_xport? _resp_xport->get_num_recv_frames() : 3)
+ radio_ctrl_core_3000_impl(const bool big_endian,
+ uhd::transport::zero_copy_if::sptr ctrl_xport,
+ uhd::transport::zero_copy_if::sptr resp_xport,
+ const boost::uint32_t sid, const std::string &name) :
+ _link_type(vrt::if_packet_info_t::LINK_TYPE_CHDR), _packet_type(
+ vrt::if_packet_info_t::PACKET_TYPE_CONTEXT), _bige(
+ big_endian), _ctrl_xport(ctrl_xport), _resp_xport(
+ resp_xport), _sid(sid), _name(name), _seq_out(0), _timeout(
+ ACK_TIMEOUT), _resp_queue(128/*max response msgs*/), _resp_queue_size(
+ _resp_xport ? _resp_xport->get_num_recv_frames() : 3)
{
- UHD_LOG << "radio_ctrl_core_3000_impl() " << _name << std::endl;
+ UHD_LOG<< "radio_ctrl_core_3000_impl() " << _name << std::endl;
if (resp_xport)
{
- while (resp_xport->get_recv_buff(0.0)){} //flush
+ while (resp_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
@@ -74,8 +66,8 @@ public:
UHD_LOG << "~radio_ctrl_core_3000_impl() " << _name << std::endl;
_timeout = ACK_TIMEOUT; //reset timeout to something small
UHD_SAFE_CALL(
- this->peek32(0); //dummy peek with the purpose of ack'ing all packets
- _async_task.reset(); //now its ok to release the task
+ this->peek32(0);//dummy peek with the purpose of ack'ing all packets
+ _async_task.reset();//now its ok to release the task
)
}
@@ -95,7 +87,6 @@ public:
{
boost::mutex::scoped_lock lock(_mutex);
UHD_LOGV(always) << _name << std::hex << " addr 0x" << addr << std::dec << std::endl;
-
this->send_pkt(SR_READBACK, addr/8);
this->wait_for_ack(false);
@@ -136,6 +127,11 @@ public:
}
private:
+ // This is the buffer type for messages in radio control core.
+ struct resp_buff_type
+ {
+ boost::uint32_t data[8];
+ };
/*******************************************************************
* Primary control and interaction private methods
@@ -143,7 +139,7 @@ private:
UHD_INLINE void send_pkt(const boost::uint32_t addr, const boost::uint32_t data = 0)
{
managed_send_buffer::sptr buff = _ctrl_xport->get_send_buff(0.0);
- if (not buff){
+ if (not buff) {
throw uhd::runtime_error("fifo ctrl timed out getting a send buffer");
}
boost::uint32_t *pkt = buff->cast<boost::uint32_t *>();
@@ -173,12 +169,11 @@ private:
pkt[packet_info.num_header_words32+0] = (_bige)? uhd::htonx(addr) : uhd::htowx(addr);
pkt[packet_info.num_header_words32+1] = (_bige)? uhd::htonx(data) : uhd::htowx(data);
//UHD_MSG(status) << boost::format("0x%08x, 0x%08x\n") % addr % data;
-
//send the buffer over the interface
_outstanding_seqs.push(_seq_out);
buff->commit(sizeof(boost::uint32_t)*(packet_info.num_packet_words32));
- _seq_out++; //inc seq for next call
+ _seq_out++;//inc seq for next call
}
UHD_INLINE boost::uint64_t wait_for_ack(const bool readback)
@@ -186,7 +181,6 @@ private:
while (readback or (_outstanding_seqs.size() >= _resp_queue_size))
{
UHD_LOGV(always) << _name << " wait_for_ack: " << "readback = " << readback << " outstanding_seqs.size() " << _outstanding_seqs.size() << std::endl;
-
//get seq to ack from outstanding packets list
UHD_ASSERT_THROW(not _outstanding_seqs.empty());
const size_t seq_to_ack = _outstanding_seqs.front();
@@ -195,6 +189,7 @@ private:
//parse the packet
vrt::if_packet_info_t packet_info;
resp_buff_type resp_buff;
+ memset(&resp_buff, 0x00, sizeof(resp_buff));
boost::uint32_t const *pkt = NULL;
managed_recv_buffer::sptr buff;
@@ -218,7 +213,27 @@ private:
//get buffer from response endpoint - or die in timeout
else
{
- UHD_ASSERT_THROW(_resp_queue.pop_with_timed_wait(resp_buff, _timeout));
+ /*
+ * Couldn't get message with haste.
+ * Now check both possible queues for messages.
+ * Messages should come in on _resp_queue,
+ * but could end up in dump_queue.
+ * If we don't get a message --> Die in timeout.
+ */
+ double accum_timeout = 0.0;
+ const double short_timeout = 0.005; // == 5ms
+ while(not ((_resp_queue.pop_with_haste(resp_buff))
+ || (check_dump_queue(resp_buff))
+ || (_resp_queue.pop_with_timed_wait(resp_buff, short_timeout))
+ )){
+ /*
+ * If a message couldn't be received within a given timeout
+ * --> throw AssertionError!
+ */
+ accum_timeout += short_timeout;
+ UHD_ASSERT_THROW(accum_timeout < _timeout);
+ }
+
pkt = resp_buff.data;
packet_info.num_packet_words32 = sizeof(resp_buff)/sizeof(boost::uint32_t);
}
@@ -233,7 +248,12 @@ private:
catch(const std::exception &ex)
{
UHD_MSG(error) << "Radio ctrl bad VITA packet: " << ex.what() << std::endl;
- UHD_VAR(buff->size());
+ if (buff){
+ UHD_VAR(buff->size());
+ }
+ else{
+ UHD_MSG(status) << "buff is NULL" << std::endl;
+ }
UHD_MSG(status) << std::hex << pkt[0] << std::dec << std::endl;
UHD_MSG(status) << std::hex << pkt[1] << std::dec << std::endl;
UHD_MSG(status) << std::hex << pkt[2] << std::dec << std::endl;
@@ -262,9 +282,34 @@ private:
return ((hi << 32) | lo);
}
}
+
return 0;
}
+ /*
+ * If ctrl_core waits for a message that didn't arrive it can search for it in the dump queue.
+ * This actually happens during shutdown.
+ * handle_async_task can't access radio_ctrl_cores queue anymore thus it returns the corresponding message.
+ * msg_task class implements a dump_queue to store such messages.
+ * With check_dump_queue we can check if a message we are waiting for got stranded there.
+ * If a message got stuck we get it here and push it onto our own message_queue.
+ */
+ bool check_dump_queue(resp_buff_type& b) {
+ const size_t min_buff_size = 8; // Same value as in b200_io_impl->handle_async_task
+ boost::uint32_t recv_sid = (((_sid)<<16)|((_sid)>>16));
+ uhd::msg_task::msg_payload_t msg;
+ do{
+ msg = _async_task->get_msg_from_dump_queue(recv_sid);
+ }
+ while(msg.size() < min_buff_size && msg.size() != 0);
+
+ if(msg.size() >= min_buff_size) {
+ memcpy(b.data, &msg.front(), std::min(msg.size(), sizeof(b.data)));
+ return true;
+ }
+ return false;
+ }
+
void push_response(const boost::uint32_t *buff)
{
resp_buff_type resp_buff;
@@ -272,7 +317,7 @@ private:
_resp_queue.push_with_haste(resp_buff);
}
- void hold_task(boost::shared_ptr<void> task)
+ void hold_task(uhd::msg_task::sptr task)
{
_async_task = task;
}
@@ -282,7 +327,7 @@ private:
const bool _bige;
const uhd::transport::zero_copy_if::sptr _ctrl_xport;
const uhd::transport::zero_copy_if::sptr _resp_xport;
- boost::shared_ptr<void> _async_task;
+ uhd::msg_task::sptr _async_task;
const boost::uint32_t _sid;
const std::string _name;
boost::mutex _mutex;
@@ -292,22 +337,15 @@ private:
double _tick_rate;
double _timeout;
std::queue<size_t> _outstanding_seqs;
- struct resp_buff_type
- {
- boost::uint32_t data[8];
- };
bounded_buffer<resp_buff_type> _resp_queue;
const size_t _resp_queue_size;
};
-
-radio_ctrl_core_3000::sptr radio_ctrl_core_3000::make(
- const bool big_endian,
- zero_copy_if::sptr ctrl_xport,
- zero_copy_if::sptr resp_xport,
- const boost::uint32_t sid,
- const std::string &name
-)
+radio_ctrl_core_3000::sptr radio_ctrl_core_3000::make(const bool big_endian,
+ zero_copy_if::sptr ctrl_xport, zero_copy_if::sptr resp_xport,
+ const boost::uint32_t sid, const std::string &name)
{
- return sptr(new radio_ctrl_core_3000_impl(big_endian, ctrl_xport, resp_xport, sid, name));
+ return sptr(
+ new radio_ctrl_core_3000_impl(big_endian, ctrl_xport, resp_xport,
+ sid, name));
}
diff --git a/host/lib/usrp/cores/radio_ctrl_core_3000.hpp b/host/lib/usrp/cores/radio_ctrl_core_3000.hpp
index 8c0548d89..51a307c10 100644
--- a/host/lib/usrp/cores/radio_ctrl_core_3000.hpp
+++ b/host/lib/usrp/cores/radio_ctrl_core_3000.hpp
@@ -18,17 +18,18 @@
#ifndef INCLUDED_LIBUHD_USRP_RADIO_CTRL_3000_HPP
#define INCLUDED_LIBUHD_USRP_RADIO_CTRL_3000_HPP
+#include <uhd/utils/msg_task.hpp>
#include <uhd/types/time_spec.hpp>
#include <uhd/transport/zero_copy.hpp>
+#include <uhd/types/wb_iface.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
-#include "wb_iface.hpp"
#include <string>
/*!
* Provide access to peek, poke for the radio ctrl module
*/
-class radio_ctrl_core_3000 : public wb_iface
+class radio_ctrl_core_3000 : public uhd::wb_iface
{
public:
typedef boost::shared_ptr<radio_ctrl_core_3000> sptr;
@@ -43,7 +44,7 @@ public:
);
//! Hold a ref to a task thats feeding push response
- virtual void hold_task(boost::shared_ptr<void> task) = 0;
+ virtual void hold_task(uhd::msg_task::sptr task) = 0;
//! Push a response externall (resp_xport is NULL)
virtual void push_response(const boost::uint32_t *buff) = 0;
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.cpp b/host/lib/usrp/cores/rx_dsp_core_200.cpp
index ef6b85de9..2fdc220b5 100644
--- a/host/lib/usrp/cores/rx_dsp_core_200.cpp
+++ b/host/lib/usrp/cores/rx_dsp_core_200.cpp
@@ -59,8 +59,11 @@ public:
const size_t dsp_base, const size_t ctrl_base,
const boost::uint32_t sid, const bool lingering_packet
):
- _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid)
+ _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid)
{
+ // previously uninitialized - assuming zero for all
+ _tick_rate = _link_rate = _host_extra_scaling = _fxpt_scalar_correction = 0.0;
+
//init to something so update method has reasonable defaults
_scaling_adjustment = 1.0;
_dsp_extra_scaling = 1.0;
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.hpp b/host/lib/usrp/cores/rx_dsp_core_200.hpp
index b01f751e9..3937df9e8 100644
--- a/host/lib/usrp/cores/rx_dsp_core_200.hpp
+++ b/host/lib/usrp/cores/rx_dsp_core_200.hpp
@@ -24,7 +24,7 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <uhd/types/stream_cmd.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
class rx_dsp_core_200 : boost::noncopyable{
@@ -32,7 +32,7 @@ public:
typedef boost::shared_ptr<rx_dsp_core_200> sptr;
static sptr make(
- wb_iface::sptr iface,
+ uhd::wb_iface::sptr iface,
const size_t dsp_base, const size_t ctrl_base,
const boost::uint32_t sid, const bool lingering_packet = false
);
diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.cpp b/host/lib/usrp/cores/rx_dsp_core_3000.cpp
index 7b3324f74..525916032 100644
--- a/host/lib/usrp/cores/rx_dsp_core_3000.cpp
+++ b/host/lib/usrp/cores/rx_dsp_core_3000.cpp
@@ -50,10 +50,13 @@ public:
):
_iface(iface), _dsp_base(dsp_base)
{
+ // previously uninitialized - assuming zero for all
+ _link_rate = _host_extra_scaling = _fxpt_scalar_correction = 0.0;
+
//init to something so update method has reasonable defaults
_scaling_adjustment = 1.0;
_dsp_extra_scaling = 1.0;
- this->set_tick_rate(1.0);
+ _tick_rate = 1.0;
}
~rx_dsp_core_3000_impl(void)
diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.hpp b/host/lib/usrp/cores/rx_dsp_core_3000.hpp
index 23b12b9b7..02e5587a2 100644
--- a/host/lib/usrp/cores/rx_dsp_core_3000.hpp
+++ b/host/lib/usrp/cores/rx_dsp_core_3000.hpp
@@ -24,7 +24,7 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <uhd/types/stream_cmd.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
class rx_dsp_core_3000 : boost::noncopyable{
@@ -32,7 +32,7 @@ public:
typedef boost::shared_ptr<rx_dsp_core_3000> sptr;
static sptr make(
- wb_iface::sptr iface,
+ uhd::wb_iface::sptr iface,
const size_t dsp_base
);
diff --git a/host/lib/usrp/cores/rx_frontend_core_200.cpp b/host/lib/usrp/cores/rx_frontend_core_200.cpp
index 1813758da..864b5cc53 100644
--- a/host/lib/usrp/cores/rx_frontend_core_200.cpp
+++ b/host/lib/usrp/cores/rx_frontend_core_200.cpp
@@ -18,6 +18,8 @@
#include "rx_frontend_core_200.hpp"
#include <boost/math/special_functions/round.hpp>
+using namespace uhd;
+
#define REG_RX_FE_SWAP_IQ _base + 0 //lower bit
#define REG_RX_FE_MAG_CORRECTION _base + 4 //18 bits
#define REG_RX_FE_PHASE_CORRECTION _base + 8 //18 bits
@@ -36,7 +38,7 @@ static boost::uint32_t fs_to_bits(const double num, const size_t bits){
class rx_frontend_core_200_impl : public rx_frontend_core_200{
public:
rx_frontend_core_200_impl(wb_iface::sptr iface, const size_t base):
- _iface(iface), _base(base)
+ _i_dc_off(0), _q_dc_off(0), _iface(iface), _base(base)
{
//NOP
}
diff --git a/host/lib/usrp/cores/rx_frontend_core_200.hpp b/host/lib/usrp/cores/rx_frontend_core_200.hpp
index 5755424c8..8327aef8b 100644
--- a/host/lib/usrp/cores/rx_frontend_core_200.hpp
+++ b/host/lib/usrp/cores/rx_frontend_core_200.hpp
@@ -21,7 +21,7 @@
#include <uhd/config.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <complex>
#include <string>
@@ -29,7 +29,7 @@ class rx_frontend_core_200 : boost::noncopyable{
public:
typedef boost::shared_ptr<rx_frontend_core_200> sptr;
- static sptr make(wb_iface::sptr iface, const size_t base);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base);
virtual void set_mux(const bool swap) = 0;
diff --git a/host/lib/usrp/cores/rx_vita_core_3000.hpp b/host/lib/usrp/cores/rx_vita_core_3000.hpp
index b011a7388..577510728 100644
--- a/host/lib/usrp/cores/rx_vita_core_3000.hpp
+++ b/host/lib/usrp/cores/rx_vita_core_3000.hpp
@@ -24,7 +24,7 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <uhd/types/stream_cmd.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
class rx_vita_core_3000 : boost::noncopyable
@@ -33,7 +33,7 @@ public:
typedef boost::shared_ptr<rx_vita_core_3000> sptr;
static sptr make(
- wb_iface::sptr iface,
+ uhd::wb_iface::sptr iface,
const size_t base
);
diff --git a/host/lib/usrp/cores/spi_core_100.hpp b/host/lib/usrp/cores/spi_core_100.hpp
index 87d328aaa..ce53c0b86 100644
--- a/host/lib/usrp/cores/spi_core_100.hpp
+++ b/host/lib/usrp/cores/spi_core_100.hpp
@@ -22,14 +22,14 @@
#include <uhd/types/serial.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class spi_core_100 : boost::noncopyable, public uhd::spi_iface{
public:
typedef boost::shared_ptr<spi_core_100> sptr;
//! makes a new spi core from iface and slave base
- static sptr make(wb_iface::sptr iface, const size_t base);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base);
};
#endif /* INCLUDED_LIBUHD_USRP_SPI_CORE_100_HPP */
diff --git a/host/lib/usrp/cores/spi_core_3000.hpp b/host/lib/usrp/cores/spi_core_3000.hpp
index 995ad59db..923efed3d 100644
--- a/host/lib/usrp/cores/spi_core_3000.hpp
+++ b/host/lib/usrp/cores/spi_core_3000.hpp
@@ -22,7 +22,7 @@
#include <uhd/types/serial.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class spi_core_3000 : boost::noncopyable, public uhd::spi_iface
{
@@ -30,7 +30,7 @@ public:
typedef boost::shared_ptr<spi_core_3000> sptr;
//! makes a new spi core from iface and slave base
- static sptr make(wb_iface::sptr iface, const size_t base, const size_t readback);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base, const size_t readback);
//! Set the spi clock divider to something usable
virtual void set_divider(const double div) = 0;
diff --git a/host/lib/usrp/cores/time64_core_200.cpp b/host/lib/usrp/cores/time64_core_200.cpp
index 11b310362..ad5e6477c 100644
--- a/host/lib/usrp/cores/time64_core_200.cpp
+++ b/host/lib/usrp/cores/time64_core_200.cpp
@@ -48,6 +48,7 @@ public:
):
_iface(iface), _base(base),
_readback_bases(readback_bases),
+ _tick_rate(0.0),
_mimo_delay_cycles(mimo_delay_cycles)
{
_sources.push_back("none");
diff --git a/host/lib/usrp/cores/time64_core_200.hpp b/host/lib/usrp/cores/time64_core_200.hpp
index 315f2ba67..e211ce040 100644
--- a/host/lib/usrp/cores/time64_core_200.hpp
+++ b/host/lib/usrp/cores/time64_core_200.hpp
@@ -22,7 +22,7 @@
#include <uhd/types/time_spec.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
#include <vector>
@@ -37,7 +37,7 @@ public:
//! makes a new time64 core from iface and slave base
static sptr make(
- wb_iface::sptr iface, const size_t base,
+ uhd::wb_iface::sptr iface, const size_t base,
const readback_bases_type &readback_bases,
const size_t mimo_delay_cycles = 0 // 0 means no-mimo
);
diff --git a/host/lib/usrp/cores/time_core_3000.hpp b/host/lib/usrp/cores/time_core_3000.hpp
index ffe2f4133..fad408810 100644
--- a/host/lib/usrp/cores/time_core_3000.hpp
+++ b/host/lib/usrp/cores/time_core_3000.hpp
@@ -22,7 +22,7 @@
#include <uhd/types/time_spec.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class time_core_3000 : boost::noncopyable
{
@@ -37,7 +37,7 @@ public:
//! makes a new time core from iface and slave base
static sptr make(
- wb_iface::sptr iface, const size_t base,
+ uhd::wb_iface::sptr iface, const size_t base,
const readback_bases_type &readback_bases
);
diff --git a/host/lib/usrp/cores/tx_dsp_core_200.cpp b/host/lib/usrp/cores/tx_dsp_core_200.cpp
index 808f13028..f8aa87aa3 100644
--- a/host/lib/usrp/cores/tx_dsp_core_200.cpp
+++ b/host/lib/usrp/cores/tx_dsp_core_200.cpp
@@ -60,6 +60,9 @@ public:
):
_iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid)
{
+ // previously uninitialized - assuming zero for all
+ _tick_rate = _link_rate = _host_extra_scaling = _fxpt_scalar_correction = 0.0;
+
//init to something so update method has reasonable defaults
_scaling_adjustment = 1.0;
_dsp_extra_scaling = 1.0;
diff --git a/host/lib/usrp/cores/tx_dsp_core_200.hpp b/host/lib/usrp/cores/tx_dsp_core_200.hpp
index 0e1cfb6bc..ce3d1dbdd 100644
--- a/host/lib/usrp/cores/tx_dsp_core_200.hpp
+++ b/host/lib/usrp/cores/tx_dsp_core_200.hpp
@@ -23,14 +23,14 @@
#include <uhd/types/ranges.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class tx_dsp_core_200 : boost::noncopyable{
public:
typedef boost::shared_ptr<tx_dsp_core_200> sptr;
static sptr make(
- wb_iface::sptr iface,
+ uhd::wb_iface::sptr iface,
const size_t dsp_base, const size_t ctrl_base,
const boost::uint32_t sid
);
diff --git a/host/lib/usrp/cores/tx_dsp_core_3000.cpp b/host/lib/usrp/cores/tx_dsp_core_3000.cpp
index feb749cd9..93c8702bc 100644
--- a/host/lib/usrp/cores/tx_dsp_core_3000.cpp
+++ b/host/lib/usrp/cores/tx_dsp_core_3000.cpp
@@ -45,6 +45,9 @@ public:
):
_iface(iface), _dsp_base(dsp_base)
{
+ // previously uninitialized - assuming zero for all
+ _link_rate = _host_extra_scaling = _fxpt_scalar_correction = 0.0;
+
//init to something so update method has reasonable defaults
_scaling_adjustment = 1.0;
_dsp_extra_scaling = 1.0;
diff --git a/host/lib/usrp/cores/tx_dsp_core_3000.hpp b/host/lib/usrp/cores/tx_dsp_core_3000.hpp
index eb5ffaf0f..6f725b836 100644
--- a/host/lib/usrp/cores/tx_dsp_core_3000.hpp
+++ b/host/lib/usrp/cores/tx_dsp_core_3000.hpp
@@ -23,14 +23,14 @@
#include <uhd/types/ranges.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class tx_dsp_core_3000 : boost::noncopyable{
public:
typedef boost::shared_ptr<tx_dsp_core_3000> sptr;
static sptr make(
- wb_iface::sptr iface,
+ uhd::wb_iface::sptr iface,
const size_t dsp_base
);
diff --git a/host/lib/usrp/cores/tx_frontend_core_200.cpp b/host/lib/usrp/cores/tx_frontend_core_200.cpp
index e35874173..d701027e5 100644
--- a/host/lib/usrp/cores/tx_frontend_core_200.cpp
+++ b/host/lib/usrp/cores/tx_frontend_core_200.cpp
@@ -21,6 +21,8 @@
#include <boost/assign/list_of.hpp>
#include <boost/math/special_functions/round.hpp>
+using namespace uhd;
+
#define REG_TX_FE_DC_OFFSET_I _base + 0 //24 bits
#define REG_TX_FE_DC_OFFSET_Q _base + 4 //24 bits
#define REG_TX_FE_MAG_CORRECTION _base + 8 //18 bits
diff --git a/host/lib/usrp/cores/tx_frontend_core_200.hpp b/host/lib/usrp/cores/tx_frontend_core_200.hpp
index 8ee0f3e6d..7d09b39d2 100644
--- a/host/lib/usrp/cores/tx_frontend_core_200.hpp
+++ b/host/lib/usrp/cores/tx_frontend_core_200.hpp
@@ -21,7 +21,7 @@
#include <uhd/config.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <complex>
#include <string>
@@ -29,7 +29,7 @@ class tx_frontend_core_200 : boost::noncopyable{
public:
typedef boost::shared_ptr<tx_frontend_core_200> sptr;
- static sptr make(wb_iface::sptr iface, const size_t base);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base);
virtual void set_mux(const std::string &mode) = 0;
diff --git a/host/lib/usrp/cores/tx_vita_core_3000.hpp b/host/lib/usrp/cores/tx_vita_core_3000.hpp
index 2070936ce..d4677a3e3 100644
--- a/host/lib/usrp/cores/tx_vita_core_3000.hpp
+++ b/host/lib/usrp/cores/tx_vita_core_3000.hpp
@@ -24,7 +24,7 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <uhd/types/stream_cmd.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
class tx_vita_core_3000 : boost::noncopyable
@@ -33,7 +33,7 @@ public:
typedef boost::shared_ptr<tx_vita_core_3000> sptr;
static sptr make(
- wb_iface::sptr iface,
+ uhd::wb_iface::sptr iface,
const size_t base
);
diff --git a/host/lib/usrp/cores/user_settings_core_200.cpp b/host/lib/usrp/cores/user_settings_core_200.cpp
index d262631b1..391725edc 100644
--- a/host/lib/usrp/cores/user_settings_core_200.cpp
+++ b/host/lib/usrp/cores/user_settings_core_200.cpp
@@ -17,6 +17,8 @@
#include "user_settings_core_200.hpp"
+using namespace uhd;
+
#define REG_USER_ADDR _base + 0
#define REG_USER_DATA _base + 4
diff --git a/host/lib/usrp/cores/user_settings_core_200.hpp b/host/lib/usrp/cores/user_settings_core_200.hpp
index 1f5d13de7..f5fca2ce6 100644
--- a/host/lib/usrp/cores/user_settings_core_200.hpp
+++ b/host/lib/usrp/cores/user_settings_core_200.hpp
@@ -21,14 +21,14 @@
#include <uhd/config.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class user_settings_core_200 : boost::noncopyable{
public:
typedef boost::shared_ptr<user_settings_core_200> sptr;
typedef std::pair<boost::uint8_t, boost::uint32_t> user_reg_t;
- static sptr make(wb_iface::sptr iface, const size_t base);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base);
virtual void set_reg(const user_reg_t &reg) = 0;
};
diff --git a/host/lib/usrp/cores/wb_iface.hpp b/host/lib/usrp/cores/wb_iface.hpp
deleted file mode 100644
index 197788180..000000000
--- a/host/lib/usrp/cores/wb_iface.hpp
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-// Copyright 2011-2013 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_WB_IFACE_HPP
-#define INCLUDED_LIBUHD_USRP_WB_IFACE_HPP
-
-#include <uhd/config.hpp>
-#include <boost/cstdint.hpp>
-#include <boost/shared_ptr.hpp>
-
-class /*UHD_API*/ wb_iface
-{
-public:
- typedef boost::shared_ptr<wb_iface> sptr;
- typedef boost::uint32_t wb_addr_type;
-
- /*!
- * Write a register (64 bits)
- * \param addr the address
- * \param data the 64bit data
- */
- virtual void poke64(const wb_addr_type addr, const boost::uint64_t data);
-
- /*!
- * Read a register (64 bits)
- * \param addr the address
- * \return the 64bit data
- */
- virtual boost::uint64_t peek64(const wb_addr_type addr);
-
- /*!
- * Write a register (32 bits)
- * \param addr the address
- * \param data the 32bit data
- */
- virtual void poke32(const wb_addr_type addr, const boost::uint32_t data);
-
- /*!
- * Read a register (32 bits)
- * \param addr the address
- * \return the 32bit data
- */
- virtual boost::uint32_t peek32(const wb_addr_type addr);
-
- /*!
- * Write a register (16 bits)
- * \param addr the address
- * \param data the 16bit data
- */
- virtual void poke16(const wb_addr_type addr, const boost::uint16_t data);
-
- /*!
- * Read a register (16 bits)
- * \param addr the address
- * \return the 16bit data
- */
- virtual boost::uint16_t peek16(const wb_addr_type addr);
-
-};
-
-#endif /* INCLUDED_LIBUHD_USRP_WB_IFACE_HPP */
diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp
index b1cee4aa7..9d04d8e16 100644
--- a/host/lib/usrp/dboard/db_dbsrx.cpp
+++ b/host/lib/usrp/dboard/db_dbsrx.cpp
@@ -179,7 +179,7 @@ dbsrx::dbsrx(ctor_args_t args) : rx_dboard_base(args){
"DBSRX: incorrect dbid\n"
"Expected dbid 0x0002 and R193\n"
"found dbid == %d\n"
- "Please see the daughterboard app notes"
+ "Please see the daughterboard app notes"
) % this->get_rx_id().to_pp_string();
//warn user about incorrect DBID on non-USRP1, requires R194 populated
@@ -188,7 +188,7 @@ dbsrx::dbsrx(ctor_args_t args) : rx_dboard_base(args){
"DBSRX: incorrect dbid\n"
"Expected dbid 0x000D and R194\n"
"found dbid == %d\n"
- "Please see the daughterboard app notes"
+ "Please see the daughterboard app notes"
) % this->get_rx_id().to_pp_string();
//send initial register settings
@@ -305,13 +305,13 @@ double dbsrx::set_lo_freq(double target_freq){
goto done_loop;
}
- }
+ }
done_loop:
- //Assert because we failed to find a suitable combination of ref_clock, R and N
+ //Assert because we failed to find a suitable combination of ref_clock, R and N
UHD_ASSERT_THROW(ref_clock <= 27.0e6 and ref_clock >= 0.0);
- UHD_ASSERT_THROW(ref_clock/m >= 1e6 and ref_clock/m <= 2.5e6);
+ UHD_ASSERT_THROW(m and ref_clock/m >= 1e6 and ref_clock/m <= 2.5e6);
UHD_ASSERT_THROW((pfd_freq >= dbsrx_pfd_freq_range.start()) and (pfd_freq <= dbsrx_pfd_freq_range.stop()));
UHD_ASSERT_THROW((N >= 256) and (N <= 32768));
@@ -332,7 +332,7 @@ double dbsrx::set_lo_freq(double target_freq){
_max2118_write_regs.r_divider = (max2118_write_regs_t::r_divider_t) r;
_max2118_write_regs.set_n_divider(N);
_max2118_write_regs.ade_vco_ade_read = max2118_write_regs_t::ADE_VCO_ADE_READ_ENABLED;
-
+
//compute prescaler variables
int scaler = actual_freq > 1125e6 ? 2 : 4;
_max2118_write_regs.div2 = scaler == 4 ? max2118_write_regs_t::DIV2_DIV4 : max2118_write_regs_t::DIV2_DIV2;
@@ -377,7 +377,7 @@ double dbsrx::set_lo_freq(double target_freq){
if (_max2118_read_regs.adc == 0){
if (_max2118_write_regs.osc_band == 0){
UHD_MSG(warning) << boost::format(
- "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"
+ "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"
) % int(_max2118_write_regs.osc_band);
UHD_ASSERT_THROW(_max2118_read_regs.adc != 0); //just to cause a throw
}
@@ -389,7 +389,7 @@ double dbsrx::set_lo_freq(double target_freq){
if (_max2118_read_regs.adc == 7){
if (_max2118_write_regs.osc_band == 7){
UHD_MSG(warning) << boost::format(
- "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"
+ "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"
) % int(_max2118_write_regs.osc_band);
UHD_ASSERT_THROW(_max2118_read_regs.adc != 7); //just to cause a throw
}
@@ -408,7 +408,7 @@ double dbsrx::set_lo_freq(double target_freq){
//allow for setup time before checking condition again
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
}
-
+
UHD_LOGV(often) << boost::format(
"DBSRX: final vco %d, vtune adc %d"
) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl;
@@ -417,7 +417,7 @@ double dbsrx::set_lo_freq(double target_freq){
if (_max2118_read_regs.adc <= 2) _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_100UA;
else if (_max2118_read_regs.adc >= 5) _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_400UA;
else _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_200UA;
-
+
//update charge pump bias current setting
send_reg(0x2, 0x2);
@@ -524,7 +524,7 @@ double dbsrx::set_bandwidth(double bandwidth){
bandwidth = dbsrx_bandwidth_range.clip(bandwidth);
double ref_clock = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX);
-
+
//NOTE: _max2118_write_regs.m_divider set in set_lo_freq
//compute f_dac setting
diff --git a/host/lib/usrp/dboard/db_dbsrx2.cpp b/host/lib/usrp/dboard/db_dbsrx2.cpp
index 013f3178a..8a8f61a69 100644
--- a/host/lib/usrp/dboard/db_dbsrx2.cpp
+++ b/host/lib/usrp/dboard/db_dbsrx2.cpp
@@ -358,12 +358,12 @@ double dbsrx2::set_gain(double gain, const std::string &name){
* Bandwidth Handling
**********************************************************************/
double dbsrx2::set_bandwidth(double bandwidth){
- //convert complex bandpass to lowpass bandwidth
- bandwidth = bandwidth/2.0;
-
//clip the input
bandwidth = dbsrx2_bandwidth_range.clip(bandwidth);
+ //convert complex bandpass to lowpass bandwidth
+ bandwidth = bandwidth/2.0;
+
_max2112_write_regs.lp = int((bandwidth/1e6 - 4)/0.29 + 12);
_bandwidth = double(4 + (_max2112_write_regs.lp - 12) * 0.29)*1e6;
diff --git a/host/lib/usrp/dboard/db_sbx_common.cpp b/host/lib/usrp/dboard/db_sbx_common.cpp
index 9db29e65a..5b713c6d7 100644
--- a/host/lib/usrp/dboard/db_sbx_common.cpp
+++ b/host/lib/usrp/dboard/db_sbx_common.cpp
@@ -21,6 +21,137 @@ using namespace uhd;
using namespace uhd::usrp;
using namespace boost::assign;
+/***********************************************************************
+ * ADF 4350/4351 Tuning Utility
+ **********************************************************************/
+sbx_xcvr::sbx_versionx::adf435x_tuning_settings sbx_xcvr::sbx_versionx::_tune_adf435x_synth(
+ double target_freq,
+ double ref_freq,
+ const adf435x_tuning_constraints& constraints,
+ double& actual_freq)
+{
+ //Default invalid value for actual_freq
+ actual_freq = 0;
+
+ double pfd_freq = 0;
+ boost::uint16_t R = 0, BS = 0, N = 0, FRAC = 0, MOD = 0;
+ boost::uint16_t RFdiv = static_cast<boost::uint16_t>(constraints.rf_divider_range.start());
+ bool D = false, T = false;
+
+ //Reference doubler for 50% duty cycle
+ //If ref_freq < 12.5MHz enable the reference doubler
+ D = (ref_freq <= constraints.ref_doubler_threshold);
+
+ static const double MIN_VCO_FREQ = 2.2e9;
+ static const double MAX_VCO_FREQ = 4.4e9;
+
+ //increase RF divider until acceptable VCO frequency
+ double vco_freq = target_freq;
+ while (vco_freq < MIN_VCO_FREQ && RFdiv < static_cast<boost::uint16_t>(constraints.rf_divider_range.stop())) {
+ vco_freq *= 2;
+ RFdiv *= 2;
+ }
+
+ /*
+ * The goal here is to loop though possible R dividers,
+ * band select clock dividers, N (int) dividers, and FRAC
+ * (frac) dividers.
+ *
+ * Calculate the N and F dividers for each set of values.
+ * The loop exits when it meets all of the constraints.
+ * The resulting loop values are loaded into the registers.
+ *
+ * from pg.21
+ *
+ * f_pfd = f_ref*(1+D)/(R*(1+T))
+ * f_vco = (N + (FRAC/MOD))*f_pfd
+ * N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD
+ * f_rf = f_vco/RFdiv)
+ * f_actual = f_rf/2
+ */
+ for(R = 1; R <= 1023; R+=1){
+ //PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T)
+ pfd_freq = ref_freq*(D?2:1)/(R*(T?2:1));
+
+ //keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth)
+ if (pfd_freq > constraints.pfd_freq_max) continue;
+
+ //ignore fractional part of tuning
+ //N is computed from target_freq and not vco_freq because the feedback
+ //mode is set to FEEDBACK_SELECT_DIVIDED
+ N = boost::uint16_t(std::floor(target_freq/pfd_freq));
+
+ //keep N > minimum int divider requirement
+ if (N < static_cast<boost::uint16_t>(constraints.int_range.start())) continue;
+
+ for(BS=1; BS <= 255; BS+=1){
+ //keep the band select frequency at or below band_sel_freq_max
+ //constraint on band select clock
+ if (pfd_freq/BS > constraints.band_sel_freq_max) continue;
+ goto done_loop;
+ }
+ } done_loop:
+
+ //Fractional-N calculation
+ MOD = 4095; //max fractional accuracy
+ //N is computed from target_freq and not vco_freq because the feedback
+ //mode is set to FEEDBACK_SELECT_DIVIDED
+ FRAC = static_cast<boost::uint16_t>((target_freq/pfd_freq - N)*MOD);
+ if (constraints.force_frac0) {
+ if (FRAC > (MOD / 2)) { //Round integer such that actual freq is closest to target
+ N++;
+ }
+ FRAC = 0;
+ }
+
+ //Reference divide-by-2 for 50% duty cycle
+ // if R even, move one divide by 2 to to regs.reference_divide_by_2
+ if(R % 2 == 0) {
+ T = true;
+ R /= 2;
+ }
+
+ //Typical phase resync time documented in data sheet pg.24
+ static const double PHASE_RESYNC_TIME = 400e-6;
+
+ //actual frequency calculation
+ actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(D?2:1)/(R*(T?2:1)));
+
+ //load the settings
+ adf435x_tuning_settings settings;
+ settings.frac_12_bit = FRAC;
+ settings.int_16_bit = N;
+ settings.mod_12_bit = MOD;
+ settings.clock_divider_12_bit = std::max<boost::uint16_t>(1, std::ceil(PHASE_RESYNC_TIME*pfd_freq/MOD));
+ settings.r_counter_10_bit = R;
+ settings.r_divide_by_2_en = T;
+ settings.r_doubler_en = D;
+ settings.band_select_clock_div = BS;
+ settings.rf_divider = RFdiv;
+ settings.feedback_after_divider = true;
+
+ UHD_LOGV(often)
+ << boost::format("ADF 435X Frequencies (MHz): REQUESTED=%0.9f, ACTUAL=%0.9f"
+ ) % (target_freq/1e6) % (actual_freq/1e6) << std::endl
+ << boost::format("ADF 435X Intermediates (MHz): VCO=%0.2f, PFD=%0.2f, BAND=%0.2f, REF=%0.2f"
+ ) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) % (ref_freq/1e6) << std::endl
+ << boost::format("ADF 435X Settings: 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;
+
+ UHD_ASSERT_THROW((settings.frac_12_bit & ((boost::uint16_t)~0xFFF)) == 0);
+ UHD_ASSERT_THROW((settings.mod_12_bit & ((boost::uint16_t)~0xFFF)) == 0);
+ UHD_ASSERT_THROW((settings.clock_divider_12_bit & ((boost::uint16_t)~0xFFF)) == 0);
+ UHD_ASSERT_THROW((settings.r_counter_10_bit & ((boost::uint16_t)~0x3FF)) == 0);
+
+ UHD_ASSERT_THROW(vco_freq >= MIN_VCO_FREQ and vco_freq <= MAX_VCO_FREQ);
+ UHD_ASSERT_THROW(settings.rf_divider >= static_cast<boost::uint16_t>(constraints.rf_divider_range.start()));
+ UHD_ASSERT_THROW(settings.rf_divider <= static_cast<boost::uint16_t>(constraints.rf_divider_range.stop()));
+ UHD_ASSERT_THROW(settings.int_16_bit >= static_cast<boost::uint16_t>(constraints.int_range.start()));
+ UHD_ASSERT_THROW(settings.int_16_bit <= static_cast<boost::uint16_t>(constraints.int_range.stop()));
+
+ return settings;
+}
+
/***********************************************************************
* Register the SBX dboard (min freq, max freq, rx div2, tx div2)
@@ -362,4 +493,3 @@ void sbx_xcvr::flash_leds(void) {
this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, (TXIO_MASK|TX_LED_IO));
this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO));
}
-
diff --git a/host/lib/usrp/dboard/db_sbx_common.hpp b/host/lib/usrp/dboard/db_sbx_common.hpp
index 4f3a2eeaa..e9bb2434c 100644
--- a/host/lib/usrp/dboard/db_sbx_common.hpp
+++ b/host/lib/usrp/dboard/db_sbx_common.hpp
@@ -181,6 +181,34 @@ protected:
~sbx_versionx(void) {}
virtual double set_lo_freq(dboard_iface::unit_t unit, double target_freq) = 0;
+ protected:
+ struct adf435x_tuning_constraints {
+ bool force_frac0;
+ double ref_doubler_threshold;
+ double pfd_freq_max;
+ double band_sel_freq_max;
+ uhd::range_t rf_divider_range;
+ uhd::range_t int_range;
+ };
+
+ struct adf435x_tuning_settings {
+ boost::uint16_t frac_12_bit;
+ boost::uint16_t int_16_bit;
+ boost::uint16_t mod_12_bit;
+ boost::uint16_t r_counter_10_bit;
+ bool r_doubler_en;
+ bool r_divide_by_2_en;
+ boost::uint16_t clock_divider_12_bit;
+ boost::uint8_t band_select_clock_div;
+ boost::uint16_t rf_divider;
+ bool feedback_after_divider;
+ };
+
+ adf435x_tuning_settings _tune_adf435x_synth(
+ double target_freq,
+ double ref_freq,
+ const adf435x_tuning_constraints& constraints,
+ double& actual_freq);
};
/*!
diff --git a/host/lib/usrp/dboard/db_sbx_version3.cpp b/host/lib/usrp/dboard/db_sbx_version3.cpp
index 2765d530c..b0c9cd18f 100644
--- a/host/lib/usrp/dboard/db_sbx_version3.cpp
+++ b/host/lib/usrp/dboard/db_sbx_version3.cpp
@@ -63,85 +63,21 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
(16, adf4350_regs_t::RF_DIVIDER_SELECT_DIV16)
;
- double actual_freq, pfd_freq;
- double ref_freq = self_base->get_iface()->get_clock_rate(unit);
- int R=0, BS=0, N=0, FRAC=0, MOD=0;
- int RFdiv = 1;
- adf4350_regs_t::reference_divide_by_2_t T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED;
- adf4350_regs_t::reference_doubler_t D = adf4350_regs_t::REFERENCE_DOUBLER_DISABLED;
-
- //Reference doubler for 50% duty cycle
- // if ref_freq < 12.5MHz enable regs.reference_divide_by_2
- if(ref_freq <= 12.5e6) D = adf4350_regs_t::REFERENCE_DOUBLER_ENABLED;
-
- //increase RF divider until acceptable VCO frequency
- double vco_freq = target_freq;
- while (vco_freq < 2.2e9) {
- vco_freq *= 2;
- RFdiv *= 2;
- }
-
//use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler)
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,
- * band select clock dividers, N (int) dividers, and FRAC
- * (frac) dividers.
- *
- * Calculate the N and F dividers for each set of values.
- * The loop exits when it meets all of the constraints.
- * The resulting loop values are loaded into the registers.
- *
- * from pg.21
- *
- * f_pfd = f_ref*(1+D)/(R*(1+T))
- * f_vco = (N + (FRAC/MOD))*f_pfd
- * N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD
- * f_rf = f_vco/RFdiv)
- * f_actual = f_rf/2
- */
- for(R = 1; R <= 1023; R+=1){
- //PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T)
- pfd_freq = ref_freq*(1+D)/(R*(1+T));
-
- //keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth)
- if (pfd_freq > 25e6) continue;
-
- //ignore fractional part of tuning
- N = int(std::floor(target_freq/pfd_freq));
-
- //keep N > minimum int divider requirement
- if (N < prescaler_to_min_int_div[prescaler]) continue;
-
- for(BS=1; BS <= 255; BS+=1){
- //keep the band select frequency at or below 100KHz
- //constraint on band select clock
- if (pfd_freq/BS > 100e3) continue;
- goto done_loop;
- }
- } done_loop:
-
- //Fractional-N calculation
- MOD = 4095; //max fractional accuracy
- 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
- if(R % 2 == 0){
- T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED;
- R /= 2;
- }
-
- //actual frequency calculation
- actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T))));
+ adf435x_tuning_constraints tuning_constraints;
+ tuning_constraints.force_frac0 = false;
+ tuning_constraints.band_sel_freq_max = 100e3;
+ tuning_constraints.ref_doubler_threshold = 12.5e6;
+ tuning_constraints.int_range = uhd::range_t(prescaler_to_min_int_div[prescaler], 4095); //INT is a 12-bit field
+ tuning_constraints.pfd_freq_max = 25e6;
+ tuning_constraints.rf_divider_range = uhd::range_t(1, 16);
- 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"
- ) % 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;
+ double actual_freq;
+ adf435x_tuning_settings tuning_settings = _tune_adf435x_synth(
+ target_freq, self_base->get_iface()->get_clock_rate(unit),
+ tuning_constraints, actual_freq);
//load the register values
adf4350_regs_t regs;
@@ -151,19 +87,25 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
else
regs.output_power = adf4350_regs_t::OUTPUT_POWER_5DBM;
- 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;
- regs.reference_doubler = D;
- regs.band_select_clock_div = BS;
- UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(RFdiv));
- regs.rf_divider_select = rfdivsel_to_enum[RFdiv];
+ regs.frac_12_bit = tuning_settings.frac_12_bit;
+ regs.int_16_bit = tuning_settings.int_16_bit;
+ regs.mod_12_bit = tuning_settings.mod_12_bit;
+ regs.clock_divider_12_bit = tuning_settings.clock_divider_12_bit;
+ regs.feedback_select = tuning_settings.feedback_after_divider ?
+ adf4350_regs_t::FEEDBACK_SELECT_DIVIDED :
+ adf4350_regs_t::FEEDBACK_SELECT_FUNDAMENTAL;
+ regs.clock_div_mode = adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
+ regs.prescaler = prescaler;
+ regs.r_counter_10_bit = tuning_settings.r_counter_10_bit;
+ regs.reference_divide_by_2 = tuning_settings.r_divide_by_2_en ?
+ adf4350_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED :
+ adf4350_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED;
+ regs.reference_doubler = tuning_settings.r_doubler_en ?
+ adf4350_regs_t::REFERENCE_DOUBLER_ENABLED :
+ adf4350_regs_t::REFERENCE_DOUBLER_DISABLED;
+ regs.band_select_clock_div = tuning_settings.band_select_clock_div;
+ UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(tuning_settings.rf_divider));
+ regs.rf_divider_select = rfdivsel_to_enum[tuning_settings.rf_divider];
//reset the N and R counter
regs.counter_reset = adf4350_regs_t::COUNTER_RESET_ENABLED;
diff --git a/host/lib/usrp/dboard/db_sbx_version4.cpp b/host/lib/usrp/dboard/db_sbx_version4.cpp
index 27fd68b05..8d95b0655 100644
--- a/host/lib/usrp/dboard/db_sbx_version4.cpp
+++ b/host/lib/usrp/dboard/db_sbx_version4.cpp
@@ -66,85 +66,21 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
(64, adf4351_regs_t::RF_DIVIDER_SELECT_DIV64)
;
- double actual_freq, pfd_freq;
- double ref_freq = self_base->get_iface()->get_clock_rate(unit);
- int R=0, BS=0, N=0, FRAC=0, MOD=0;
- int RFdiv = 1;
- adf4351_regs_t::reference_divide_by_2_t T = adf4351_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED;
- adf4351_regs_t::reference_doubler_t D = adf4351_regs_t::REFERENCE_DOUBLER_DISABLED;
-
- //Reference doubler for 50% duty cycle
- // if ref_freq < 12.5MHz enable regs.reference_divide_by_2
- if(ref_freq <= 12.5e6) D = adf4351_regs_t::REFERENCE_DOUBLER_ENABLED;
-
- //increase RF divider until acceptable VCO frequency
- double vco_freq = target_freq;
- while (vco_freq < 2.2e9) {
- vco_freq *= 2;
- RFdiv *= 2;
- }
-
//use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler)
- 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,
- * band select clock dividers, N (int) dividers, and FRAC
- * (frac) dividers.
- *
- * Calculate the N and F dividers for each set of values.
- * The loop exits when it meets all of the constraints.
- * The resulting loop values are loaded into the registers.
- *
- * from pg.21
- *
- * f_pfd = f_ref*(1+D)/(R*(1+T))
- * f_vco = (N + (FRAC/MOD))*f_pfd
- * N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD
- * f_rf = f_vco/RFdiv)
- * f_actual = f_rf/2
- */
- for(R = 1; R <= 1023; R+=1){
- //PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T)
- pfd_freq = ref_freq*(1+D)/(R*(1+T));
-
- //keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth)
- if (pfd_freq > 25e6) continue;
-
- //ignore fractional part of tuning
- N = int(std::floor(vco_freq/pfd_freq));
-
- //keep N > minimum int divider requirement
- if (N < prescaler_to_min_int_div[prescaler]) continue;
-
- for(BS=1; BS <= 255; BS+=1){
- //keep the band select frequency at or below 100KHz
- //constraint on band select clock
- if (pfd_freq/BS > 100e3) continue;
- goto done_loop;
- }
- } done_loop:
-
- //Fractional-N calculation
- MOD = 4095; //max fractional accuracy
- 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
- if(R % 2 == 0){
- T = adf4351_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED;
- R /= 2;
- }
+ adf4351_regs_t::prescaler_t prescaler = target_freq > 3.6e9 ? adf4351_regs_t::PRESCALER_8_9 : adf4351_regs_t::PRESCALER_4_5;
- //actual frequency calculation
- actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T))));
+ adf435x_tuning_constraints tuning_constraints;
+ tuning_constraints.force_frac0 = false;
+ tuning_constraints.band_sel_freq_max = 100e3;
+ tuning_constraints.ref_doubler_threshold = 12.5e6;
+ tuning_constraints.int_range = uhd::range_t(prescaler_to_min_int_div[prescaler], 4095); //INT is a 12-bit field
+ tuning_constraints.pfd_freq_max = 25e6;
+ tuning_constraints.rf_divider_range = uhd::range_t(1, 64);
- 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"
- ) % 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;
+ double actual_freq;
+ adf435x_tuning_settings tuning_settings = _tune_adf435x_synth(
+ target_freq, self_base->get_iface()->get_clock_rate(unit),
+ tuning_constraints, actual_freq);
//load the register values
adf4351_regs_t regs;
@@ -154,19 +90,25 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
else
regs.output_power = adf4351_regs_t::OUTPUT_POWER_5DBM;
- 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;
- regs.reference_doubler = D;
- regs.band_select_clock_div = BS;
- UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(RFdiv));
- regs.rf_divider_select = rfdivsel_to_enum[RFdiv];
+ regs.frac_12_bit = tuning_settings.frac_12_bit;
+ regs.int_16_bit = tuning_settings.int_16_bit;
+ regs.mod_12_bit = tuning_settings.mod_12_bit;
+ regs.clock_divider_12_bit = tuning_settings.clock_divider_12_bit;
+ regs.feedback_select = tuning_settings.feedback_after_divider ?
+ adf4351_regs_t::FEEDBACK_SELECT_DIVIDED :
+ adf4351_regs_t::FEEDBACK_SELECT_FUNDAMENTAL;
+ regs.clock_div_mode = adf4351_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
+ regs.prescaler = prescaler;
+ regs.r_counter_10_bit = tuning_settings.r_counter_10_bit;
+ regs.reference_divide_by_2 = tuning_settings.r_divide_by_2_en ?
+ adf4351_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED :
+ adf4351_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED;
+ regs.reference_doubler = tuning_settings.r_doubler_en ?
+ adf4351_regs_t::REFERENCE_DOUBLER_ENABLED :
+ adf4351_regs_t::REFERENCE_DOUBLER_DISABLED;
+ regs.band_select_clock_div = tuning_settings.band_select_clock_div;
+ UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(tuning_settings.rf_divider));
+ regs.rf_divider_select = rfdivsel_to_enum[tuning_settings.rf_divider];
//reset the N and R counter
regs.counter_reset = adf4351_regs_t::COUNTER_RESET_ENABLED;
diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp
index edee46cd5..e9f60f765 100644
--- a/host/lib/usrp/dboard/db_tvrx.cpp
+++ b/host/lib/usrp/dboard/db_tvrx.cpp
@@ -267,7 +267,7 @@ static std::string get_band(double freq) {
* \return a voltage to feed the TVRX analog gain
*/
-static double gain_interp(double gain, boost::array<double, 17> db_vector, boost::array<double, 17> volts_vector) {
+static double gain_interp(double gain, const boost::array<double, 17>& db_vector, const boost::array<double, 17>& volts_vector) {
double volts;
gain = uhd::clip<double>(gain, db_vector.front(), db_vector.back()); //let's not get carried away here
diff --git a/host/lib/usrp/dboard/db_wbx_common.hpp b/host/lib/usrp/dboard/db_wbx_common.hpp
index 9e984dce7..d1beb160e 100644
--- a/host/lib/usrp/dboard/db_wbx_common.hpp
+++ b/host/lib/usrp/dboard/db_wbx_common.hpp
@@ -118,7 +118,7 @@ protected:
*/
class wbx_versionx {
public:
- wbx_versionx() {}
+ wbx_versionx():self_base(NULL) {}
~wbx_versionx(void) {}
virtual double set_tx_gain(double gain, const std::string &name) = 0;
diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp
index 6f64d4b80..813f9cc8f 100644
--- a/host/lib/usrp/e100/e100_impl.hpp
+++ b/host/lib/usrp/e100/e100_impl.hpp
@@ -61,7 +61,7 @@ extern void e100_load_fpga(const std::string &bin_file);
//! Make an e100 dboard interface
uhd::usrp::dboard_iface::sptr make_e100_dboard_iface(
- wb_iface::sptr wb_iface,
+ uhd::wb_iface::sptr wb_iface,
uhd::i2c_iface::sptr i2c_iface,
uhd::spi_iface::sptr spi_iface,
e100_clock_ctrl::sptr clock,
diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp
index c3af75faa..105a52b30 100644
--- a/host/lib/usrp/gps_ctrl.cpp
+++ b/host/lib/usrp/gps_ctrl.cpp
@@ -223,7 +223,6 @@ private:
boost::this_thread::sleep(milliseconds(GPS_TIMEOUT_DELAY_MS));
}
throw uhd::value_error(str(boost::format("get_nmea(): no %s message found") % msgtype));
- return std::string();
}
//helper function to retrieve a field from an NMEA sentence
@@ -322,7 +321,6 @@ private:
boost::this_thread::sleep(milliseconds(GPS_TIMEOUT_DELAY_MS));
}
throw uhd::value_error("get_stat(): no servo message found");
- return std::string();
}
uart_iface::sptr _uart;
diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp
index d384eb13f..e1f17e5a6 100644
--- a/host/lib/usrp/usrp1/io_impl.cpp
+++ b/host/lib/usrp/usrp1/io_impl.cpp
@@ -63,7 +63,7 @@ static const size_t alignment_padding = 512;
* Helper struct to associate an offset with a buffer
**********************************************************************/
struct offset_send_buffer{
- offset_send_buffer(void){
+ offset_send_buffer(void):offset(0){
/* NOP */
}
diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp
index 9301721aa..6eff9d3ad 100644
--- a/host/lib/usrp/usrp1/usrp1_iface.cpp
+++ b/host/lib/usrp/usrp1/usrp1_iface.cpp
@@ -91,11 +91,11 @@ public:
return uhd::ntohx(value_out);
}
-
+
void poke16(boost::uint32_t, boost::uint16_t) {
throw uhd::not_implemented_error("Unhandled command poke16()");
}
-
+
boost::uint16_t peek16(boost::uint32_t) {
throw uhd::not_implemented_error("Unhandled command peek16()");
return 0;
@@ -141,8 +141,10 @@ public:
if (readback) {
unsigned char buff[4] = {
- (bits >> 0) & 0xff, (bits >> 8) & 0xff,
- (bits >> 16) & 0xff, (bits >> 24) & 0xff
+ (unsigned char)(bits & 0xff),
+ (unsigned char)((bits >> 8) & 0xff),
+ (unsigned char)((bits >> 16) & 0xff),
+ (unsigned char)((bits >> 24) & 0xff)
};
//conditions where there are two header bytes
if (num_bytes >= 3 and buff[num_bytes-1] != 0 and buff[num_bytes-2] != 0 and buff[num_bytes-3] == 0){
@@ -168,7 +170,7 @@ public:
(((boost::uint32_t)buff[1]) << 8) |
(((boost::uint32_t)buff[2]) << 16) |
(((boost::uint32_t)buff[3]) << 24);
- return val;
+ return val;
}
else {
// Byteswap on num_bytes
diff --git a/host/lib/usrp/usrp1/usrp1_iface.hpp b/host/lib/usrp/usrp1/usrp1_iface.hpp
index 4612d7912..7fc943190 100644
--- a/host/lib/usrp/usrp1/usrp1_iface.hpp
+++ b/host/lib/usrp/usrp1/usrp1_iface.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2013 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,7 +19,7 @@
#define INCLUDED_USRP1_IFACE_HPP
#include "fx2_ctrl.hpp"
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <uhd/types/serial.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
@@ -42,7 +42,8 @@
* Provides a set of functions to implementation layer.
* Including spi, peek, poke, control...
*/
-class usrp1_iface : public wb_iface, public uhd::i2c_iface, public uhd::spi_iface, boost::noncopyable{
+class usrp1_iface : public uhd::wb_iface, public uhd::i2c_iface, public uhd::spi_iface, boost::noncopyable
+{
public:
typedef boost::shared_ptr<usrp1_iface> sptr;
diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp
index 253ac1d6f..625926f36 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.cpp
@@ -258,12 +258,14 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){
_tree->create<std::string>(rx_codec_path / "name").set("ad9522");
_tree->create<meta_range_t>(rx_codec_path / "gains/pga/range").set(usrp1_codec_ctrl::rx_pga_gain_range);
_tree->create<double>(rx_codec_path / "gains/pga/value")
- .coerce(boost::bind(&usrp1_impl::update_rx_codec_gain, this, db, _1));
+ .coerce(boost::bind(&usrp1_impl::update_rx_codec_gain, this, db, _1))
+ .set(0.0);
_tree->create<std::string>(tx_codec_path / "name").set("ad9522");
_tree->create<meta_range_t>(tx_codec_path / "gains/pga/range").set(usrp1_codec_ctrl::tx_pga_gain_range);
_tree->create<double>(tx_codec_path / "gains/pga/value")
.subscribe(boost::bind(&usrp1_codec_ctrl::set_tx_pga_gain, _dbc[db].codec, _1))
- .publish(boost::bind(&usrp1_codec_ctrl::get_tx_pga_gain, _dbc[db].codec));
+ .publish(boost::bind(&usrp1_codec_ctrl::get_tx_pga_gain, _dbc[db].codec))
+ .set(0.0);
}
////////////////////////////////////////////////////////////////////
@@ -407,7 +409,7 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){
_tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(_rx_subdev_spec);
if (_tree->list(mb_path / "tx_dsps").size() > 0)
_tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(_tx_subdev_spec);
-
+
}
usrp1_impl::~usrp1_impl(void){
diff --git a/host/lib/usrp/usrp2/usrp2_clk_regs.hpp b/host/lib/usrp/usrp2/usrp2_clk_regs.hpp
index 8b185eac0..d5e506d8d 100644
--- a/host/lib/usrp/usrp2/usrp2_clk_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_clk_regs.hpp
@@ -22,8 +22,18 @@
class usrp2_clk_regs_t {
public:
- usrp2_clk_regs_t(void) { ; }
+ usrp2_clk_regs_t(void):
+ test(0),
+ fpga(0),
+ adc(0),
+ dac(0),
+ serdes(0),
+ exp(0),
+ tx_db(0),
+ rx_db(0) {}
+
usrp2_clk_regs_t(usrp2_iface::rev_type rev) {
+ fpga = adc = serdes = exp = tx_db = 0;
test = 0;
fpga = 1;
dac = 3;
@@ -54,7 +64,7 @@ public:
//dont throw, it may be unitialized
break;
}
-
+
rx_db = 7;
}
diff --git a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp
index b48d05aa2..13dfb5b46 100644
--- a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp
@@ -23,14 +23,15 @@
#include <uhd/transport/zero_copy.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/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{
+class usrp2_fifo_ctrl : public uhd::wb_iface, public uhd::spi_iface
+{
public:
typedef boost::shared_ptr<usrp2_fifo_ctrl> sptr;
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index 3b230ca69..5f97045e1 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -271,7 +271,7 @@ public:
//send and recv
usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_I2C);
UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE);
- UHD_ASSERT_THROW(in_data.data.i2c_args.addr = num_bytes);
+ UHD_ASSERT_THROW(in_data.data.i2c_args.bytes == num_bytes);
//copy out the data
byte_vector_t result(num_bytes);
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
index ed4de02d5..a01f2ccfa 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.hpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2012 Ettus Research LLC
+// Copyright 2010-2013 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include "usrp2_regs.hpp"
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
/*!
@@ -33,7 +33,8 @@
* Provides a set of functions to implementation layer.
* Including spi, peek, poke, control...
*/
-class usrp2_iface : public wb_iface, public uhd::spi_iface, public uhd::i2c_iface{
+class usrp2_iface : public uhd::wb_iface, public uhd::spi_iface, public uhd::i2c_iface
+{
public:
typedef boost::shared_ptr<usrp2_iface> sptr;
/*!
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index a6c0d87cf..f9988287f 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -57,7 +57,7 @@ static const std::string USRP2_EEPROM_MAP_KEY = "N100";
//! Make a usrp2 dboard interface.
uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface(
- wb_iface::sptr wb_iface,
+ uhd::wb_iface::sptr wb_iface,
uhd::i2c_iface::sptr i2c_iface,
uhd::spi_iface::sptr spi_iface,
usrp2_clock_ctrl::sptr clk_ctrl
@@ -84,7 +84,7 @@ private:
usrp2_iface::sptr iface;
usrp2_fifo_ctrl::sptr fifo_ctrl;
uhd::spi_iface::sptr spiface;
- wb_iface::sptr wbiface;
+ uhd::wb_iface::sptr wbiface;
usrp2_clock_ctrl::sptr clock;
usrp2_codec_ctrl::sptr codec;
uhd::gps_ctrl::sptr gps;
diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp
index 53055314b..3e2bea1c6 100644
--- a/host/lib/utils/paths.cpp
+++ b/host/lib/utils/paths.cpp
@@ -34,8 +34,19 @@
namespace fs = boost::filesystem;
/***********************************************************************
+ * Get a list of paths for an environment variable
+ **********************************************************************/
+static std::string get_env_var(const std::string &var_name, const std::string &def_val = ""){
+ const char *var_value_ptr = std::getenv(var_name.c_str());
+ return (var_value_ptr == NULL)? def_val : var_value_ptr;
+}
+
+static std::vector<fs::path> get_env_paths(const std::string &var_name){
+
+/***********************************************************************
* Determine the paths separator
**********************************************************************/
+
#ifdef UHD_PLATFORM_WIN32
static const std::string env_path_sep = ";";
#else
@@ -46,16 +57,6 @@ namespace fs = boost::filesystem;
boost::tokenizer<boost::char_separator<char> > \
(inp, boost::char_separator<char>(env_path_sep.c_str()))
-/***********************************************************************
- * Get a list of paths for an environment variable
- **********************************************************************/
-static std::string get_env_var(const std::string &var_name, const std::string &def_val = ""){
- const char *var_value_ptr = std::getenv(var_name.c_str());
- return (var_value_ptr == NULL)? def_val : var_value_ptr;
-}
-
-static std::vector<fs::path> get_env_paths(const std::string &var_name){
-
std::string var_value = get_env_var(var_name);
//convert to filesystem path, filter blank paths
@@ -85,6 +86,7 @@ std::vector<fs::path> get_image_paths(void){
std::vector<fs::path> get_module_paths(void){
std::vector<fs::path> paths = get_env_paths("UHD_MODULE_PATH");
paths.push_back(fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "modules");
+ paths.push_back(fs::path(uhd::get_pkg_path()) / "share" / "uhd" / "modules");
return paths;
}
@@ -113,8 +115,8 @@ std::string uhd::get_tmp_path(void){
//try the stdio define if available
#ifdef P_tmpdir
- if (P_tmpdir != NULL) return P_tmpdir;
- #endif
+ return P_tmpdir;
+ #else
//try unix environment variables
tmp_path = std::getenv("TMPDIR");
@@ -122,6 +124,7 @@ std::string uhd::get_tmp_path(void){
//give up and use the unix default
return "/tmp";
+ #endif
}
std::string uhd::get_app_path(void){
diff --git a/host/lib/utils/tasks.cpp b/host/lib/utils/tasks.cpp
index 1f735de06..08c32a5fb 100644
--- a/host/lib/utils/tasks.cpp
+++ b/host/lib/utils/tasks.cpp
@@ -16,11 +16,13 @@
//
#include <uhd/utils/tasks.hpp>
+#include <uhd/utils/msg_task.hpp>
#include <uhd/utils/msg.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/barrier.hpp>
#include <exception>
#include <iostream>
+#include <vector>
using namespace uhd;
@@ -80,3 +82,100 @@ private:
task::sptr task::make(const task_fcn_type &task_fcn){
return task::sptr(new task_impl(task_fcn));
}
+
+/*
+ * During shutdown pointers to queues for radio_ctrl_core might not be available anymore.
+ * msg_task_impl provides a dump_queue for such messages.
+ * ctrl_cores can check this queue for stranded messages.
+ */
+
+class msg_task_impl : public msg_task{
+public:
+
+ msg_task_impl(const task_fcn_type &task_fcn):
+ _spawn_barrier(2)
+ {
+ _thread_group.create_thread(boost::bind(&msg_task_impl::task_loop, this, task_fcn));
+ _spawn_barrier.wait();
+ }
+
+ ~msg_task_impl(void){
+ _running = false;
+ _thread_group.interrupt_all();
+ _thread_group.join_all();
+ }
+
+ /*
+ * Returns the first message for the given SID.
+ * This way a radio_ctrl_core doesn't have to die in timeout but can check for stranded messages here.
+ * This might happen during shutdown when dtors are called.
+ * See also: comments in b200_io_impl->handle_async_task
+ */
+ msg_payload_t get_msg_from_dump_queue(boost::uint32_t sid)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ msg_payload_t b;
+ for (size_t i = 0; i < _dump_queue.size(); i++) {
+ if (sid == _dump_queue[i].first) {
+ b = _dump_queue[i].second;
+ _dump_queue.erase(_dump_queue.begin() + i);
+ break;
+ }
+ }
+ return b;
+ }
+
+private:
+
+ void task_loop(const task_fcn_type &task_fcn){
+ _running = true;
+ _spawn_barrier.wait();
+
+ try{
+ while (_running){
+ boost::optional<msg_type_t> buff = task_fcn();
+ if(buff != boost::none){
+ /*
+ * If a message gets stranded it is returned by task_fcn and then pushed to the dump_queue.
+ * This way ctrl_cores can check dump_queue for missing messages.
+ */
+ boost::mutex::scoped_lock lock(_mutex);
+ _dump_queue.push_back(buff.get() );
+ }
+ }
+ }
+ catch(const boost::thread_interrupted &){
+ //this is an ok way to exit the task loop
+ }
+ catch(const std::exception &e){
+ do_error_msg(e.what());
+ }
+ catch(...){
+ //FIXME
+ //Unfortunately, this is also an ok way to end a task,
+ //because on some systems boost throws uncatchables.
+ }
+ }
+
+ void do_error_msg(const std::string &msg){
+ UHD_MSG(error)
+ << "An unexpected exception was caught in a task loop." << std::endl
+ << "The task loop will now exit, things may not work." << std::endl
+ << msg << std::endl
+ ;
+ }
+
+ boost::mutex _mutex;
+ boost::thread_group _thread_group;
+ boost::barrier _spawn_barrier;
+ bool _running;
+
+ /*
+ * This queue holds stranded messages until a radio_ctrl_core grabs them via 'get_msg_from_dump_queue'.
+ */
+ std::vector <msg_type_t> _dump_queue;
+};
+
+msg_task::sptr msg_task::make(const task_fcn_type &task_fcn){
+ return msg_task::sptr(new msg_task_impl(task_fcn));
+}