diff options
Diffstat (limited to 'host/lib')
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 ®) = 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)); +} |