diff options
Diffstat (limited to 'host/lib/usrp/common/ad9361_ctrl.cpp')
-rw-r--r-- | host/lib/usrp/common/ad9361_ctrl.cpp | 230 |
1 files changed, 121 insertions, 109 deletions
diff --git a/host/lib/usrp/common/ad9361_ctrl.cpp b/host/lib/usrp/common/ad9361_ctrl.cpp index 10496f2a9..dea18ff06 100644 --- a/host/lib/usrp/common/ad9361_ctrl.cpp +++ b/host/lib/usrp/common/ad9361_ctrl.cpp @@ -1,70 +1,105 @@ // -// 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/>. +// Copyright 2014 Ettus Research LLC // #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 <uhd/types/serial.hpp> #include <cstring> - -//! compat strnlen for platforms that dont have it -static size_t my_strnlen(const char *str, size_t max) -{ - const char *end = (const char *)std::memchr((const void *)str, 0, max); - if (end == NULL) return max; - return (size_t)(end - str); -} +#include <boost/format.hpp> +#include <boost/utility.hpp> +#include <boost/function.hpp> +#include <boost/make_shared.hpp> +#include <boost/thread.hpp> using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * AD9361 IO Implementation Classes + **********************************************************************/ -struct ad9361_ctrl_impl : public ad9361_ctrl +class ad9361_io_spi : public ad9361_io { - ad9361_ctrl_impl(ad9361_ctrl_iface_sptr iface): - _iface(iface), _seq(0) +public: + ad9361_io_spi(uhd::spi_iface::sptr spi_iface, boost::uint32_t slave_num) : + _spi_iface(spi_iface), _slave_num(slave_num) { } + + virtual ~ad9361_io_spi() { } + + virtual boost::uint8_t peek8(boost::uint32_t reg) { - ad9361_transaction_t request; + boost::lock_guard<boost::mutex> lock(_mutex); + + uhd::spi_config_t config; + config.mosi_edge = uhd::spi_config_t::EDGE_FALL; + config.miso_edge = uhd::spi_config_t::EDGE_FALL; //TODO (Ashish): FPGA SPI workaround. This should be EDGE_RISE - request.action = AD9361_ACTION_ECHO; - this->do_transaction(request); + boost::uint32_t rd_word = AD9361_SPI_READ_CMD | + ((boost::uint32_t(reg) << AD9361_SPI_ADDR_SHIFT) & AD9361_SPI_ADDR_MASK); - request.action = AD9361_ACTION_INIT; - this->do_transaction(request); + boost::uint32_t val = (_spi_iface->read_spi(_slave_num, config, rd_word, AD9361_SPI_NUM_BITS)); + val &= 0xFF; + + return static_cast<boost::uint8_t>(val); } - double set_gain(const std::string &which, const double value) + virtual void poke8(boost::uint32_t reg, boost::uint8_t val) + { + boost::lock_guard<boost::mutex> lock(_mutex); + + uhd::spi_config_t config; + config.mosi_edge = uhd::spi_config_t::EDGE_FALL; + config.miso_edge = uhd::spi_config_t::EDGE_FALL; //TODO (Ashish): FPGA SPI workaround. This should be EDGE_RISE + + boost::uint32_t wr_word = AD9361_SPI_WRITE_CMD | + ((boost::uint32_t(reg) << AD9361_SPI_ADDR_SHIFT) & AD9361_SPI_ADDR_MASK) | + ((boost::uint32_t(val) << AD9361_SPI_DATA_SHIFT) & AD9361_SPI_DATA_MASK); + _spi_iface->write_spi(_slave_num, config, wr_word, AD9361_SPI_NUM_BITS); + } + +private: + uhd::spi_iface::sptr _spi_iface; + boost::uint32_t _slave_num; + boost::mutex _mutex; + + static const boost::uint32_t AD9361_SPI_WRITE_CMD = 0x00800000; + static const boost::uint32_t AD9361_SPI_READ_CMD = 0x00000000; + static const boost::uint32_t AD9361_SPI_ADDR_MASK = 0x003FFF00; + static const boost::uint32_t AD9361_SPI_ADDR_SHIFT = 8; + static const boost::uint32_t AD9361_SPI_DATA_MASK = 0x000000FF; + static const boost::uint32_t AD9361_SPI_DATA_SHIFT = 0; + static const boost::uint32_t AD9361_SPI_NUM_BITS = 24; +}; + +/*********************************************************************** + * AD9361 Control API Class + **********************************************************************/ +class ad9361_ctrl_impl : public ad9361_ctrl +{ +public: + ad9361_ctrl_impl(ad9361_params::sptr client_settings, ad9361_io::sptr io_iface): + _device(client_settings, io_iface) { - ad9361_transaction_t request; + _device.initialize(); + } - 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; + double set_gain(const std::string &which, const double value) + { + boost::lock_guard<boost::mutex> lock(_mutex); - ad9361_double_pack(value, request.value.gain); - const ad9361_transaction_t reply = this->do_transaction(request); - return ad9361_double_unpack(reply.value.gain); + ad9361_device_t::direction_t direction = _get_direction_from_antenna(which); + ad9361_device_t::chain_t chain =_get_chain_from_antenna(which); + return _device.set_gain(direction, chain, value); } //! set a new clock rate, return the exact value double set_clock_rate(const double rate) { + boost::lock_guard<boost::mutex> lock(_mutex); + //warning for known trouble rates if (rate > 56e6) UHD_MSG(warning) << boost::format( "The requested clock rate %f MHz may cause slow configuration.\n" @@ -75,99 +110,76 @@ struct ad9361_ctrl_impl : public ad9361_ctrl const meta_range_t clock_rate_range = ad9361_ctrl::get_clock_rate_range(); 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); + return _device.set_clock_rate(clipped_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); + boost::lock_guard<boost::mutex> lock(_mutex); + + _device.set_active_chains(tx1, tx2, rx1, rx2); } //! tune the given frontend, return the exact value double tune(const std::string &which, const double freq) { + boost::lock_guard<boost::mutex> lock(_mutex); + //clip to known bounds const meta_range_t freq_range = ad9361_ctrl::get_rf_freq_range(); 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); + + ad9361_device_t::direction_t direction = _get_direction_from_antenna(which); + return _device.tune(direction, value); } //! 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); + boost::lock_guard<boost::mutex> lock(_mutex); + + _device.data_port_loopback(on); } - ad9361_transaction_t do_transaction(const ad9361_transaction_t &request) +private: + static ad9361_device_t::direction_t _get_direction_from_antenna(const std::string& antenna) { - 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 = my_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_ctrl::do_transaction] firmware reported: \"" + error_msg + "\""); - - //return result done! - return *out; + std::string sub = antenna.substr(0, 2); + if (sub == "RX") { + return ad9361_device_t::RX; + } else if (sub == "TX") { + return ad9361_device_t::TX; + } else { + throw uhd::runtime_error("ad9361_ctrl got an invalid channel string."); + } + return ad9361_device_t::RX; } - ad9361_ctrl_iface_sptr _iface; - size_t _seq; - boost::mutex _mutex; + static ad9361_device_t::chain_t _get_chain_from_antenna(const std::string& antenna) + { + std::string sub = antenna.substr(2, 1); + if (sub == "1") { + return ad9361_device_t::CHAIN_1; + } else if (sub == "2") { + return ad9361_device_t::CHAIN_2; + } else { + throw uhd::runtime_error("ad9361_ctrl::set_gain got an invalid channel string."); + } + return ad9361_device_t::CHAIN_1; + } + ad9361_device_t _device; + boost::mutex _mutex; }; - -/*********************************************************************** - * Make an instance of the implementation - **********************************************************************/ -ad9361_ctrl::sptr ad9361_ctrl::make(ad9361_ctrl_iface_sptr iface) +//---------------------------------------------------------------------- +// Make an instance of the AD9361 Control interface +//---------------------------------------------------------------------- +ad9361_ctrl::sptr ad9361_ctrl::make_spi( + ad9361_params::sptr client_settings, uhd::spi_iface::sptr spi_iface, boost::uint32_t slave_num) { - return sptr(new ad9361_ctrl_impl(iface)); + boost::shared_ptr<ad9361_io_spi> spi_io_iface = boost::make_shared<ad9361_io_spi>(spi_iface, slave_num); + return sptr(new ad9361_ctrl_impl(client_settings, spi_io_iface)); } |