aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/common
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/common')
-rw-r--r--host/lib/usrp/common/CMakeLists.txt4
-rw-r--r--host/lib/usrp/common/ad9361_ctrl.cpp165
-rw-r--r--host/lib/usrp/common/ad9361_ctrl.hpp127
-rw-r--r--host/lib/usrp/common/ad9361_transaction.h102
-rw-r--r--host/lib/usrp/common/adf4001_ctrl.cpp151
-rw-r--r--host/lib/usrp/common/adf4001_ctrl.hpp142
-rw-r--r--host/lib/usrp/common/recv_packet_demuxer_3000.hpp14
7 files changed, 703 insertions, 2 deletions
diff --git a/host/lib/usrp/common/CMakeLists.txt b/host/lib/usrp/common/CMakeLists.txt
index fa07e3d1d..1728b63f9 100644
--- a/host/lib/usrp/common/CMakeLists.txt
+++ b/host/lib/usrp/common/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2011-2012 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
@@ -29,6 +29,8 @@ ENDIF(ENABLE_USB)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/adf4001_ctrl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ad9361_ctrl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/apply_corrections.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_subdev_spec.cpp
${CMAKE_CURRENT_SOURCE_DIR}/recv_packet_demuxer.cpp
diff --git a/host/lib/usrp/common/ad9361_ctrl.cpp b/host/lib/usrp/common/ad9361_ctrl.cpp
new file mode 100644
index 000000000..ae7cc6f9b
--- /dev/null
+++ b/host/lib/usrp/common/ad9361_ctrl.cpp
@@ -0,0 +1,165 @@
+//
+// Copyright 2012-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/>.
+//
+
+#include "ad9361_ctrl.hpp"
+#include "ad9361_transaction.h"
+#include <uhd/exception.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/format.hpp>
+#include <cstring>
+
+using namespace uhd;
+
+struct ad9361_ctrl_impl : public ad9361_ctrl
+{
+ ad9361_ctrl_impl(ad9361_ctrl_iface_sptr iface):
+ _iface(iface), _seq(0)
+ {
+ ad9361_transaction_t request;
+
+ request.action = AD9361_ACTION_ECHO;
+ this->do_transaction(request);
+
+ request.action = AD9361_ACTION_INIT;
+ this->do_transaction(request);
+ }
+
+ double set_gain(const std::string &which, const double value)
+ {
+ ad9361_transaction_t request;
+
+ if (which == "RX1") request.action = AD9361_ACTION_SET_RX1_GAIN;
+ if (which == "RX2") request.action = AD9361_ACTION_SET_RX2_GAIN;
+ if (which == "TX1") request.action = AD9361_ACTION_SET_TX1_GAIN;
+ if (which == "TX2") request.action = AD9361_ACTION_SET_TX2_GAIN;
+
+ ad9361_double_pack(value, request.value.gain);
+ const ad9361_transaction_t reply = this->do_transaction(request);
+ return ad9361_double_unpack(reply.value.gain);
+ }
+
+ //! set a new clock rate, return the exact value
+ double set_clock_rate(const double rate)
+ {
+ //warning for known trouble rates
+ if (rate > 56e6) UHD_MSG(warning) << boost::format(
+ "The requested clock rate %f MHz may cause slow configuration.\n"
+ "The driver recommends a master clock rate less than %f MHz.\n"
+ ) % (rate/1e6) % 56.0 << std::endl;
+
+ //clip to known bounds
+ const meta_range_t clock_rate_range(250e3, 61.44e6);
+ const double clipped_rate = clock_rate_range.clip(rate);
+
+ ad9361_transaction_t request;
+ request.action = AD9361_ACTION_SET_CLOCK_RATE;
+ ad9361_double_pack(clipped_rate, request.value.rate);
+ const ad9361_transaction_t reply = this->do_transaction(request);
+ return ad9361_double_unpack(reply.value.rate);
+ }
+
+ //! set which RX and TX chains/antennas are active
+ void set_active_chains(bool tx1, bool tx2, bool rx1, bool rx2)
+ {
+ boost::uint32_t mask = 0;
+ if (tx1) mask |= (1 << 0);
+ if (tx2) mask |= (1 << 1);
+ if (rx1) mask |= (1 << 2);
+ if (rx2) mask |= (1 << 3);
+
+ ad9361_transaction_t request;
+ request.action = AD9361_ACTION_SET_ACTIVE_CHAINS;
+ request.value.enable_mask = mask;
+ this->do_transaction(request);
+ }
+
+ //! tune the given frontend, return the exact value
+ double tune(const std::string &which, const double freq)
+ {
+ //clip to known bounds
+ const meta_range_t freq_range(50e6, 6e9);
+ const double clipped_freq = freq_range.clip(freq);
+
+ ad9361_transaction_t request;
+
+ if (which[0] == 'R') request.action = AD9361_ACTION_SET_RX_FREQ;
+ if (which[0] == 'T') request.action = AD9361_ACTION_SET_TX_FREQ;
+
+ const double value = ad9361_ctrl::get_rf_freq_range().clip(clipped_freq);
+ ad9361_double_pack(value, request.value.freq);
+ const ad9361_transaction_t reply = this->do_transaction(request);
+ return ad9361_double_unpack(reply.value.freq);
+ }
+
+ //! turn on/off Catalina's data port loopback
+ void data_port_loopback(const bool on)
+ {
+ ad9361_transaction_t request;
+ request.action = AD9361_ACTION_SET_CODEC_LOOP;
+ request.value.codec_loop = on? 1 : 0;
+ this->do_transaction(request);
+ }
+
+ ad9361_transaction_t do_transaction(const ad9361_transaction_t &request)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+
+ //declare in/out buffers
+ unsigned char in_buff[64] = {};
+ unsigned char out_buff[64] = {};
+
+ //copy the input transaction
+ std::memcpy(in_buff, &request, sizeof(request));
+
+ //fill in other goodies
+ ad9361_transaction_t *in = (ad9361_transaction_t *)in_buff;
+ in->version = AD9361_TRANSACTION_VERSION;
+ in->sequence = _seq++;
+
+ //transact
+ _iface->ad9361_transact(in_buff, out_buff);
+ ad9361_transaction_t *out = (ad9361_transaction_t *)out_buff;
+
+ //sanity checks
+ UHD_ASSERT_THROW(out->version == in->version);
+ UHD_ASSERT_THROW(out->sequence == in->sequence);
+
+ //handle errors
+ const size_t len = strnlen(out->error_msg, AD9361_TRANSACTION_MAX_ERROR_MSG);
+ const std::string error_msg(out->error_msg, len);
+ if (not error_msg.empty()) throw uhd::runtime_error("ad9361 do transaction: " + error_msg);
+
+ //return result done!
+ return *out;
+ }
+
+ ad9361_ctrl_iface_sptr _iface;
+ size_t _seq;
+ boost::mutex _mutex;
+
+};
+
+
+/***********************************************************************
+ * Make an instance of the implementation
+ **********************************************************************/
+ad9361_ctrl::sptr ad9361_ctrl::make(ad9361_ctrl_iface_sptr iface)
+{
+ return sptr(new ad9361_ctrl_impl(iface));
+}
diff --git a/host/lib/usrp/common/ad9361_ctrl.hpp b/host/lib/usrp/common/ad9361_ctrl.hpp
new file mode 100644
index 000000000..6d79ef3e9
--- /dev/null
+++ b/host/lib/usrp/common/ad9361_ctrl.hpp
@@ -0,0 +1,127 @@
+//
+// Copyright 2012-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_AD9361_CTRL_HPP
+#define INCLUDED_AD9361_CTRL_HPP
+
+#include <uhd/transport/zero_copy.hpp>
+#include <uhd/types/serial.hpp>
+#include <uhd/types/ranges.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include <boost/function.hpp>
+#include <vector>
+#include <string>
+
+
+struct ad9361_ctrl_iface_type
+{
+ virtual void ad9361_transact(const unsigned char in_buff[64], unsigned char out_buff[64]) = 0;
+};
+typedef boost::shared_ptr<ad9361_ctrl_iface_type> ad9361_ctrl_iface_sptr;
+
+
+struct ad9361_ctrl_over_zc : ad9361_ctrl_iface_type
+{
+ ad9361_ctrl_over_zc(uhd::transport::zero_copy_if::sptr xport)
+ {
+ _xport = xport;
+ }
+
+ void ad9361_transact(const unsigned char in_buff[64], unsigned char out_buff[64])
+ {
+ {
+ uhd::transport::managed_send_buffer::sptr buff = _xport->get_send_buff(10.0);
+ if (not buff or buff->size() < 64) throw std::runtime_error("ad9361_ctrl_over_zc send timeout");
+ std::memcpy(buff->cast<void *>(), in_buff, 64);
+ buff->commit(64);
+ }
+ {
+ uhd::transport::managed_recv_buffer::sptr buff = _xport->get_recv_buff(10.0);
+ if (not buff or buff->size() < 64) throw std::runtime_error("ad9361_ctrl_over_zc recv timeout");
+ std::memcpy(out_buff, buff->cast<const void *>(), 64);
+ }
+ }
+
+ uhd::transport::zero_copy_if::sptr _xport;
+};
+
+
+class ad9361_ctrl : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<ad9361_ctrl> sptr;
+
+ //! make a new codec control object
+ static sptr make(ad9361_ctrl_iface_sptr iface);
+
+ //! Get a list of gain names for RX or TX
+ static std::vector<std::string> get_gain_names(const std::string &/*which*/)
+ {
+ return std::vector<std::string>(1, "PGA");
+ }
+
+ //! get the gain range for a particular gain element
+ static uhd::meta_range_t get_gain_range(const std::string &which)
+ {
+ if(which[0] == 'R') {
+ return uhd::meta_range_t(0.0, 73.0, 1.0);
+ } else {
+ return uhd::meta_range_t(0.0, 89.75, 0.25);
+ }
+ }
+
+ //! get the freq range for the frontend which
+ static uhd::meta_range_t get_rf_freq_range(void)
+ {
+ return uhd::meta_range_t(30e6, 6e9);
+ }
+
+ //! get the filter range for the frontend which
+ static uhd::meta_range_t get_bw_filter_range(const std::string &/*which*/)
+ {
+ return uhd::meta_range_t(200e3, 56e6);
+ }
+
+ //! get the filter range for the frontend which
+ static uhd::meta_range_t get_samp_rate_range(void)
+ {
+ return uhd::meta_range_t(220e3, 61.44e6);
+ }
+
+ //! set the filter bandwidth for the frontend
+ double set_bw_filter(const std::string &/*which*/, const double /*bw*/)
+ {
+ return 56e6; //TODO
+ }
+
+ //! set the gain for a particular gain element
+ virtual double set_gain(const std::string &which, const double value) = 0;
+
+ //! set a new clock rate, return the exact value
+ virtual double set_clock_rate(const double rate) = 0;
+
+ //! set which RX and TX chains/antennas are active
+ virtual void set_active_chains(bool tx1, bool tx2, bool rx1, bool rx2) = 0;
+
+ //! tune the given frontend, return the exact value
+ virtual double tune(const std::string &which, const double value) = 0;
+
+ //! turn on/off Catalina's data port loopback
+ virtual void data_port_loopback(const bool on) = 0;
+};
+
+#endif /* INCLUDED_AD9361_CTRL_HPP */
diff --git a/host/lib/usrp/common/ad9361_transaction.h b/host/lib/usrp/common/ad9361_transaction.h
new file mode 100644
index 000000000..7b41b811f
--- /dev/null
+++ b/host/lib/usrp/common/ad9361_transaction.h
@@ -0,0 +1,102 @@
+//
+// Copyright 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_AD9361_TRANSACTION_H
+#define INCLUDED_AD9361_TRANSACTION_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//various constants
+#define AD9361_TRANSACTION_VERSION 0x4
+#define AD9361_TRANSACTION_MAX_ERROR_MSG 40
+
+//action types
+#define AD9361_ACTION_ECHO 0
+#define AD9361_ACTION_INIT 1
+#define AD9361_ACTION_SET_RX1_GAIN 2
+#define AD9361_ACTION_SET_TX1_GAIN 3
+#define AD9361_ACTION_SET_RX2_GAIN 4
+#define AD9361_ACTION_SET_TX2_GAIN 5
+#define AD9361_ACTION_SET_RX_FREQ 6
+#define AD9361_ACTION_SET_TX_FREQ 7
+#define AD9361_ACTION_SET_CODEC_LOOP 8
+#define AD9361_ACTION_SET_CLOCK_RATE 9
+#define AD9361_ACTION_SET_ACTIVE_CHAINS 10
+
+static inline void ad9361_double_pack(const double input, uint32_t output[2])
+{
+ const uint32_t *p = (const uint32_t *)&input;
+ output[0] = p[0];
+ output[1] = p[1];
+}
+
+static inline double ad9361_double_unpack(const uint32_t input[2])
+{
+ double output = 0.0;
+ uint32_t *p = (uint32_t *)&output;
+ p[0] = input[0];
+ p[1] = input[1];
+ return output;
+}
+
+typedef struct
+{
+ //version is expected to be AD9361_TRANSACTION_VERSION
+ //check otherwise for compatibility
+ uint32_t version;
+
+ //sequence number - increment every call for sanity
+ uint32_t sequence;
+
+ //action tells us what to do, see AD9361_ACTION_*
+ uint32_t action;
+
+ union
+ {
+ //enable mask for chains
+ uint32_t enable_mask;
+
+ //true to enable codec internal loopback
+ uint32_t codec_loop;
+
+ //freq holds request LO freq and result from tune
+ uint32_t freq[2];
+
+ //gain holds request gain and result from action
+ uint32_t gain[2];
+
+ //rate holds request clock rate and result from action
+ uint32_t rate[2];
+
+ } value;
+
+ //error message comes back as a reply -
+ //set to null string for no error \0
+ char error_msg[];
+
+} ad9361_transaction_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INCLUDED_AD9361_TRANSACTION_H */
diff --git a/host/lib/usrp/common/adf4001_ctrl.cpp b/host/lib/usrp/common/adf4001_ctrl.cpp
new file mode 100644
index 000000000..46171c7ce
--- /dev/null
+++ b/host/lib/usrp/common/adf4001_ctrl.cpp
@@ -0,0 +1,151 @@
+//
+// Copyright 2013 Ettus Research LLC
+//
+// Original ADF4001 driver written by: bistromath
+// Mar 1, 2013
+//
+// Re-used and re-licensed with permission.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "adf4001_ctrl.hpp"
+
+#include <uhd/utils/msg.hpp>
+#include <iostream>
+#include <iomanip>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+adf4001_regs_t::adf4001_regs_t(void) {
+ ref_counter = 0;
+ n = 0;
+ charge_pump_current_1 = 0;
+ charge_pump_current_2 = 0;
+ anti_backlash_width = ANTI_BACKLASH_WIDTH_2_9NS;
+ lock_detect_precision = LOCK_DETECT_PRECISION_3CYC;
+ charge_pump_gain = CHARGE_PUMP_GAIN_1;
+ counter_reset = COUNTER_RESET_NORMAL;
+ power_down = POWER_DOWN_NORMAL;
+ muxout = MUXOUT_TRISTATE_OUT;
+ phase_detector_polarity = PHASE_DETECTOR_POLARITY_NEGATIVE;
+ charge_pump_mode = CHARGE_PUMP_TRISTATE;
+ fastlock_mode = FASTLOCK_MODE_DISABLED;
+ timer_counter_control = TIMEOUT_3CYC;
+}
+
+
+boost::uint32_t adf4001_regs_t::get_reg(boost::uint8_t addr) {
+ boost::uint32_t reg = 0;
+ switch (addr) {
+ case 0:
+ reg |= (boost::uint32_t(ref_counter) & 0x003FFF) << 2;
+ reg |= (boost::uint32_t(anti_backlash_width) & 0x000003) << 16;
+ reg |= (boost::uint32_t(lock_detect_precision) & 0x000001) << 20;
+ break;
+ case 1:
+ reg |= (boost::uint32_t(n) & 0x001FFF) << 8;
+ reg |= (boost::uint32_t(charge_pump_gain) & 0x000001) << 21;
+ break;
+ case 2:
+ reg |= (boost::uint32_t(counter_reset) & 0x000001) << 2;
+ reg |= (boost::uint32_t(power_down) & 0x000001) << 3;
+ reg |= (boost::uint32_t(muxout) & 0x000007) << 4;
+ reg |= (boost::uint32_t(phase_detector_polarity) & 0x000001) << 7;
+ reg |= (boost::uint32_t(charge_pump_mode) & 0x000001) << 8;
+ reg |= (boost::uint32_t(fastlock_mode) & 0x000003) << 9;
+ reg |= (boost::uint32_t(timer_counter_control) & 0x00000F) << 11;
+ reg |= (boost::uint32_t(charge_pump_current_1) & 0x000007) << 15;
+ reg |= (boost::uint32_t(charge_pump_current_2) & 0x000007) << 18;
+ reg |= (boost::uint32_t(power_down) & 0x000002) << 21;
+ break;
+ case 3:
+ reg |= (boost::uint32_t(counter_reset) & 0x000001) << 2;
+ reg |= (boost::uint32_t(power_down) & 0x000001) << 3;
+ reg |= (boost::uint32_t(muxout) & 0x000007) << 4;
+ reg |= (boost::uint32_t(phase_detector_polarity) & 0x000001) << 7;
+ reg |= (boost::uint32_t(charge_pump_mode) & 0x000001) << 8;
+ reg |= (boost::uint32_t(fastlock_mode) & 0x000003) << 9;
+ reg |= (boost::uint32_t(timer_counter_control) & 0x00000F) << 11;
+ reg |= (boost::uint32_t(charge_pump_current_1) & 0x000007) << 15;
+ reg |= (boost::uint32_t(charge_pump_current_2) & 0x000007) << 18;
+ reg |= (boost::uint32_t(power_down) & 0x000002) << 21;
+ break;
+ default:
+ break;
+ }
+
+ reg |= (boost::uint32_t(addr) & 0x03);
+
+ return reg;
+}
+
+
+adf4001_ctrl::adf4001_ctrl(spi_core_3000::sptr _spi, int slaveno):
+ spi_iface(_spi),
+ slaveno(slaveno)
+ {
+
+ spi_config.mosi_edge = spi_config_t::EDGE_RISE;
+
+ //set defaults
+ adf4001_regs.ref_counter = 1;
+ adf4001_regs.n = 4;
+ adf4001_regs.charge_pump_current_1 = 7;
+ adf4001_regs.charge_pump_current_2 = 7;
+ adf4001_regs.muxout = adf4001_regs_t::MUXOUT_DLD;
+ adf4001_regs.counter_reset = adf4001_regs_t::COUNTER_RESET_NORMAL;
+ adf4001_regs.phase_detector_polarity = adf4001_regs_t::PHASE_DETECTOR_POLARITY_POSITIVE;
+ adf4001_regs.charge_pump_mode = adf4001_regs_t::CHARGE_PUMP_TRISTATE;
+
+ //everything else should be defaults
+
+ program_regs();
+}
+
+void adf4001_ctrl::set_lock_to_ext_ref(bool external) {
+ if(external) {
+ adf4001_regs.charge_pump_mode = adf4001_regs_t::CHARGE_PUMP_NORMAL;
+ } else {
+ adf4001_regs.charge_pump_mode = adf4001_regs_t::CHARGE_PUMP_TRISTATE;
+ }
+
+ program_regs();
+}
+
+void adf4001_ctrl::program_regs(void) {
+ //no control over CE, only LE, therefore we use the initialization latch method
+ write_reg(3);
+ boost::this_thread::sleep(boost::posix_time::microseconds(1));
+
+ //write R counter latch (0)
+ write_reg(0);
+ boost::this_thread::sleep(boost::posix_time::microseconds(1));
+
+ //write N counter latch (1)
+ write_reg(1);
+ boost::this_thread::sleep(boost::posix_time::microseconds(1));
+}
+
+
+void adf4001_ctrl::write_reg(boost::uint8_t addr) {
+ boost::uint32_t reg = adf4001_regs.get_reg(addr); //load the reg data
+
+ spi_iface->transact_spi(slaveno,
+ spi_config,
+ reg,
+ 24,
+ false);
+}
diff --git a/host/lib/usrp/common/adf4001_ctrl.hpp b/host/lib/usrp/common/adf4001_ctrl.hpp
new file mode 100644
index 000000000..a16cff3fa
--- /dev/null
+++ b/host/lib/usrp/common/adf4001_ctrl.hpp
@@ -0,0 +1,142 @@
+//
+// Copyright 2013 Ettus Research LLC
+//
+// Original ADF4001 driver written by: bistromath
+// Mar 1, 2013
+//
+// Re-used and re-licensed with permission.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_USRP_COMMON_ADF4001_HPP
+#define INCLUDED_LIBUHD_USRP_COMMON_ADF4001_HPP
+
+#include "spi_core_3000.hpp"
+#include <uhd/types/serial.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/thread/thread.hpp>
+
+namespace uhd { namespace usrp {
+
+class adf4001_regs_t {
+public:
+
+ /* Function prototypes */
+ boost::uint32_t get_reg(boost::uint8_t addr);
+ adf4001_regs_t(void);
+
+ /* Register values / addresses */
+ boost::uint16_t ref_counter; //14 bits
+ boost::uint16_t n; //13 bits
+ boost::uint8_t charge_pump_current_1; //3 bits
+ boost::uint8_t charge_pump_current_2; //3 bits
+
+ enum anti_backlash_width_t {
+ ANTI_BACKLASH_WIDTH_2_9NS = 0,
+ ANTI_BACKLASH_WIDTH_1_3NS = 1,
+ ANTI_BACKLASH_WIDTH_6_0NS = 2,
+ ANTI_BACKLASH_WIDTH_2_9NS_WAT = 3
+ };
+ anti_backlash_width_t anti_backlash_width;
+
+ enum lock_detect_precision_t {
+ LOCK_DETECT_PRECISION_3CYC = 0,
+ LOCK_DETECT_PRECISION_5CYC = 1
+ };
+ lock_detect_precision_t lock_detect_precision;
+ enum charge_pump_gain_t {
+ CHARGE_PUMP_GAIN_1 = 0,
+ CHARGE_PUMP_GAIN_2 = 1
+ };
+ charge_pump_gain_t charge_pump_gain;
+ enum counter_reset_t {
+ COUNTER_RESET_NORMAL = 0,
+ COUNTER_RESET_RESET = 1
+ };
+ counter_reset_t counter_reset;
+ enum power_down_t {
+ POWER_DOWN_NORMAL = 0,
+ POWER_DOWN_ASYNC = 1,
+ POWER_DOWN_SYNC = 3
+ };
+ power_down_t power_down;
+ enum muxout_t {
+ MUXOUT_TRISTATE_OUT = 0,
+ MUXOUT_DLD = 1,
+ MUXOUT_NDIV = 2,
+ MUXOUT_AVDD = 3,
+ MUXOUT_RDIV = 4,
+ MUXOUT_NCH_OD_ALD = 5,
+ MUXOUT_SDO = 6,
+ MUXOUT_GND = 7
+ };
+ muxout_t muxout;
+ enum phase_detector_polarity_t {
+ PHASE_DETECTOR_POLARITY_NEGATIVE = 0,
+ PHASE_DETECTOR_POLARITY_POSITIVE = 1
+ };
+ phase_detector_polarity_t phase_detector_polarity;
+ enum charge_pump_mode_t {
+ CHARGE_PUMP_NORMAL = 0,
+ CHARGE_PUMP_TRISTATE = 1
+ };
+ charge_pump_mode_t charge_pump_mode;
+ enum fastlock_mode_t {
+ FASTLOCK_MODE_DISABLED = 0,
+ FASTLOCK_MODE_1 = 1,
+ FASTLOCK_MODE_2 = 2
+ };
+ fastlock_mode_t fastlock_mode;
+ enum timer_counter_control_t {
+ TIMEOUT_3CYC = 0,
+ TIMEOUT_7CYC = 1,
+ TIMEOUT_11CYC = 2,
+ TIMEOUT_15CYC = 3,
+ TIMEOUT_19CYC = 4,
+ TIMEOUT_23CYC = 5,
+ TIMEOUT_27CYC = 6,
+ TIMEOUT_31CYC = 7,
+ TIMEOUT_35CYC = 8,
+ TIMEOUT_39CYC = 9,
+ TIMEOUT_43CYC = 10,
+ TIMEOUT_47CYC = 11,
+ TIMEOUT_51CYC = 12,
+ TIMEOUT_55CYC = 13,
+ TIMEOUT_59CYC = 14,
+ TIMEOUT_63CYC = 15,
+ };
+ timer_counter_control_t timer_counter_control;
+};
+
+
+class adf4001_ctrl {
+public:
+
+ adf4001_ctrl(spi_core_3000::sptr _spi, int slaveno);
+ void set_lock_to_ext_ref(bool external);
+
+private:
+ spi_core_3000::sptr spi_iface;
+ int slaveno;
+ spi_config_t spi_config;
+ adf4001_regs_t adf4001_regs;
+
+ void program_regs(void);
+ void write_reg(boost::uint8_t addr);
+};
+
+}}
+
+#endif
diff --git a/host/lib/usrp/common/recv_packet_demuxer_3000.hpp b/host/lib/usrp/common/recv_packet_demuxer_3000.hpp
index 9de3666dd..4fb6c4604 100644
--- a/host/lib/usrp/common/recv_packet_demuxer_3000.hpp
+++ b/host/lib/usrp/common/recv_packet_demuxer_3000.hpp
@@ -92,7 +92,10 @@ namespace uhd{ namespace usrp{
if (new_sid != sid)
{
boost::mutex::scoped_lock l(mutex);
- _queues[new_sid].push(buff);
+ if (_queues.count(new_sid) == 0) UHD_MSG(error)
+ << "recv packet demuxer unexpected sid 0x" << std::hex << new_sid << std::dec
+ << std::endl;
+ else _queues[new_sid].push(buff);
buff.reset();
}
}
@@ -102,6 +105,15 @@ namespace uhd{ namespace usrp{
return buff;
}
+ void realloc_sid(const boost::uint32_t sid)
+ {
+ boost::mutex::scoped_lock l(mutex);
+ while(not _queues[sid].empty()) //allocated and clears if already allocated
+ {
+ _queues[sid].pop();
+ }
+ }
+
typedef std::queue<transport::managed_recv_buffer::sptr> queue_type_t;
std::map<boost::uint32_t, queue_type_t> _queues;
transport::zero_copy_if::sptr _xport;