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.cpp204
1 files changed, 171 insertions, 33 deletions
diff --git a/host/lib/usrp/common/ad9361_ctrl.cpp b/host/lib/usrp/common/ad9361_ctrl.cpp
index 10496f2a9..4cdfaa6e1 100644
--- a/host/lib/usrp/common/ad9361_ctrl.cpp
+++ b/host/lib/usrp/common/ad9361_ctrl.cpp
@@ -1,42 +1,169 @@
//
-// 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 "ad9361_dispatch.h"
+#include <ad9361_platform.h>
#include <uhd/exception.hpp>
#include <uhd/types/ranges.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/types/serial.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/format.hpp>
#include <cstring>
+#include <boost/utility.hpp>
+#include <boost/function.hpp>
+
+using namespace uhd;
+
+/***********************************************************************
+ * AD9361 IO Implementation Classes
+ **********************************************************************/
+
+class ad9361_io_spi : public ad9361_io
+{
+public:
+ ad9361_io_spi(uhd::spi_iface::sptr spi_iface, uint32_t slave_num) :
+ _spi_iface(spi_iface), _slave_num(slave_num) { }
+
+ uint8_t peek8(uint32_t reg)
+ {
+ 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
+
+ uint32_t rd_word = AD9361_SPI_READ_CMD |
+ ((uint32_t(reg) << AD9361_SPI_ADDR_SHIFT) & AD9361_SPI_ADDR_MASK);
+
+ uint32_t val = (_spi_iface->read_spi(_slave_num, config, rd_word, AD9361_SPI_NUM_BITS));
+ val &= 0xFF;
+
+ return static_cast<uint8_t>(val);
+ }
+
+ void poke8(uint32_t reg, uint8_t val)
+ {
+ 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
+
+ uint32_t wr_word = AD9361_SPI_WRITE_CMD |
+ ((uint32_t(reg) << AD9361_SPI_ADDR_SHIFT) & AD9361_SPI_ADDR_MASK) |
+ ((uint32_t(val) << AD9361_SPI_DATA_SHIFT) & AD9361_SPI_DATA_MASK);
+ _spi_iface->write_spi(_slave_num, config, wr_word, AD9361_SPI_NUM_BITS);
+
+ //TODO (Ashish): Is this necessary? The FX3 firmware does it right now but for
+ //networked devices, it makes writes blocking which will considerably slow down the programming
+ peek8(reg);
+ }
+private:
+ uhd::spi_iface::sptr _spi_iface;
+ uint32_t _slave_num;
+
+ static const uint32_t AD9361_SPI_WRITE_CMD = 0x00800000;
+ static const uint32_t AD9361_SPI_READ_CMD = 0x00000000;
+ static const uint32_t AD9361_SPI_ADDR_MASK = 0x003FFF00;
+ static const uint32_t AD9361_SPI_ADDR_SHIFT = 8;
+ static const uint32_t AD9361_SPI_DATA_MASK = 0x000000FF;
+ static const uint32_t AD9361_SPI_DATA_SHIFT = 0;
+ static const uint32_t AD9361_SPI_NUM_BITS = 24;
+};
+
+/***********************************************************************
+ * AD9361 Transport Implementation Classes
+ **********************************************************************/
+
+//----------------------------------------------------------------------
+//Over a zero-copy device transport
+//----------------------------------------------------------------------
+class ad9361_ctrl_transport_zc_impl : public ad9361_ctrl_transport
+{
+public:
+ ad9361_ctrl_transport_zc_impl(uhd::transport::zero_copy_if::sptr xport)
+ {
+ _xport = xport;
+ }
+
+ void ad9361_transact(const unsigned char in_buff[AD9361_DISPATCH_PACKET_SIZE], unsigned char out_buff[AD9361_DISPATCH_PACKET_SIZE])
+ {
+ {
+ uhd::transport::managed_send_buffer::sptr buff = _xport->get_send_buff(10.0);
+ if (not buff or buff->size() < AD9361_DISPATCH_PACKET_SIZE) throw std::runtime_error("ad9361_ctrl_over_zc send timeout");
+ std::memcpy(buff->cast<void *>(), in_buff, AD9361_DISPATCH_PACKET_SIZE);
+ buff->commit(AD9361_DISPATCH_PACKET_SIZE);
+ }
+ {
+ uhd::transport::managed_recv_buffer::sptr buff = _xport->get_recv_buff(10.0);
+ if (not buff or buff->size() < AD9361_DISPATCH_PACKET_SIZE) throw std::runtime_error("ad9361_ctrl_over_zc recv timeout");
+ std::memcpy(out_buff, buff->cast<const void *>(), AD9361_DISPATCH_PACKET_SIZE);
+ }
+ }
+
+ uint64_t get_device_handle()
+ {
+ return 0; //Unused for zero-copy transport because chip class is in FW
+ }
+
+private:
+ uhd::transport::zero_copy_if::sptr _xport;
+};
-//! compat strnlen for platforms that dont have it
-static size_t my_strnlen(const char *str, size_t max)
+//----------------------------------------------------------------------
+//Over a software transport
+//----------------------------------------------------------------------
+class ad9361_ctrl_transport_sw_spi_impl : public ad9361_ctrl_transport
{
- const char *end = (const char *)std::memchr((const void *)str, 0, max);
- if (end == NULL) return max;
- return (size_t)(end - str);
+public:
+ ad9361_ctrl_transport_sw_spi_impl(
+ ad9361_product_t product,
+ uhd::spi_iface::sptr spi_iface,
+ boost::uint32_t slave_num) :
+ _io_iface(spi_iface, slave_num)
+ {
+ _device.product = product;
+ _device.io_iface = reinterpret_cast<void*>(&_io_iface);
+ }
+
+ void ad9361_transact(const unsigned char in_buff[AD9361_DISPATCH_PACKET_SIZE], unsigned char out_buff[AD9361_DISPATCH_PACKET_SIZE])
+ {
+ ad9361_dispatch((const char*)in_buff, (char*)out_buff);
+ }
+
+ uint64_t get_device_handle()
+ {
+ return reinterpret_cast<uint64_t>(reinterpret_cast<void*>(&_device));
+ }
+
+private:
+ ad9361_device_t _device;
+ ad9361_io_spi _io_iface;
+};
+
+//----------------------------------------------------------------------
+// Make an instance of the AD9361 Transport
+//----------------------------------------------------------------------
+ad9361_ctrl_transport::sptr ad9361_ctrl_transport::make_zero_copy(uhd::transport::zero_copy_if::sptr xport)
+{
+ return sptr(new ad9361_ctrl_transport_zc_impl(xport));
}
-using namespace uhd;
+ad9361_ctrl_transport::sptr ad9361_ctrl_transport::make_software_spi(
+ ad9361_product_t product,
+ uhd::spi_iface::sptr spi_iface,
+ boost::uint32_t slave_num)
+{
+ return sptr(new ad9361_ctrl_transport_sw_spi_impl(product, spi_iface, slave_num));
+}
-struct ad9361_ctrl_impl : public ad9361_ctrl
+/***********************************************************************
+ * AD9361 Software API Class
+ **********************************************************************/
+class ad9361_ctrl_impl : public ad9361_ctrl
{
- ad9361_ctrl_impl(ad9361_ctrl_iface_sptr iface):
+public:
+ ad9361_ctrl_impl(ad9361_ctrl_transport::sptr iface):
_iface(iface), _seq(0)
{
ad9361_transaction_t request;
@@ -129,17 +256,21 @@ struct ad9361_ctrl_impl : public ad9361_ctrl
boost::mutex::scoped_lock lock(_mutex);
//declare in/out buffers
- unsigned char in_buff[64] = {};
- unsigned char out_buff[64] = {};
+ unsigned char in_buff[AD9361_DISPATCH_PACKET_SIZE] = {};
+ unsigned char out_buff[AD9361_DISPATCH_PACKET_SIZE] = {};
//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->handle = _iface->get_device_handle();
in->version = AD9361_TRANSACTION_VERSION;
in->sequence = _seq++;
+ //initialize error message to "no error"
+ std::memset(in->error_msg, 0, AD9361_TRANSACTION_MAX_ERROR_MSG);
+
//transact
_iface->ad9361_transact(in_buff, out_buff);
ad9361_transaction_t *out = (ad9361_transaction_t *)out_buff;
@@ -157,17 +288,24 @@ struct ad9361_ctrl_impl : public ad9361_ctrl
return *out;
}
- ad9361_ctrl_iface_sptr _iface;
- size_t _seq;
- boost::mutex _mutex;
+private:
+ //! 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);
+ }
+ ad9361_ctrl_transport::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)
+//----------------------------------------------------------------------
+// Make an instance of the AD9361 Control interface
+//----------------------------------------------------------------------
+ad9361_ctrl::sptr ad9361_ctrl::make(ad9361_ctrl_transport::sptr iface)
{
return sptr(new ad9361_ctrl_impl(iface));
}