diff options
Diffstat (limited to 'host/lib/usrp/common/ad9361_ctrl.cpp')
-rw-r--r-- | host/lib/usrp/common/ad9361_ctrl.cpp | 204 |
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)); } |