aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/common/ad9361_ctrl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/common/ad9361_ctrl.cpp')
-rw-r--r--host/lib/usrp/common/ad9361_ctrl.cpp230
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));
}