aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/cores
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/cores')
-rw-r--r--host/lib/usrp/cores/CMakeLists.txt44
-rw-r--r--host/lib/usrp/cores/gpio_core_200.cpp138
-rw-r--r--host/lib/usrp/cores/gpio_core_200.hpp66
-rw-r--r--host/lib/usrp/cores/i2c_core_100.cpp140
-rw-r--r--host/lib/usrp/cores/i2c_core_100.hpp35
-rw-r--r--host/lib/usrp/cores/i2c_core_100_wb32.cpp152
-rw-r--r--host/lib/usrp/cores/i2c_core_100_wb32.hpp37
-rw-r--r--host/lib/usrp/cores/i2c_core_200.cpp158
-rw-r--r--host/lib/usrp/cores/i2c_core_200.hpp35
-rw-r--r--host/lib/usrp/cores/radio_ctrl_core_3000.cpp312
-rw-r--r--host/lib/usrp/cores/radio_ctrl_core_3000.hpp59
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.cpp280
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.hpp67
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_3000.cpp204
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_3000.hpp58
-rw-r--r--host/lib/usrp/cores/rx_frontend_core_200.cpp80
-rw-r--r--host/lib/usrp/cores/rx_frontend_core_200.hpp44
-rw-r--r--host/lib/usrp/cores/rx_vita_core_3000.cpp153
-rw-r--r--host/lib/usrp/cores/rx_vita_core_3000.hpp59
-rw-r--r--host/lib/usrp/cores/spi_core_100.cpp88
-rw-r--r--host/lib/usrp/cores/spi_core_100.hpp35
-rw-r--r--host/lib/usrp/cores/spi_core_3000.cpp96
-rw-r--r--host/lib/usrp/cores/spi_core_3000.hpp39
-rw-r--r--host/lib/usrp/cores/time64_core_200.cpp138
-rw-r--r--host/lib/usrp/cores/time64_core_200.hpp63
-rw-r--r--host/lib/usrp/cores/time_core_3000.cpp118
-rw-r--r--host/lib/usrp/cores/time_core_3000.hpp58
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_200.cpp226
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_200.hpp59
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_3000.cpp181
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_3000.hpp54
-rw-r--r--host/lib/usrp/cores/tx_frontend_core_200.cpp76
-rw-r--r--host/lib/usrp/cores/tx_frontend_core_200.hpp42
-rw-r--r--host/lib/usrp/cores/tx_vita_core_3000.cpp107
-rw-r--r--host/lib/usrp/cores/tx_vita_core_3000.hpp49
-rw-r--r--host/lib/usrp/cores/user_settings_core_200.cpp43
-rw-r--r--host/lib/usrp/cores/user_settings_core_200.hpp36
-rw-r--r--host/lib/usrp/cores/wb_iface.cpp51
-rw-r--r--host/lib/usrp/cores/wb_iface.hpp75
39 files changed, 3755 insertions, 0 deletions
diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt
new file mode 100644
index 000000000..f526319bc
--- /dev/null
+++ b/host/lib/usrp/cores/CMakeLists.txt
@@ -0,0 +1,44 @@
+#
+# 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
+# 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/>.
+#
+
+########################################################################
+# This file included, use CMake directory variables
+########################################################################
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/wb_iface.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/gpio_core_200.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/i2c_core_100.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/i2c_core_200.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/spi_core_100.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/time64_core_200.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/rx_dsp_core_200.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/tx_dsp_core_200.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/rx_frontend_core_200.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/tx_frontend_core_200.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/user_settings_core_200.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/rx_vita_core_3000.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/tx_vita_core_3000.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/time_core_3000.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/spi_core_3000.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/i2c_core_100_wb32.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/rx_dsp_core_3000.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/tx_dsp_core_3000.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/radio_ctrl_core_3000.cpp
+)
diff --git a/host/lib/usrp/cores/gpio_core_200.cpp b/host/lib/usrp/cores/gpio_core_200.cpp
new file mode 100644
index 000000000..51c23aa4b
--- /dev/null
+++ b/host/lib/usrp/cores/gpio_core_200.cpp
@@ -0,0 +1,138 @@
+//
+// Copyright 2011 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 "gpio_core_200.hpp"
+#include <uhd/types/dict.hpp>
+
+#define REG_GPIO_IDLE _base + 0
+#define REG_GPIO_RX_ONLY _base + 4
+#define REG_GPIO_TX_ONLY _base + 8
+#define REG_GPIO_BOTH _base + 12
+#define REG_GPIO_DDR _base + 16
+
+using namespace uhd;
+using namespace usrp;
+
+class gpio_core_200_impl : public gpio_core_200{
+public:
+ gpio_core_200_impl(wb_iface::sptr iface, const size_t base, const size_t rb_addr):
+ _iface(iface), _base(base), _rb_addr(rb_addr) { /* NOP */ }
+
+ void set_pin_ctrl(const unit_t unit, const boost::uint16_t value){
+ _pin_ctrl[unit] = value; //shadow
+ this->update(); //full update
+ }
+
+ void set_atr_reg(const unit_t unit, const atr_reg_t atr, const boost::uint16_t value){
+ _atr_regs[unit][atr] = value; //shadow
+ this->update(); //full update
+ }
+
+ void set_gpio_ddr(const unit_t unit, const boost::uint16_t value){
+ _gpio_ddr[unit] = value; //shadow
+ _iface->poke32(REG_GPIO_DDR, //update the 32 bit register
+ (boost::uint32_t(_gpio_ddr[dboard_iface::UNIT_RX]) << unit2shit(dboard_iface::UNIT_RX)) |
+ (boost::uint32_t(_gpio_ddr[dboard_iface::UNIT_TX]) << unit2shit(dboard_iface::UNIT_TX))
+ );
+ }
+
+ void set_gpio_out(const unit_t unit, const boost::uint16_t value){
+ _gpio_out[unit] = value; //shadow
+ this->update(); //full update
+ }
+
+ boost::uint16_t read_gpio(const unit_t unit){
+ return boost::uint16_t(_iface->peek32(_rb_addr) >> unit2shit(unit));
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _base;
+ const size_t _rb_addr;
+ uhd::dict<size_t, boost::uint32_t> _update_cache;
+
+ uhd::dict<unit_t, boost::uint16_t> _pin_ctrl, _gpio_out, _gpio_ddr;
+ uhd::dict<unit_t, uhd::dict<atr_reg_t, boost::uint16_t> > _atr_regs;
+
+ unsigned unit2shit(const unit_t unit){
+ return (unit == dboard_iface::UNIT_RX)? 0 : 16;
+ }
+
+ void update(void){
+ this->update(dboard_iface::ATR_REG_IDLE, REG_GPIO_IDLE);
+ this->update(dboard_iface::ATR_REG_TX_ONLY, REG_GPIO_TX_ONLY);
+ this->update(dboard_iface::ATR_REG_RX_ONLY, REG_GPIO_RX_ONLY);
+ this->update(dboard_iface::ATR_REG_FULL_DUPLEX, REG_GPIO_BOTH);
+ }
+
+ void update(const atr_reg_t atr, const size_t addr){
+ const boost::uint32_t atr_val =
+ (boost::uint32_t(_atr_regs[dboard_iface::UNIT_RX][atr]) << unit2shit(dboard_iface::UNIT_RX)) |
+ (boost::uint32_t(_atr_regs[dboard_iface::UNIT_TX][atr]) << unit2shit(dboard_iface::UNIT_TX));
+
+ const boost::uint32_t gpio_val =
+ (boost::uint32_t(_gpio_out[dboard_iface::UNIT_RX]) << unit2shit(dboard_iface::UNIT_RX)) |
+ (boost::uint32_t(_gpio_out[dboard_iface::UNIT_TX]) << unit2shit(dboard_iface::UNIT_TX));
+
+ const boost::uint32_t ctrl =
+ (boost::uint32_t(_pin_ctrl[dboard_iface::UNIT_RX]) << unit2shit(dboard_iface::UNIT_RX)) |
+ (boost::uint32_t(_pin_ctrl[dboard_iface::UNIT_TX]) << unit2shit(dboard_iface::UNIT_TX));
+ const boost::uint32_t val = (ctrl & atr_val) | ((~ctrl) & gpio_val);
+ if (not _update_cache.has_key(addr) or _update_cache[addr] != val)
+ {
+ _iface->poke32(addr, val);
+ }
+ _update_cache[addr] = val;
+ }
+
+};
+
+gpio_core_200::sptr gpio_core_200::make(wb_iface::sptr iface, const size_t base, const size_t rb_addr){
+ return sptr(new gpio_core_200_impl(iface, base, rb_addr));
+}
+
+class gpio_core_200_32wo_impl : public gpio_core_200_32wo{
+public:
+ gpio_core_200_32wo_impl(wb_iface::sptr iface, const size_t base):
+ _iface(iface), _base(base)
+ {
+ _iface->poke32(REG_GPIO_DDR, 0xffffffff);
+ }
+
+ void set_atr_reg(const atr_reg_t atr, const boost::uint32_t value){
+ if (atr == dboard_iface::ATR_REG_IDLE) _iface->poke32(REG_GPIO_IDLE, value);
+ if (atr == dboard_iface::ATR_REG_TX_ONLY) _iface->poke32(REG_GPIO_TX_ONLY, value);
+ if (atr == dboard_iface::ATR_REG_RX_ONLY) _iface->poke32(REG_GPIO_RX_ONLY, value);
+ if (atr == dboard_iface::ATR_REG_FULL_DUPLEX) _iface->poke32(REG_GPIO_BOTH, value);
+ }
+
+ void set_all_regs(const boost::uint32_t value){
+ this->set_atr_reg(dboard_iface::ATR_REG_IDLE, value);
+ this->set_atr_reg(dboard_iface::ATR_REG_TX_ONLY, value);
+ this->set_atr_reg(dboard_iface::ATR_REG_RX_ONLY, value);
+ this->set_atr_reg(dboard_iface::ATR_REG_FULL_DUPLEX, value);
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _base;
+
+};
+
+gpio_core_200_32wo::sptr gpio_core_200_32wo::make(wb_iface::sptr iface, const size_t base){
+ return sptr(new gpio_core_200_32wo_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/gpio_core_200.hpp b/host/lib/usrp/cores/gpio_core_200.hpp
new file mode 100644
index 000000000..a3edf5454
--- /dev/null
+++ b/host/lib/usrp/cores/gpio_core_200.hpp
@@ -0,0 +1,66 @@
+//
+// Copyright 2011 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_LIBUHD_USRP_GPIO_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_GPIO_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/usrp/dboard_iface.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class gpio_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<gpio_core_200> sptr;
+
+ typedef uhd::usrp::dboard_iface::unit_t unit_t;
+ typedef uhd::usrp::dboard_iface::atr_reg_t atr_reg_t;
+
+ //! makes a new GPIO core from iface and slave base
+ static sptr make(wb_iface::sptr iface, const size_t base, const size_t rb_addr);
+
+ //! 1 = ATR
+ virtual void set_pin_ctrl(const unit_t unit, const boost::uint16_t value) = 0;
+
+ virtual void set_atr_reg(const unit_t unit, const atr_reg_t atr, const boost::uint16_t value) = 0;
+
+ //! 1 = OUTPUT
+ virtual void set_gpio_ddr(const unit_t unit, const boost::uint16_t value) = 0;
+
+ virtual void set_gpio_out(const unit_t unit, const boost::uint16_t value) = 0;
+
+ virtual boost::uint16_t read_gpio(const unit_t unit) = 0;
+
+};
+
+//! Simple wrapper for 32 bit write only
+class gpio_core_200_32wo : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<gpio_core_200_32wo> sptr;
+
+ typedef uhd::usrp::dboard_iface::atr_reg_t atr_reg_t;
+
+ static sptr make(wb_iface::sptr iface, const size_t);
+
+ virtual void set_atr_reg(const atr_reg_t atr, const boost::uint32_t value) = 0;
+
+ virtual void set_all_regs(const boost::uint32_t value) = 0;
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_GPIO_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/i2c_core_100.cpp b/host/lib/usrp/cores/i2c_core_100.cpp
new file mode 100644
index 000000000..9e8a226f2
--- /dev/null
+++ b/host/lib/usrp/cores/i2c_core_100.cpp
@@ -0,0 +1,140 @@
+//
+// Copyright 2011 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 "i2c_core_100.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/thread/thread.hpp> //sleep
+
+#define REG_I2C_PRESCALER_LO _base + 0
+#define REG_I2C_PRESCALER_HI _base + 2
+#define REG_I2C_CTRL _base + 4
+#define REG_I2C_DATA _base + 6
+#define REG_I2C_CMD_STATUS _base + 8
+
+//
+// STA, STO, RD, WR, and IACK bits are cleared automatically
+//
+
+#define I2C_CTRL_EN (1 << 7) // core enable
+#define I2C_CTRL_IE (1 << 6) // interrupt enable
+
+#define I2C_CMD_START (1 << 7) // generate (repeated) start condition
+#define I2C_CMD_STOP (1 << 6) // generate stop condition
+#define I2C_CMD_RD (1 << 5) // read from slave
+#define I2C_CMD_WR (1 << 4) // write to slave
+#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1)
+#define I2C_CMD_RSVD_2 (1 << 2) // reserved
+#define I2C_CMD_RSVD_1 (1 << 1) // reserved
+#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt
+
+#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK)
+#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected
+#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration
+#define I2C_ST_RSVD_4 (1 << 4) // reserved
+#define I2C_ST_RSVD_3 (1 << 3) // reserved
+#define I2C_ST_RSVD_2 (1 << 2) // reserved
+#define I2C_ST_TIP (1 << 1) // Transfer-in-progress
+#define I2C_ST_IP (1 << 0) // Interrupt pending
+
+using namespace uhd;
+
+class i2c_core_100_impl : public i2c_core_100{
+public:
+ i2c_core_100_impl(wb_iface::sptr iface, const size_t base):
+ _iface(iface), _base(base)
+ {
+ //init I2C FPGA interface.
+ _iface->poke16(REG_I2C_CTRL, 0x0000);
+ //set prescalers to operate at 400kHz: WB_CLK is 64MHz...
+ static const boost::uint32_t i2c_datarate = 400000;
+ static const boost::uint32_t wishbone_clk = 64000000; //FIXME should go somewhere else
+ boost::uint16_t prescaler = wishbone_clk / (i2c_datarate*5) - 1;
+ _iface->poke16(REG_I2C_PRESCALER_LO, prescaler & 0xFF);
+ _iface->poke16(REG_I2C_PRESCALER_HI, (prescaler >> 8) & 0xFF);
+ _iface->poke16(REG_I2C_CTRL, I2C_CTRL_EN); //enable I2C core
+ }
+
+ void write_i2c(
+ boost::uint16_t addr,
+ const byte_vector_t &bytes
+ ){
+ _iface->poke16(REG_I2C_DATA, (addr << 1) | 0); //addr and read bit (0)
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START | (bytes.size() == 0 ? I2C_CMD_STOP : 0));
+
+ //wait for previous transfer to complete
+ if (not wait_chk_ack()) {
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_STOP);
+ return;
+ }
+
+ for (size_t i = 0; i < bytes.size(); i++) {
+ _iface->poke16(REG_I2C_DATA, bytes[i]);
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_WR | ((i == (bytes.size() - 1)) ? I2C_CMD_STOP : 0));
+ if(!wait_chk_ack()) {
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_STOP);
+ return;
+ }
+ }
+ }
+
+ byte_vector_t read_i2c(
+ boost::uint16_t addr,
+ size_t num_bytes
+ ){
+ byte_vector_t bytes;
+ if (num_bytes == 0) return bytes;
+
+ while (_iface->peek16(REG_I2C_CMD_STATUS) & I2C_ST_BUSY){
+ /* NOP */
+ }
+
+ _iface->poke16(REG_I2C_DATA, (addr << 1) | 1); //addr and read bit (1)
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START);
+ //wait for previous transfer to complete
+ if (not wait_chk_ack()) {
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_STOP);
+ }
+ for (size_t i = 0; i < num_bytes; i++) {
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_RD | ((num_bytes == i+1) ? (I2C_CMD_STOP | I2C_CMD_NACK) : 0));
+ i2c_wait();
+ bytes.push_back(boost::uint8_t(_iface->peek16(REG_I2C_DATA)));
+ }
+ return bytes;
+ }
+
+private:
+ void i2c_wait(void) {
+ for (size_t i = 0; i < 100; i++){
+ if ((_iface->peek16(REG_I2C_CMD_STATUS) & I2C_ST_TIP) == 0) return;
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ }
+ UHD_MSG(error) << "i2c_core_100: i2c_wait timeout" << std::endl;
+ }
+
+ bool wait_chk_ack(void){
+ i2c_wait();
+ return (_iface->peek16(REG_I2C_CMD_STATUS) & I2C_ST_RXACK) == 0;
+ }
+
+ wb_iface::sptr _iface;
+ const size_t _base;
+};
+
+i2c_core_100::sptr i2c_core_100::make(wb_iface::sptr iface, const size_t base){
+ return sptr(new i2c_core_100_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/i2c_core_100.hpp b/host/lib/usrp/cores/i2c_core_100.hpp
new file mode 100644
index 000000000..f7a5ae4f7
--- /dev/null
+++ b/host/lib/usrp/cores/i2c_core_100.hpp
@@ -0,0 +1,35 @@
+//
+// Copyright 2011 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_LIBUHD_USRP_I2C_CORE_100_HPP
+#define INCLUDED_LIBUHD_USRP_I2C_CORE_100_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/serial.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class i2c_core_100 : boost::noncopyable, public uhd::i2c_iface{
+public:
+ typedef boost::shared_ptr<i2c_core_100> sptr;
+
+ //! makes a new i2c core from iface and slave base
+ static sptr make(wb_iface::sptr iface, const size_t base);
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_I2C_CORE_100_HPP */
diff --git a/host/lib/usrp/cores/i2c_core_100_wb32.cpp b/host/lib/usrp/cores/i2c_core_100_wb32.cpp
new file mode 100644
index 000000000..df6e6ff72
--- /dev/null
+++ b/host/lib/usrp/cores/i2c_core_100_wb32.cpp
@@ -0,0 +1,152 @@
+//
+// 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
+// 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 "i2c_core_100_wb32.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/thread/thread.hpp> //sleep
+
+#define REG_I2C_PRESCALER_LO _base + 0
+#define REG_I2C_PRESCALER_HI _base + 4
+#define REG_I2C_CTRL _base + 8
+#define REG_I2C_DATA _base + 12
+#define REG_I2C_CMD_STATUS _base + 16
+
+//
+// STA, STO, RD, WR, and IACK bits are cleared automatically
+//
+
+#define I2C_CTRL_EN (1 << 7) // core enable
+#define I2C_CTRL_IE (1 << 6) // interrupt enable
+
+#define I2C_CMD_START (1 << 7) // generate (repeated) start condition
+#define I2C_CMD_STOP (1 << 6) // generate stop condition
+#define I2C_CMD_RD (1 << 5) // read from slave
+#define I2C_CMD_WR (1 << 4) // write to slave
+#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1)
+#define I2C_CMD_RSVD_2 (1 << 2) // reserved
+#define I2C_CMD_RSVD_1 (1 << 1) // reserved
+#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt
+
+#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK)
+#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected
+#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration
+#define I2C_ST_RSVD_4 (1 << 4) // reserved
+#define I2C_ST_RSVD_3 (1 << 3) // reserved
+#define I2C_ST_RSVD_2 (1 << 2) // reserved
+#define I2C_ST_TIP (1 << 1) // Transfer-in-progress
+#define I2C_ST_IP (1 << 0) // Interrupt pending
+
+using namespace uhd;
+
+class i2c_core_100_wb32_wb32_impl : public i2c_core_100_wb32{
+public:
+ i2c_core_100_wb32_wb32_impl(wb_iface::sptr iface, const size_t base):
+ _iface(iface), _base(base)
+ {
+ //init I2C FPGA interface.
+ _iface->poke32(REG_I2C_CTRL, 0x0000);
+ _iface->poke32(REG_I2C_CTRL, I2C_CTRL_EN); //enable I2C core
+ }
+
+ void set_clock_rate(const double rate)
+ {
+ static const boost::uint32_t i2c_datarate = 400000;
+ boost::uint16_t prescaler = rate / (i2c_datarate*5) - 1;
+ _iface->poke32(REG_I2C_PRESCALER_LO, prescaler & 0xFF);
+ _iface->poke32(REG_I2C_PRESCALER_HI, (prescaler >> 8) & 0xFF);
+ }
+
+ void write_i2c(
+ boost::uint16_t addr,
+ const byte_vector_t &bytes
+ ){
+ _iface->poke32(REG_I2C_DATA, (addr << 1) | 0); //addr and read bit (0)
+ _iface->poke32(REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START | (bytes.size() == 0 ? I2C_CMD_STOP : 0));
+
+ //wait for previous transfer to complete
+ if (not wait_chk_ack()) {
+ _iface->poke32(REG_I2C_CMD_STATUS, I2C_CMD_STOP);
+ return;
+ }
+
+ for (size_t i = 0; i < bytes.size(); i++) {
+ _iface->poke32(REG_I2C_DATA, bytes[i]);
+ _iface->poke32(REG_I2C_CMD_STATUS, I2C_CMD_WR | ((i == (bytes.size() - 1)) ? I2C_CMD_STOP : 0));
+ if(!wait_chk_ack()) {
+ _iface->poke32(REG_I2C_CMD_STATUS, I2C_CMD_STOP);
+ return;
+ }
+ }
+ }
+
+ byte_vector_t read_i2c(
+ boost::uint16_t addr,
+ size_t num_bytes
+ ){
+ byte_vector_t bytes;
+ if (num_bytes == 0) return bytes;
+
+ while (_iface->peek32(REG_I2C_CMD_STATUS) & I2C_ST_BUSY){
+ /* NOP */
+ }
+
+ _iface->poke32(REG_I2C_DATA, (addr << 1) | 1); //addr and read bit (1)
+ _iface->poke32(REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START);
+ //wait for previous transfer to complete
+ if (not wait_chk_ack()) {
+ _iface->poke32(REG_I2C_CMD_STATUS, I2C_CMD_STOP);
+ }
+ for (size_t i = 0; i < num_bytes; i++) {
+ _iface->poke32(REG_I2C_CMD_STATUS, I2C_CMD_RD | ((num_bytes == i+1) ? (I2C_CMD_STOP | I2C_CMD_NACK) : 0));
+ i2c_wait();
+ bytes.push_back(boost::uint8_t(_iface->peek32(REG_I2C_DATA)));
+ }
+ return bytes;
+ }
+
+ //override read_eeprom so we can write once, read all N bytes
+ //the default implementation calls read i2c once per byte
+ byte_vector_t read_eeprom(boost::uint16_t addr, boost::uint16_t offset, size_t num_bytes)
+ {
+ this->write_i2c(addr, byte_vector_t(1, offset));
+ return this->read_i2c(addr, num_bytes);
+ }
+
+private:
+ void i2c_wait(void) {
+ for (size_t i = 0; i < 10; i++)
+ {
+ if ((_iface->peek32(REG_I2C_CMD_STATUS) & I2C_ST_TIP) == 0) return;
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ }
+ UHD_MSG(error) << "i2c_core_100_wb32: i2c_wait timeout" << std::endl;
+ }
+
+ bool wait_chk_ack(void){
+ i2c_wait();
+ return (_iface->peek32(REG_I2C_CMD_STATUS) & I2C_ST_RXACK) == 0;
+ }
+
+ wb_iface::sptr _iface;
+ const size_t _base;
+};
+
+i2c_core_100_wb32::sptr i2c_core_100_wb32::make(wb_iface::sptr iface, const size_t base)
+{
+ return sptr(new i2c_core_100_wb32_wb32_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/i2c_core_100_wb32.hpp b/host/lib/usrp/cores/i2c_core_100_wb32.hpp
new file mode 100644
index 000000000..f2ac98292
--- /dev/null
+++ b/host/lib/usrp/cores/i2c_core_100_wb32.hpp
@@ -0,0 +1,37 @@
+//
+// 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
+// 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_I2C_CORE_100_WB32_HPP
+#define INCLUDED_LIBUHD_USRP_I2C_CORE_100_WB32_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/serial.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class i2c_core_100_wb32 : boost::noncopyable, public uhd::i2c_iface{
+public:
+ typedef boost::shared_ptr<i2c_core_100_wb32> sptr;
+
+ //! makes a new i2c core from iface and slave base
+ static sptr make(wb_iface::sptr iface, const size_t base);
+
+ virtual void set_clock_rate(const double rate) = 0;
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_I2C_CORE_100_WB32_HPP */
diff --git a/host/lib/usrp/cores/i2c_core_200.cpp b/host/lib/usrp/cores/i2c_core_200.cpp
new file mode 100644
index 000000000..6010ac5a2
--- /dev/null
+++ b/host/lib/usrp/cores/i2c_core_200.cpp
@@ -0,0 +1,158 @@
+//
+// Copyright 2011-2012 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 "i2c_core_200.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/thread/thread.hpp> //sleep
+#include <boost/thread/mutex.hpp>
+
+#define REG_I2C_WR_PRESCALER_LO (1 << 3) | 0
+#define REG_I2C_WR_PRESCALER_HI (1 << 3) | 1
+#define REG_I2C_WR_CTRL (1 << 3) | 2
+#define REG_I2C_WR_DATA (1 << 3) | 3
+#define REG_I2C_WR_CMD (1 << 3) | 4
+#define REG_I2C_RD_DATA (0 << 3) | 3
+#define REG_I2C_RD_ST (0 << 3) | 4
+
+//
+// STA, STO, RD, WR, and IACK bits are cleared automatically
+//
+
+#define I2C_CTRL_EN (1 << 7) // core enable
+#define I2C_CTRL_IE (1 << 6) // interrupt enable
+
+#define I2C_CMD_START (1 << 7) // generate (repeated) start condition
+#define I2C_CMD_STOP (1 << 6) // generate stop condition
+#define I2C_CMD_RD (1 << 5) // read from slave
+#define I2C_CMD_WR (1 << 4) // write to slave
+#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1)
+#define I2C_CMD_RSVD_2 (1 << 2) // reserved
+#define I2C_CMD_RSVD_1 (1 << 1) // reserved
+#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt
+
+#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK)
+#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected
+#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration
+#define I2C_ST_RSVD_4 (1 << 4) // reserved
+#define I2C_ST_RSVD_3 (1 << 3) // reserved
+#define I2C_ST_RSVD_2 (1 << 2) // reserved
+#define I2C_ST_TIP (1 << 1) // Transfer-in-progress
+#define I2C_ST_IP (1 << 0) // Interrupt pending
+
+using namespace uhd;
+
+class i2c_core_200_impl : public i2c_core_200{
+public:
+ i2c_core_200_impl(wb_iface::sptr iface, const size_t base, const size_t readback):
+ _iface(iface), _base(base), _readback(readback)
+ {
+ //init I2C FPGA interface.
+ this->poke(REG_I2C_WR_CTRL, 0x0000);
+ //set prescalers to operate at 400kHz: WB_CLK is 64MHz...
+ static const boost::uint32_t i2c_datarate = 400000;
+ static const boost::uint32_t wishbone_clk = 64000000; //FIXME should go somewhere else
+ boost::uint16_t prescaler = wishbone_clk / (i2c_datarate*5) - 1;
+ this->poke(REG_I2C_WR_PRESCALER_LO, prescaler & 0xFF);
+ this->poke(REG_I2C_WR_PRESCALER_HI, (prescaler >> 8) & 0xFF);
+ this->poke(REG_I2C_WR_CTRL, I2C_CTRL_EN); //enable I2C core
+ }
+
+ void write_i2c(
+ boost::uint16_t addr,
+ const byte_vector_t &bytes
+ ){
+ this->poke(REG_I2C_WR_DATA, (addr << 1) | 0); //addr and read bit (0)
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_WR | I2C_CMD_START | (bytes.size() == 0 ? I2C_CMD_STOP : 0));
+
+ //wait for previous transfer to complete
+ if (not wait_chk_ack()) {
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_STOP);
+ return;
+ }
+
+ for (size_t i = 0; i < bytes.size(); i++) {
+ this->poke(REG_I2C_WR_DATA, bytes[i]);
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_WR | ((i == (bytes.size() - 1)) ? I2C_CMD_STOP : 0));
+ if(!wait_chk_ack()) {
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_STOP);
+ return;
+ }
+ }
+ }
+
+ byte_vector_t read_i2c(
+ boost::uint16_t addr,
+ size_t num_bytes
+ ){
+ byte_vector_t bytes;
+ if (num_bytes == 0) return bytes;
+
+ while (this->peek(REG_I2C_RD_ST) & I2C_ST_BUSY){
+ /* NOP */
+ }
+
+ this->poke(REG_I2C_WR_DATA, (addr << 1) | 1); //addr and read bit (1)
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_WR | I2C_CMD_START);
+ //wait for previous transfer to complete
+ if (not wait_chk_ack()) {
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_STOP);
+ }
+ for (size_t i = 0; i < num_bytes; i++) {
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_RD | ((num_bytes == i+1) ? (I2C_CMD_STOP | I2C_CMD_NACK) : 0));
+ i2c_wait();
+ bytes.push_back(this->peek(REG_I2C_RD_DATA));
+ }
+ return bytes;
+ }
+
+private:
+ void i2c_wait(void) {
+ for (size_t i = 0; i < 100; i++){
+ if ((this->peek(REG_I2C_RD_ST) & I2C_ST_TIP) == 0) return;
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ }
+ UHD_MSG(error) << "i2c_core_200: i2c_wait timeout" << std::endl;
+ }
+
+ bool wait_chk_ack(void){
+ i2c_wait();
+ return (this->peek(REG_I2C_RD_ST) & I2C_ST_RXACK) == 0;
+ }
+
+ void poke(const size_t what, const boost::uint8_t cmd)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ _iface->poke32(_base, (what << 8) | cmd);
+ }
+
+ boost::uint8_t peek(const size_t what)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ _iface->poke32(_base, what << 8);
+ return boost::uint8_t(_iface->peek32(_readback));
+ }
+
+ wb_iface::sptr _iface;
+ const size_t _base;
+ const size_t _readback;
+ boost::mutex _mutex;
+};
+
+i2c_core_200::sptr i2c_core_200::make(wb_iface::sptr iface, const size_t base, const size_t readback){
+ return sptr(new i2c_core_200_impl(iface, base, readback));
+}
diff --git a/host/lib/usrp/cores/i2c_core_200.hpp b/host/lib/usrp/cores/i2c_core_200.hpp
new file mode 100644
index 000000000..508855985
--- /dev/null
+++ b/host/lib/usrp/cores/i2c_core_200.hpp
@@ -0,0 +1,35 @@
+//
+// Copyright 2011-2012 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_LIBUHD_USRP_I2C_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_I2C_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/serial.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class i2c_core_200 : boost::noncopyable, public uhd::i2c_iface{
+public:
+ typedef boost::shared_ptr<i2c_core_200> sptr;
+
+ //! makes a new i2c core from iface and slave base
+ static sptr make(wb_iface::sptr iface, const size_t base, const size_t readback);
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_I2C_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/radio_ctrl_core_3000.cpp b/host/lib/usrp/cores/radio_ctrl_core_3000.cpp
new file mode 100644
index 000000000..616903920
--- /dev/null
+++ b/host/lib/usrp/cores/radio_ctrl_core_3000.cpp
@@ -0,0 +1,312 @@
+//
+// 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 "radio_ctrl_core_3000.hpp"
+#include "async_packet_handler.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <uhd/utils/safe_call.hpp>
+#include <uhd/transport/bounded_buffer.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/format.hpp>
+#include <boost/bind.hpp>
+#include <queue>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace uhd::transport;
+
+static const double ACK_TIMEOUT = 0.5;
+static const double MASSIVE_TIMEOUT = 10.0; //for when we wait on a timed command
+static const size_t SR_READBACK = 32;
+
+class radio_ctrl_core_3000_impl : public radio_ctrl_core_3000
+{
+public:
+
+ radio_ctrl_core_3000_impl(
+ vrt::if_packet_info_t::link_type_t link_type,
+ uhd::transport::zero_copy_if::sptr ctrl_xport,
+ uhd::transport::zero_copy_if::sptr resp_xport,
+ const boost::uint32_t sid,
+ const std::string &name
+ ):
+ _link_type(link_type),
+ _packet_type(vrt::if_packet_info_t::PACKET_TYPE_CONTEXT),
+ _bige(link_type == vrt::if_packet_info_t::LINK_TYPE_VRLP),
+ _ctrl_xport(ctrl_xport),
+ _resp_xport(resp_xport),
+ _sid(sid),
+ _name(name),
+ _seq_out(0),
+ _timeout(ACK_TIMEOUT),
+ _resp_queue(128/*max response msgs*/),
+ _resp_queue_size(_resp_xport? _resp_xport->get_num_recv_frames() : 3)
+ {
+ UHD_LOG << "radio_ctrl_core_3000_impl() " << _name << std::endl;
+ if (resp_xport)
+ {
+ while (resp_xport->get_recv_buff(0.0)){} //flush
+ }
+ this->set_time(uhd::time_spec_t(0.0));
+ this->set_tick_rate(1.0); //something possible but bogus
+ }
+
+ ~radio_ctrl_core_3000_impl(void)
+ {
+ UHD_LOG << "~radio_ctrl_core_3000_impl() " << _name << std::endl;
+ _timeout = ACK_TIMEOUT; //reset timeout to something small
+ UHD_SAFE_CALL(
+ this->peek32(0); //dummy peek with the purpose of ack'ing all packets
+ _async_task.reset(); //now its ok to release the task
+ )
+ }
+
+ /*******************************************************************
+ * Peek and poke 32 bit implementation
+ ******************************************************************/
+ void poke32(const wb_addr_type addr, const boost::uint32_t data)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ UHD_LOGV(always) << _name << std::hex << " addr 0x" << addr << " data 0x" << data << std::dec << std::endl;
+
+ this->send_pkt(addr/4, data);
+ this->wait_for_ack(false);
+ }
+
+ boost::uint32_t peek32(const wb_addr_type addr)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ UHD_LOGV(always) << _name << std::hex << " addr 0x" << addr << std::dec << std::endl;
+
+ this->send_pkt(SR_READBACK, addr/8);
+ this->wait_for_ack(false);
+
+ this->send_pkt(0);
+ const boost::uint64_t res = this->wait_for_ack(true);
+ const boost::uint32_t lo = boost::uint32_t(res & 0xffffffff);
+ const boost::uint32_t hi = boost::uint32_t(res >> 32);
+ return ((addr/4) & 0x1)? hi : lo;
+ }
+
+ boost::uint64_t peek64(const wb_addr_type addr)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ UHD_LOGV(always) << _name << std::hex << " addr 0x" << addr << std::dec << std::endl;
+
+ this->send_pkt(SR_READBACK, addr/8);
+ this->wait_for_ack(false);
+
+ this->send_pkt(0);
+ return this->wait_for_ack(true);
+ }
+
+ /*******************************************************************
+ * Update methods for time
+ ******************************************************************/
+ void set_time(const uhd::time_spec_t &time)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ _time = time;
+ _use_time = _time != uhd::time_spec_t(0.0);
+ if (_use_time) _timeout = MASSIVE_TIMEOUT; //permanently sets larger timeout
+ }
+
+ void set_tick_rate(const double rate)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ _tick_rate = rate;
+ }
+
+private:
+
+ /*******************************************************************
+ * Primary control and interaction private methods
+ ******************************************************************/
+ UHD_INLINE void send_pkt(const boost::uint32_t addr, const boost::uint32_t data = 0)
+ {
+ managed_send_buffer::sptr buff = _ctrl_xport->get_send_buff(0.0);
+ if (not buff){
+ throw uhd::runtime_error("fifo ctrl timed out getting a send buffer");
+ }
+ boost::uint32_t *pkt = buff->cast<boost::uint32_t *>();
+
+ //load packet info
+ vrt::if_packet_info_t packet_info;
+ packet_info.link_type = _link_type;
+ packet_info.packet_type = _packet_type;
+ packet_info.num_payload_words32 = 2;
+ packet_info.num_payload_bytes = packet_info.num_payload_words32*sizeof(boost::uint32_t);
+ packet_info.packet_count = _seq_out;
+ packet_info.tsf = _time.to_ticks(_tick_rate);
+ packet_info.sob = false;
+ packet_info.eob = false;
+ packet_info.sid = _sid;
+ packet_info.has_sid = true;
+ packet_info.has_cid = false;
+ packet_info.has_tsi = false;
+ packet_info.has_tsf = _use_time;
+ packet_info.has_tlr = false;
+
+ //load header
+ if (_bige) vrt::if_hdr_pack_be(pkt, packet_info);
+ else vrt::if_hdr_pack_le(pkt, packet_info);
+
+ //load payload
+ pkt[packet_info.num_header_words32+0] = (_bige)? uhd::htonx(addr) : uhd::htowx(addr);
+ pkt[packet_info.num_header_words32+1] = (_bige)? uhd::htonx(data) : uhd::htowx(data);
+ //UHD_MSG(status) << boost::format("0x%08x, 0x%08x\n") % addr % data;
+
+ //send the buffer over the interface
+ _outstanding_seqs.push(_seq_out);
+ buff->commit(sizeof(boost::uint32_t)*(packet_info.num_packet_words32));
+
+ _seq_out++; //inc seq for next call
+ }
+
+ UHD_INLINE boost::uint64_t wait_for_ack(const bool readback)
+ {
+ while (readback or (_outstanding_seqs.size() >= _resp_queue_size))
+ {
+ UHD_LOGV(always) << _name << " wait_for_ack: " << "readback = " << readback << " outstanding_seqs.size() " << _outstanding_seqs.size() << std::endl;
+
+ //get seq to ack from outstanding packets list
+ UHD_ASSERT_THROW(not _outstanding_seqs.empty());
+ const size_t seq_to_ack = _outstanding_seqs.front();
+ _outstanding_seqs.pop();
+
+ //parse the packet
+ vrt::if_packet_info_t packet_info;
+ resp_buff_type resp_buff;
+ boost::uint32_t const *pkt = NULL;
+ managed_recv_buffer::sptr buff;
+
+ //get buffer from response endpoint - or die in timeout
+ if (_resp_xport)
+ {
+ buff = _resp_xport->get_recv_buff(_timeout);
+ try
+ {
+ UHD_ASSERT_THROW(bool(buff));
+ UHD_ASSERT_THROW(bool(buff->size()));
+ }
+ catch(const std::exception &ex)
+ {
+ throw uhd::io_error(str(boost::format("Radio ctrl (%s) no response packet - %s") % _name % ex.what()));
+ }
+ pkt = buff->cast<const boost::uint32_t *>();
+ packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t);
+ }
+
+ //get buffer from response endpoint - or die in timeout
+ else
+ {
+ UHD_ASSERT_THROW(_resp_queue.pop_with_timed_wait(resp_buff, _timeout));
+ pkt = resp_buff.data;
+ packet_info.num_packet_words32 = sizeof(resp_buff)/sizeof(boost::uint32_t);
+ }
+
+ //parse the buffer
+ try
+ {
+ packet_info.link_type = _link_type;
+ if (_bige) vrt::if_hdr_unpack_be(pkt, packet_info);
+ else vrt::if_hdr_unpack_le(pkt, packet_info);
+ }
+ catch(const std::exception &ex)
+ {
+ UHD_MSG(error) << "Radio ctrl bad VITA packet: " << ex.what() << std::endl;
+ UHD_VAR(buff->size());
+ UHD_MSG(status) << std::hex << pkt[0] << std::dec << std::endl;
+ UHD_MSG(status) << std::hex << pkt[1] << std::dec << std::endl;
+ UHD_MSG(status) << std::hex << pkt[2] << std::dec << std::endl;
+ UHD_MSG(status) << std::hex << pkt[3] << std::dec << std::endl;
+ }
+
+ //check the buffer
+ try
+ {
+ UHD_ASSERT_THROW(packet_info.has_sid);
+ UHD_ASSERT_THROW(packet_info.sid == boost::uint32_t((_sid >> 16) | (_sid << 16)));
+ UHD_ASSERT_THROW(packet_info.packet_count == (seq_to_ack & 0xfff));
+ UHD_ASSERT_THROW(packet_info.num_payload_words32 == 2);
+ UHD_ASSERT_THROW(packet_info.packet_type == _packet_type);
+ }
+ catch(const std::exception &ex)
+ {
+ throw uhd::io_error(str(boost::format("Radio ctrl (%s) packet parse error - %s") % _name % ex.what()));
+ }
+
+ //return the readback value
+ if (readback and _outstanding_seqs.empty())
+ {
+ const boost::uint64_t hi = (_bige)? uhd::ntohx(pkt[packet_info.num_header_words32+0]) : uhd::wtohx(pkt[packet_info.num_header_words32+0]);
+ const boost::uint64_t lo = (_bige)? uhd::ntohx(pkt[packet_info.num_header_words32+1]) : uhd::wtohx(pkt[packet_info.num_header_words32+1]);
+ return ((hi << 32) | lo);
+ }
+ }
+ return 0;
+ }
+
+ void push_response(const boost::uint32_t *buff)
+ {
+ resp_buff_type resp_buff;
+ std::memcpy(resp_buff.data, buff, sizeof(resp_buff));
+ _resp_queue.push_with_haste(resp_buff);
+ }
+
+ void hold_task(boost::shared_ptr<void> task)
+ {
+ _async_task = task;
+ }
+
+ const vrt::if_packet_info_t::link_type_t _link_type;
+ const vrt::if_packet_info_t::packet_type_t _packet_type;
+ const bool _bige;
+ const uhd::transport::zero_copy_if::sptr _ctrl_xport;
+ const uhd::transport::zero_copy_if::sptr _resp_xport;
+ boost::shared_ptr<void> _async_task;
+ const boost::uint32_t _sid;
+ const std::string _name;
+ boost::mutex _mutex;
+ size_t _seq_out;
+ uhd::time_spec_t _time;
+ bool _use_time;
+ double _tick_rate;
+ double _timeout;
+ std::queue<size_t> _outstanding_seqs;
+ struct resp_buff_type
+ {
+ boost::uint32_t data[8];
+ };
+ bounded_buffer<resp_buff_type> _resp_queue;
+ const size_t _resp_queue_size;
+};
+
+
+radio_ctrl_core_3000::sptr radio_ctrl_core_3000::make(
+ vrt::if_packet_info_t::link_type_t link_type,
+ zero_copy_if::sptr ctrl_xport,
+ zero_copy_if::sptr resp_xport,
+ const boost::uint32_t sid,
+ const std::string &name
+)
+{
+ return sptr(new radio_ctrl_core_3000_impl(link_type, ctrl_xport, resp_xport, sid, name));
+}
diff --git a/host/lib/usrp/cores/radio_ctrl_core_3000.hpp b/host/lib/usrp/cores/radio_ctrl_core_3000.hpp
new file mode 100644
index 000000000..6ef484296
--- /dev/null
+++ b/host/lib/usrp/cores/radio_ctrl_core_3000.hpp
@@ -0,0 +1,59 @@
+//
+// 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_LIBUHD_USRP_RADIO_CTRL_3000_HPP
+#define INCLUDED_LIBUHD_USRP_RADIO_CTRL_3000_HPP
+
+#include <uhd/types/time_spec.hpp>
+#include <uhd/transport/zero_copy.hpp>
+#include <uhd/transport/vrt_if_packet.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include "wb_iface.hpp"
+#include <string>
+
+/*!
+ * Provide access to peek, poke for the radio ctrl module
+ */
+class radio_ctrl_core_3000 : public wb_iface
+{
+public:
+ typedef boost::shared_ptr<radio_ctrl_core_3000> sptr;
+
+ //! Make a new control object
+ static sptr make(
+ uhd::transport::vrt::if_packet_info_t::link_type_t link_type,
+ uhd::transport::zero_copy_if::sptr ctrl_xport,
+ uhd::transport::zero_copy_if::sptr resp_xport,
+ const boost::uint32_t sid,
+ const std::string &name = "0"
+ );
+
+ //! Hold a ref to a task thats feeding push response
+ virtual void hold_task(boost::shared_ptr<void> task) = 0;
+
+ //! Push a response externall (resp_xport is NULL)
+ virtual void push_response(const boost::uint32_t *buff) = 0;
+
+ //! Set the command time that will activate
+ virtual void set_time(const uhd::time_spec_t &time) = 0;
+
+ //! Set the tick rate (converting time into ticks)
+ virtual void set_tick_rate(const double rate) = 0;
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_RADIO_CTRL_3000_HPP */
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.cpp b/host/lib/usrp/cores/rx_dsp_core_200.cpp
new file mode 100644
index 000000000..ef6b85de9
--- /dev/null
+++ b/host/lib/usrp/cores/rx_dsp_core_200.cpp
@@ -0,0 +1,280 @@
+//
+// Copyright 2011-2012 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 "rx_dsp_core_200.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <uhd/utils/safe_call.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/thread/thread.hpp> //thread sleep
+#include <boost/math/special_functions/round.hpp>
+#include <boost/math/special_functions/sign.hpp>
+#include <algorithm>
+#include <cmath>
+
+#define REG_DSP_RX_FREQ _dsp_base + 0
+#define REG_DSP_RX_SCALE_IQ _dsp_base + 4
+#define REG_DSP_RX_DECIM _dsp_base + 8
+#define REG_DSP_RX_MUX _dsp_base + 12
+
+#define FLAG_DSP_RX_MUX_SWAP_IQ (1 << 0)
+#define FLAG_DSP_RX_MUX_REAL_MODE (1 << 1)
+
+#define REG_RX_CTRL_STREAM_CMD _ctrl_base + 0
+#define REG_RX_CTRL_TIME_HI _ctrl_base + 4
+#define REG_RX_CTRL_TIME_LO _ctrl_base + 8
+#define REG_RX_CTRL_FORMAT _ctrl_base + 12
+#define REG_RX_CTRL_VRT_HDR _ctrl_base + 16
+#define REG_RX_CTRL_VRT_SID _ctrl_base + 20
+#define REG_RX_CTRL_VRT_TLR _ctrl_base + 24
+#define REG_RX_CTRL_NSAMPS_PP _ctrl_base + 28
+#define REG_RX_CTRL_NCHANNELS _ctrl_base + 32
+
+template <class T> T ceil_log2(T num){
+ return std::ceil(std::log(num)/std::log(T(2)));
+}
+
+using namespace uhd;
+
+class rx_dsp_core_200_impl : public rx_dsp_core_200{
+public:
+ rx_dsp_core_200_impl(
+ wb_iface::sptr iface,
+ const size_t dsp_base, const size_t ctrl_base,
+ const boost::uint32_t sid, const bool lingering_packet
+ ):
+ _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid)
+ {
+ //init to something so update method has reasonable defaults
+ _scaling_adjustment = 1.0;
+ _dsp_extra_scaling = 1.0;
+
+ //This is a hack/fix for the lingering packet problem.
+ //The caller should also flush the recv transports
+ if (lingering_packet){
+ stream_cmd_t stream_cmd(stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
+ stream_cmd.num_samps = 1;
+ issue_stream_command(stream_cmd);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10)); //lets lingering pkt propagate
+ }
+
+ this->clear();
+ }
+
+ ~rx_dsp_core_200_impl(void)
+ {
+ UHD_SAFE_CALL
+ (
+ //shutdown any possible streaming
+ this->clear();
+ )
+ }
+
+ void clear(void){
+ _iface->poke32(REG_RX_CTRL_NCHANNELS, 0); //also reset
+ _iface->poke32(REG_RX_CTRL_VRT_HDR, 0
+ | (0x1 << 28) //if data with stream id
+ | (0x1 << 26) //has trailer
+ | (0x1 << 20) //fractional time sample count
+ );
+ _iface->poke32(REG_RX_CTRL_VRT_SID, _sid);
+ _iface->poke32(REG_RX_CTRL_VRT_TLR, 0);
+ }
+
+ void set_nsamps_per_packet(const size_t nsamps){
+ _iface->poke32(REG_RX_CTRL_NSAMPS_PP, nsamps);
+ }
+
+ void issue_stream_command(const stream_cmd_t &stream_cmd){
+ UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x0fffffff);
+ _continuous_streaming = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
+
+ //setup the mode to instruction flags
+ typedef boost::tuple<bool, bool, bool, bool> inst_t;
+ static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of
+ //reload, chain, samps, stop
+ (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false, false))
+ (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false, true))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true, false))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true, false))
+ ;
+
+ //setup the instruction flag values
+ bool inst_reload, inst_chain, inst_samps, inst_stop;
+ boost::tie(inst_reload, inst_chain, inst_samps, inst_stop) = mode_to_inst[stream_cmd.stream_mode];
+
+ //calculate the word from flags and length
+ boost::uint32_t cmd_word = 0;
+ cmd_word |= boost::uint32_t((stream_cmd.stream_now)? 1 : 0) << 31;
+ cmd_word |= boost::uint32_t((inst_chain)? 1 : 0) << 30;
+ cmd_word |= boost::uint32_t((inst_reload)? 1 : 0) << 29;
+ cmd_word |= boost::uint32_t((inst_stop)? 1 : 0) << 28;
+ cmd_word |= (inst_samps)? stream_cmd.num_samps : ((inst_stop)? 0 : 1);
+
+ //issue the stream command
+ _iface->poke32(REG_RX_CTRL_STREAM_CMD, cmd_word);
+ const boost::uint64_t ticks = (stream_cmd.stream_now)? 0 : stream_cmd.time_spec.to_ticks(_tick_rate);
+ _iface->poke32(REG_RX_CTRL_TIME_HI, boost::uint32_t(ticks >> 32));
+ _iface->poke32(REG_RX_CTRL_TIME_LO, boost::uint32_t(ticks >> 0)); //latches the command
+ }
+
+ void set_mux(const std::string &mode, const bool fe_swapped){
+ static const uhd::dict<std::string, boost::uint32_t> mode_to_mux = boost::assign::map_list_of
+ ("IQ", 0)
+ ("QI", FLAG_DSP_RX_MUX_SWAP_IQ)
+ ("I", FLAG_DSP_RX_MUX_REAL_MODE)
+ ("Q", FLAG_DSP_RX_MUX_SWAP_IQ | FLAG_DSP_RX_MUX_REAL_MODE)
+ ;
+ _iface->poke32(REG_DSP_RX_MUX, mode_to_mux[mode] ^ (fe_swapped? FLAG_DSP_RX_MUX_SWAP_IQ : 0));
+ }
+
+ void set_tick_rate(const double rate){
+ _tick_rate = rate;
+ }
+
+ void set_link_rate(const double rate){
+ //_link_rate = rate/sizeof(boost::uint32_t); //in samps/s
+ _link_rate = rate/sizeof(boost::uint16_t); //in samps/s (allows for 8sc)
+ }
+
+ uhd::meta_range_t get_host_rates(void){
+ meta_range_t range;
+ for (int rate = 512; rate > 256; rate -= 4){
+ range.push_back(range_t(_tick_rate/rate));
+ }
+ for (int rate = 256; rate > 128; rate -= 2){
+ range.push_back(range_t(_tick_rate/rate));
+ }
+ for (int rate = 128; rate >= int(std::ceil(_tick_rate/_link_rate)); rate -= 1){
+ range.push_back(range_t(_tick_rate/rate));
+ }
+ return range;
+ }
+
+ double set_host_rate(const double rate){
+ const size_t decim_rate = boost::math::iround(_tick_rate/this->get_host_rates().clip(rate, true));
+ size_t decim = decim_rate;
+
+ //determine which half-band filters are activated
+ int hb0 = 0, hb1 = 0;
+ if (decim % 2 == 0){
+ hb0 = 1;
+ decim /= 2;
+ }
+ if (decim % 2 == 0){
+ hb1 = 1;
+ decim /= 2;
+ }
+
+ _iface->poke32(REG_DSP_RX_DECIM, (hb1 << 9) | (hb0 << 8) | (decim & 0xff));
+
+ if (decim > 1 and hb0 == 0 and hb1 == 0)
+ {
+ UHD_MSG(warning) << boost::format(
+ "The requested decimation is odd; the user should expect CIC rolloff.\n"
+ "Select an even decimation to ensure that a halfband filter is enabled.\n"
+ "decimation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n"
+ ) % decim_rate % (_tick_rate/1e6) % (rate/1e6);
+ }
+
+ // Calculate CIC decimation (i.e., without halfband decimators)
+ // Calculate closest multiplier constant to reverse gain absent scale multipliers
+ const double rate_pow = std::pow(double(decim & 0xff), 4);
+ _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*rate_pow);
+ this->update_scalar();
+
+ return _tick_rate/decim_rate;
+ }
+
+ void update_scalar(void){
+ const double factor = 1.0 + std::max(ceil_log2(_scaling_adjustment), 0.0);
+ const double target_scalar = (1 << 17)*_scaling_adjustment/_dsp_extra_scaling/factor;
+ const boost::int32_t actual_scalar = boost::math::iround(target_scalar);
+ _fxpt_scalar_correction = target_scalar/actual_scalar*factor; //should be small
+ _iface->poke32(REG_DSP_RX_SCALE_IQ, actual_scalar);
+ }
+
+ double get_scaling_adjustment(void){
+ return _fxpt_scalar_correction*_host_extra_scaling/32767.;
+ }
+
+ double set_freq(const double freq_){
+ //correct for outside of rate (wrap around)
+ double freq = std::fmod(freq_, _tick_rate);
+ if (std::abs(freq) > _tick_rate/2.0)
+ freq -= boost::math::sign(freq)*_tick_rate;
+
+ //calculate the freq register word (signed)
+ UHD_ASSERT_THROW(std::abs(freq) <= _tick_rate/2.0);
+ static const double scale_factor = std::pow(2.0, 32);
+ const boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / _tick_rate) * scale_factor));
+
+ //update the actual frequency
+ const double actual_freq = (double(freq_word) / scale_factor) * _tick_rate;
+
+ _iface->poke32(REG_DSP_RX_FREQ, boost::uint32_t(freq_word));
+
+ return actual_freq;
+ }
+
+ uhd::meta_range_t get_freq_range(void){
+ return uhd::meta_range_t(-_tick_rate/2, +_tick_rate/2, _tick_rate/std::pow(2.0, 32));
+ }
+
+ void handle_overflow(void){
+ if (_continuous_streaming) issue_stream_command(stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+ }
+
+ void setup(const uhd::stream_args_t &stream_args){
+ if (not stream_args.args.has_key("noclear")) this->clear();
+
+ unsigned format_word = 0;
+ if (stream_args.otw_format == "sc16"){
+ format_word = 0;
+ _dsp_extra_scaling = 1.0;
+ _host_extra_scaling = 1.0;
+ }
+ else if (stream_args.otw_format == "sc8"){
+ format_word = (1 << 0);
+ double peak = stream_args.args.cast<double>("peak", 1.0);
+ peak = std::max(peak, 1.0/256);
+ _host_extra_scaling = peak*256;
+ _dsp_extra_scaling = peak*256;
+ }
+ else throw uhd::value_error("USRP RX cannot handle requested wire format: " + stream_args.otw_format);
+
+ _host_extra_scaling *= stream_args.args.cast<double>("fullscale", 1.0);
+
+ this->update_scalar();
+
+ _iface->poke32(REG_RX_CTRL_FORMAT, format_word);
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _dsp_base, _ctrl_base;
+ double _tick_rate, _link_rate;
+ bool _continuous_streaming;
+ double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction;
+ const boost::uint32_t _sid;
+};
+
+rx_dsp_core_200::sptr rx_dsp_core_200::make(wb_iface::sptr iface, const size_t dsp_base, const size_t ctrl_base, const boost::uint32_t sid, const bool lingering_packet){
+ return sptr(new rx_dsp_core_200_impl(iface, dsp_base, ctrl_base, sid, lingering_packet));
+}
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.hpp b/host/lib/usrp/cores/rx_dsp_core_200.hpp
new file mode 100644
index 000000000..b01f751e9
--- /dev/null
+++ b/host/lib/usrp/cores/rx_dsp_core_200.hpp
@@ -0,0 +1,67 @@
+//
+// Copyright 2011 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_LIBUHD_USRP_RX_DSP_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_RX_DSP_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/stream.hpp>
+#include <uhd/types/ranges.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <uhd/types/stream_cmd.hpp>
+#include "wb_iface.hpp"
+#include <string>
+
+class rx_dsp_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<rx_dsp_core_200> sptr;
+
+ static sptr make(
+ wb_iface::sptr iface,
+ const size_t dsp_base, const size_t ctrl_base,
+ const boost::uint32_t sid, const bool lingering_packet = false
+ );
+
+ virtual void clear(void) = 0;
+
+ virtual void set_nsamps_per_packet(const size_t nsamps) = 0;
+
+ virtual void issue_stream_command(const uhd::stream_cmd_t &stream_cmd) = 0;
+
+ virtual void set_mux(const std::string &mode, const bool fe_swapped = false) = 0;
+
+ virtual void set_tick_rate(const double rate) = 0;
+
+ virtual void set_link_rate(const double rate) = 0;
+
+ virtual double set_host_rate(const double rate) = 0;
+
+ virtual uhd::meta_range_t get_host_rates(void) = 0;
+
+ virtual double get_scaling_adjustment(void) = 0;
+
+ virtual uhd::meta_range_t get_freq_range(void) = 0;
+
+ virtual double set_freq(const double freq) = 0;
+
+ virtual void handle_overflow(void) = 0;
+
+ virtual void setup(const uhd::stream_args_t &stream_args) = 0;
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_RX_DSP_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.cpp b/host/lib/usrp/cores/rx_dsp_core_3000.cpp
new file mode 100644
index 000000000..36d9af5bc
--- /dev/null
+++ b/host/lib/usrp/cores/rx_dsp_core_3000.cpp
@@ -0,0 +1,204 @@
+//
+// 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
+// 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 "rx_dsp_core_3000.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <uhd/utils/safe_call.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/thread/thread.hpp> //thread sleep
+#include <boost/math/special_functions/round.hpp>
+#include <boost/math/special_functions/sign.hpp>
+#include <algorithm>
+#include <cmath>
+
+#define REG_DSP_RX_FREQ _dsp_base + 0
+#define REG_DSP_RX_SCALE_IQ _dsp_base + 4
+#define REG_DSP_RX_DECIM _dsp_base + 8
+#define REG_DSP_RX_MUX _dsp_base + 12
+
+#define FLAG_DSP_RX_MUX_SWAP_IQ (1 << 0)
+#define FLAG_DSP_RX_MUX_REAL_MODE (1 << 1)
+
+template <class T> T ceil_log2(T num){
+ return std::ceil(std::log(num)/std::log(T(2)));
+}
+
+using namespace uhd;
+
+class rx_dsp_core_3000_impl : public rx_dsp_core_3000{
+public:
+ rx_dsp_core_3000_impl(
+ wb_iface::sptr iface,
+ const size_t dsp_base
+ ):
+ _iface(iface), _dsp_base(dsp_base)
+ {
+ //init to something so update method has reasonable defaults
+ _scaling_adjustment = 1.0;
+ _dsp_extra_scaling = 1.0;
+ this->set_tick_rate(1.0);
+ }
+
+ ~rx_dsp_core_3000_impl(void)
+ {
+ UHD_SAFE_CALL
+ (
+ //NOP
+ )
+ }
+
+ void set_mux(const std::string &mode, const bool fe_swapped){
+ static const uhd::dict<std::string, boost::uint32_t> mode_to_mux = boost::assign::map_list_of
+ ("IQ", 0)
+ ("QI", FLAG_DSP_RX_MUX_SWAP_IQ)
+ ("I", FLAG_DSP_RX_MUX_REAL_MODE)
+ ("Q", FLAG_DSP_RX_MUX_SWAP_IQ | FLAG_DSP_RX_MUX_REAL_MODE)
+ ;
+ _iface->poke32(REG_DSP_RX_MUX, mode_to_mux[mode] ^ (fe_swapped? FLAG_DSP_RX_MUX_SWAP_IQ : 0));
+ }
+
+ void set_tick_rate(const double rate){
+ _tick_rate = rate;
+ }
+
+ void set_link_rate(const double rate){
+ //_link_rate = rate/sizeof(boost::uint32_t); //in samps/s
+ _link_rate = rate/sizeof(boost::uint16_t); //in samps/s (allows for 8sc)
+ }
+
+ uhd::meta_range_t get_host_rates(void){
+ meta_range_t range;
+ for (int rate = 512; rate > 256; rate -= 4){
+ range.push_back(range_t(_tick_rate/rate));
+ }
+ for (int rate = 256; rate > 128; rate -= 2){
+ range.push_back(range_t(_tick_rate/rate));
+ }
+ for (int rate = 128; rate >= int(std::ceil(_tick_rate/_link_rate)); rate -= 1){
+ range.push_back(range_t(_tick_rate/rate));
+ }
+ return range;
+ }
+
+ double set_host_rate(const double rate){
+ const size_t decim_rate = boost::math::iround(_tick_rate/this->get_host_rates().clip(rate, true));
+ size_t decim = decim_rate;
+
+ //determine which half-band filters are activated
+ int hb0 = 0, hb1 = 0;
+ if (decim % 2 == 0){
+ hb0 = 1;
+ decim /= 2;
+ }
+ if (decim % 2 == 0){
+ hb1 = 1;
+ decim /= 2;
+ }
+
+ _iface->poke32(REG_DSP_RX_DECIM, (hb1 << 9) | (hb0 << 8) | (decim & 0xff));
+
+ if (decim > 1 and hb0 == 0 and hb1 == 0)
+ {
+ UHD_MSG(warning) << boost::format(
+ "The requested decimation is odd; the user should expect CIC rolloff.\n"
+ "Select an even decimation to ensure that a halfband filter is enabled.\n"
+ "decimation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n"
+ ) % decim_rate % (_tick_rate/1e6) % (rate/1e6);
+ }
+
+ // Calculate CIC decimation (i.e., without halfband decimators)
+ // Calculate closest multiplier constant to reverse gain absent scale multipliers
+ const double rate_pow = std::pow(double(decim & 0xff), 4);
+ _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*rate_pow);
+ this->update_scalar();
+
+ return _tick_rate/decim_rate;
+ }
+
+ void update_scalar(void){
+ const double factor = 1.0 + std::max(ceil_log2(_scaling_adjustment), 0.0);
+ const double target_scalar = (1 << 17)*_scaling_adjustment/_dsp_extra_scaling/factor;
+ const boost::int32_t actual_scalar = boost::math::iround(target_scalar);
+ _fxpt_scalar_correction = target_scalar/actual_scalar*factor; //should be small
+ _iface->poke32(REG_DSP_RX_SCALE_IQ, actual_scalar);
+ }
+
+ double get_scaling_adjustment(void){
+ return _fxpt_scalar_correction*_host_extra_scaling/32767.;
+ }
+
+ double set_freq(const double freq_){
+ //correct for outside of rate (wrap around)
+ double freq = std::fmod(freq_, _tick_rate);
+ if (std::abs(freq) > _tick_rate/2.0)
+ freq -= boost::math::sign(freq)*_tick_rate;
+
+ //calculate the freq register word (signed)
+ UHD_ASSERT_THROW(std::abs(freq) <= _tick_rate/2.0);
+ static const double scale_factor = std::pow(2.0, 32);
+ const boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / _tick_rate) * scale_factor));
+
+ //update the actual frequency
+ const double actual_freq = (double(freq_word) / scale_factor) * _tick_rate;
+
+ _iface->poke32(REG_DSP_RX_FREQ, boost::uint32_t(freq_word));
+
+ return actual_freq;
+ }
+
+ uhd::meta_range_t get_freq_range(void){
+ return uhd::meta_range_t(-_tick_rate/2, +_tick_rate/2, _tick_rate/std::pow(2.0, 32));
+ }
+
+ void setup(const uhd::stream_args_t &stream_args){
+
+ //unsigned format_word = 0;
+ if (stream_args.otw_format == "sc16"){
+ //format_word = 0;
+ _dsp_extra_scaling = 1.0;
+ _host_extra_scaling = 1.0;
+ }
+ /*
+ else if (stream_args.otw_format == "sc8"){
+ format_word = (1 << 0);
+ double peak = stream_args.args.cast<double>("peak", 1.0);
+ peak = std::max(peak, 1.0/256);
+ _host_extra_scaling = peak*256;
+ _dsp_extra_scaling = peak*256;
+ }
+ */
+ else throw uhd::value_error("USRP RX cannot handle requested wire format: " + stream_args.otw_format);
+
+ _host_extra_scaling *= stream_args.args.cast<double>("fullscale", 1.0);
+
+ this->update_scalar();
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _dsp_base;
+ double _tick_rate, _link_rate;
+ double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction;
+};
+
+rx_dsp_core_3000::sptr rx_dsp_core_3000::make(wb_iface::sptr iface, const size_t dsp_base)
+{
+ return sptr(new rx_dsp_core_3000_impl(iface, dsp_base));
+}
diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.hpp b/host/lib/usrp/cores/rx_dsp_core_3000.hpp
new file mode 100644
index 000000000..23b12b9b7
--- /dev/null
+++ b/host/lib/usrp/cores/rx_dsp_core_3000.hpp
@@ -0,0 +1,58 @@
+//
+// 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
+// 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_RX_DSP_CORE_3000_HPP
+#define INCLUDED_LIBUHD_USRP_RX_DSP_CORE_3000_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/stream.hpp>
+#include <uhd/types/ranges.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <uhd/types/stream_cmd.hpp>
+#include "wb_iface.hpp"
+#include <string>
+
+class rx_dsp_core_3000 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<rx_dsp_core_3000> sptr;
+
+ static sptr make(
+ wb_iface::sptr iface,
+ const size_t dsp_base
+ );
+
+ virtual void set_mux(const std::string &mode, const bool fe_swapped = false) = 0;
+
+ virtual void set_tick_rate(const double rate) = 0;
+
+ virtual void set_link_rate(const double rate) = 0;
+
+ virtual double set_host_rate(const double rate) = 0;
+
+ virtual uhd::meta_range_t get_host_rates(void) = 0;
+
+ virtual double get_scaling_adjustment(void) = 0;
+
+ virtual uhd::meta_range_t get_freq_range(void) = 0;
+
+ virtual double set_freq(const double freq) = 0;
+
+ virtual void setup(const uhd::stream_args_t &stream_args) = 0;
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_RX_DSP_CORE_3000_HPP */
diff --git a/host/lib/usrp/cores/rx_frontend_core_200.cpp b/host/lib/usrp/cores/rx_frontend_core_200.cpp
new file mode 100644
index 000000000..1813758da
--- /dev/null
+++ b/host/lib/usrp/cores/rx_frontend_core_200.cpp
@@ -0,0 +1,80 @@
+//
+// Copyright 2011-2012 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 "rx_frontend_core_200.hpp"
+#include <boost/math/special_functions/round.hpp>
+
+#define REG_RX_FE_SWAP_IQ _base + 0 //lower bit
+#define REG_RX_FE_MAG_CORRECTION _base + 4 //18 bits
+#define REG_RX_FE_PHASE_CORRECTION _base + 8 //18 bits
+#define REG_RX_FE_OFFSET_I _base + 12 //18 bits
+#define REG_RX_FE_OFFSET_Q _base + 16 //18 bits
+
+#define OFFSET_FIXED (1ul << 31)
+#define OFFSET_SET (1ul << 30)
+#define FLAG_MASK (OFFSET_FIXED | OFFSET_SET)
+
+static boost::uint32_t fs_to_bits(const double num, const size_t bits){
+ return boost::int32_t(boost::math::round(num * (1 << (bits-1))));
+}
+
+
+class rx_frontend_core_200_impl : public rx_frontend_core_200{
+public:
+ rx_frontend_core_200_impl(wb_iface::sptr iface, const size_t base):
+ _iface(iface), _base(base)
+ {
+ //NOP
+ }
+
+ void set_mux(const bool swap){
+ _iface->poke32(REG_RX_FE_SWAP_IQ, swap? 1 : 0);
+ }
+
+ void set_dc_offset_auto(const bool enb){
+ this->set_dc_offset(enb? 0 : OFFSET_FIXED);
+ }
+
+ std::complex<double> set_dc_offset(const std::complex<double> &off){
+ static const double scaler = double(1ul << 29);
+ _i_dc_off = boost::math::iround(off.real()*scaler);
+ _q_dc_off = boost::math::iround(off.imag()*scaler);
+
+ this->set_dc_offset(OFFSET_SET | OFFSET_FIXED);
+
+ return std::complex<double>(_i_dc_off/scaler, _q_dc_off/scaler);
+ }
+
+ void set_dc_offset(const boost::uint32_t flags){
+ _iface->poke32(REG_RX_FE_OFFSET_I, flags | (_i_dc_off & ~FLAG_MASK));
+ _iface->poke32(REG_RX_FE_OFFSET_Q, flags | (_q_dc_off & ~FLAG_MASK));
+ }
+
+ void set_iq_balance(const std::complex<double> &cor){
+ _iface->poke32(REG_RX_FE_MAG_CORRECTION, fs_to_bits(cor.real(), 18));
+ _iface->poke32(REG_RX_FE_PHASE_CORRECTION, fs_to_bits(cor.imag(), 18));
+ }
+
+private:
+ boost::int32_t _i_dc_off, _q_dc_off;
+ wb_iface::sptr _iface;
+ const size_t _base;
+};
+
+rx_frontend_core_200::sptr rx_frontend_core_200::make(wb_iface::sptr iface, const size_t base){
+ return sptr(new rx_frontend_core_200_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/rx_frontend_core_200.hpp b/host/lib/usrp/cores/rx_frontend_core_200.hpp
new file mode 100644
index 000000000..5755424c8
--- /dev/null
+++ b/host/lib/usrp/cores/rx_frontend_core_200.hpp
@@ -0,0 +1,44 @@
+//
+// Copyright 2011 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_LIBUHD_USRP_TX_FRONTEND_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_TX_FRONTEND_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+#include <complex>
+#include <string>
+
+class rx_frontend_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<rx_frontend_core_200> sptr;
+
+ static sptr make(wb_iface::sptr iface, const size_t base);
+
+ virtual void set_mux(const bool swap) = 0;
+
+ virtual void set_dc_offset_auto(const bool enb) = 0;
+
+ virtual std::complex<double> set_dc_offset(const std::complex<double> &off) = 0;
+
+ virtual void set_iq_balance(const std::complex<double> &cor) = 0;
+
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_TX_FRONTEND_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/rx_vita_core_3000.cpp b/host/lib/usrp/cores/rx_vita_core_3000.cpp
new file mode 100644
index 000000000..aad137ea3
--- /dev/null
+++ b/host/lib/usrp/cores/rx_vita_core_3000.cpp
@@ -0,0 +1,153 @@
+//
+// 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/>.
+//
+
+#include "rx_vita_core_3000.hpp"
+#include <uhd/utils/msg.hpp>
+#include <uhd/utils/safe_call.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/tuple/tuple.hpp>
+
+#define REG_FRAMER_MAXLEN _base + 4*4 + 0
+#define REG_FRAMER_SID _base + 4*4 + 4
+
+#define REG_CTRL_CMD _base + 0
+#define REG_CTRL_TIME_HI _base + 4
+#define REG_CTRL_TIME_LO _base + 8
+
+#define REG_FC_WINDOW _base + 6*4 + 0
+#define REG_FC_ENABLE _base + 6*4 + 4
+
+using namespace uhd;
+
+struct rx_vita_core_3000_impl : rx_vita_core_3000
+{
+ rx_vita_core_3000_impl(
+ wb_iface::sptr iface,
+ const size_t base
+ ):
+ _iface(iface),
+ _base(base),
+ _continuous_streaming(false),
+ _is_setup(false)
+ {
+ this->set_tick_rate(1); //init to non zero
+ this->set_nsamps_per_packet(100); //init to non zero
+ this->clear();
+ }
+
+ ~rx_vita_core_3000_impl(void)
+ {
+ UHD_SAFE_CALL
+ (
+ this->clear();
+ )
+ }
+
+ void configure_flow_control(const size_t window_size)
+ {
+ _iface->poke32(REG_FC_WINDOW, window_size-1);
+ _iface->poke32(REG_FC_ENABLE, window_size?1:0);
+ }
+
+ void clear(void)
+ {
+ this->configure_flow_control(0); //disable fc
+ }
+
+ void set_nsamps_per_packet(const size_t nsamps)
+ {
+ _iface->poke32(REG_FRAMER_MAXLEN, nsamps);
+ }
+
+ void issue_stream_command(const uhd::stream_cmd_t &stream_cmd)
+ {
+ if (not _is_setup)
+ {
+ //UHD_MSG(warning) << "rx vita core 3000 issue stream command - not setup yet!";
+ return;
+ }
+ UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x0fffffff);
+ _continuous_streaming = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
+
+ //setup the mode to instruction flags
+ typedef boost::tuple<bool, bool, bool, bool> inst_t;
+ static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of
+ //reload, chain, samps, stop
+ (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false, false))
+ (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false, true))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true, false))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true, false))
+ ;
+
+ //setup the instruction flag values
+ bool inst_reload, inst_chain, inst_samps, inst_stop;
+ boost::tie(inst_reload, inst_chain, inst_samps, inst_stop) = mode_to_inst[stream_cmd.stream_mode];
+
+ //calculate the word from flags and length
+ boost::uint32_t cmd_word = 0;
+ cmd_word |= boost::uint32_t((stream_cmd.stream_now)? 1 : 0) << 31;
+ cmd_word |= boost::uint32_t((inst_chain)? 1 : 0) << 30;
+ cmd_word |= boost::uint32_t((inst_reload)? 1 : 0) << 29;
+ cmd_word |= boost::uint32_t((inst_stop)? 1 : 0) << 28;
+ cmd_word |= (inst_samps)? stream_cmd.num_samps : ((inst_stop)? 0 : 1);
+
+ //issue the stream command
+ _iface->poke32(REG_CTRL_CMD, cmd_word);
+ const boost::uint64_t ticks = (stream_cmd.stream_now)? 0 : stream_cmd.time_spec.to_ticks(_tick_rate);
+ _iface->poke32(REG_CTRL_TIME_HI, boost::uint32_t(ticks >> 32));
+ _iface->poke32(REG_CTRL_TIME_LO, boost::uint32_t(ticks >> 0)); //latches the command
+ }
+
+ void set_tick_rate(const double rate)
+ {
+ _tick_rate = rate;
+ }
+
+ void set_sid(const boost::uint32_t sid)
+ {
+ _iface->poke32(REG_FRAMER_SID, sid);
+ }
+
+ void handle_overflow(void)
+ {
+ if (_continuous_streaming) this->issue_stream_command(stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+ }
+
+ void setup(const uhd::stream_args_t &)
+ {
+ _is_setup = true;
+ }
+
+ bool in_continuous_streaming_mode(void)
+ {
+ return _continuous_streaming;
+ }
+
+ wb_iface::sptr _iface;
+ const size_t _base;
+ double _tick_rate;
+ bool _continuous_streaming;
+ bool _is_setup;
+};
+
+rx_vita_core_3000::sptr rx_vita_core_3000::make(
+ wb_iface::sptr iface,
+ const size_t base
+)
+{
+ return rx_vita_core_3000::sptr(new rx_vita_core_3000_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/rx_vita_core_3000.hpp b/host/lib/usrp/cores/rx_vita_core_3000.hpp
new file mode 100644
index 000000000..b011a7388
--- /dev/null
+++ b/host/lib/usrp/cores/rx_vita_core_3000.hpp
@@ -0,0 +1,59 @@
+//
+// 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_LIBUHD_USRP_RX_VITA_CORE_3000_HPP
+#define INCLUDED_LIBUHD_USRP_RX_VITA_CORE_3000_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/stream.hpp>
+#include <uhd/types/ranges.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <uhd/types/stream_cmd.hpp>
+#include "wb_iface.hpp"
+#include <string>
+
+class rx_vita_core_3000 : boost::noncopyable
+{
+public:
+ typedef boost::shared_ptr<rx_vita_core_3000> sptr;
+
+ static sptr make(
+ wb_iface::sptr iface,
+ const size_t base
+ );
+
+ virtual void clear(void) = 0;
+
+ virtual void set_nsamps_per_packet(const size_t nsamps) = 0;
+
+ virtual void issue_stream_command(const uhd::stream_cmd_t &stream_cmd) = 0;
+
+ virtual void set_tick_rate(const double rate) = 0;
+
+ virtual void set_sid(const boost::uint32_t sid) = 0;
+
+ virtual void handle_overflow(void) = 0;
+
+ virtual void setup(const uhd::stream_args_t &stream_args) = 0;
+
+ virtual void configure_flow_control(const size_t window_size) = 0;
+
+ virtual bool in_continuous_streaming_mode(void) = 0;
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_RX_VITA_CORE_3000_HPP */
diff --git a/host/lib/usrp/cores/spi_core_100.cpp b/host/lib/usrp/cores/spi_core_100.cpp
new file mode 100644
index 000000000..d11a499a9
--- /dev/null
+++ b/host/lib/usrp/cores/spi_core_100.cpp
@@ -0,0 +1,88 @@
+//
+// Copyright 2011 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 "spi_core_100.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/thread/thread.hpp> //sleep
+
+#define REG_SPI_TXRX0 _base + 0
+#define REG_SPI_TXRX1 _base + 4
+#define REG_SPI_TXRX2 _base + 8
+#define REG_SPI_TXRX3 _base + 12
+#define REG_SPI_CTRL _base + 16
+#define REG_SPI_DIV _base + 20
+#define REG_SPI_SS _base + 24
+
+//spi ctrl register bit definitions
+#define SPI_CTRL_ASS (1<<13)
+#define SPI_CTRL_IE (1<<12)
+#define SPI_CTRL_LSB (1<<11)
+#define SPI_CTRL_TXNEG (1<<10) //mosi edge, push on falling edge when 1
+#define SPI_CTRL_RXNEG (1<< 9) //miso edge, latch on falling edge when 1
+#define SPI_CTRL_GO_BSY (1<< 8)
+#define SPI_CTRL_CHAR_LEN_MASK 0x7F
+
+using namespace uhd;
+
+class spi_core_100_impl : public spi_core_100{
+public:
+ spi_core_100_impl(wb_iface::sptr iface, const size_t base):
+ _iface(iface), _base(base) { /* NOP */}
+
+ boost::uint32_t transact_spi(
+ int which_slave,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits,
+ bool readback
+ ){
+ UHD_ASSERT_THROW(num_bits <= 32 and (num_bits % 8) == 0);
+
+ int edge_flags = ((config.miso_edge==spi_config_t::EDGE_FALL) ? SPI_CTRL_RXNEG : 0) |
+ ((config.mosi_edge==spi_config_t::EDGE_FALL) ? 0 : SPI_CTRL_TXNEG)
+ ;
+ boost::uint16_t ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & num_bits) | edge_flags;
+
+ spi_wait();
+ _iface->poke16(REG_SPI_DIV, 0x0001); // = fpga_clk / 4
+ _iface->poke32(REG_SPI_SS, which_slave & 0xFFFF);
+ _iface->poke32(REG_SPI_TXRX0, data);
+ _iface->poke16(REG_SPI_CTRL, ctrl);
+ _iface->poke16(REG_SPI_CTRL, ctrl | SPI_CTRL_GO_BSY);
+
+ if (not readback) return 0;
+ spi_wait();
+ return _iface->peek32(REG_SPI_TXRX0);
+ }
+
+private:
+ void spi_wait(void) {
+ for (size_t i = 0; i < 100; i++){
+ if ((_iface->peek16(REG_SPI_CTRL) & SPI_CTRL_GO_BSY) == 0) return;
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ }
+ UHD_MSG(error) << "spi_core_100: spi_wait timeout" << std::endl;
+ }
+
+ wb_iface::sptr _iface;
+ const size_t _base;
+};
+
+spi_core_100::sptr spi_core_100::make(wb_iface::sptr iface, const size_t base){
+ return sptr(new spi_core_100_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/spi_core_100.hpp b/host/lib/usrp/cores/spi_core_100.hpp
new file mode 100644
index 000000000..87d328aaa
--- /dev/null
+++ b/host/lib/usrp/cores/spi_core_100.hpp
@@ -0,0 +1,35 @@
+//
+// Copyright 2011 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_LIBUHD_USRP_SPI_CORE_100_HPP
+#define INCLUDED_LIBUHD_USRP_SPI_CORE_100_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/serial.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class spi_core_100 : boost::noncopyable, public uhd::spi_iface{
+public:
+ typedef boost::shared_ptr<spi_core_100> sptr;
+
+ //! makes a new spi core from iface and slave base
+ static sptr make(wb_iface::sptr iface, const size_t base);
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_SPI_CORE_100_HPP */
diff --git a/host/lib/usrp/cores/spi_core_3000.cpp b/host/lib/usrp/cores/spi_core_3000.cpp
new file mode 100644
index 000000000..b7503064a
--- /dev/null
+++ b/host/lib/usrp/cores/spi_core_3000.cpp
@@ -0,0 +1,96 @@
+//
+// 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/>.
+//
+
+#include "spi_core_3000.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/thread/thread.hpp> //sleep
+
+#define SPI_DIV _base + 0
+#define SPI_CTRL _base + 4
+#define SPI_DATA _base + 8
+
+using namespace uhd;
+
+class spi_core_3000_impl : public spi_core_3000
+{
+public:
+ spi_core_3000_impl(wb_iface::sptr iface, const size_t base, const size_t readback):
+ _iface(iface), _base(base), _readback(readback), _ctrl_word_cache(0)
+ {
+ this->set_divider(30);
+ }
+
+ boost::uint32_t transact_spi(
+ int which_slave,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits,
+ bool readback
+ ){
+ boost::mutex::scoped_lock lock(_mutex);
+
+ //load control word
+ boost::uint32_t ctrl_word = 0;
+ ctrl_word |= ((which_slave & 0xffffff) << 0);
+ ctrl_word |= ((num_bits & 0x3f) << 24);
+ if (config.mosi_edge == spi_config_t::EDGE_FALL) ctrl_word |= (1 << 31);
+ if (config.miso_edge == spi_config_t::EDGE_RISE) ctrl_word |= (1 << 30);
+
+ //load data word (must be in upper bits)
+ const boost::uint32_t data_out = data << (32 - num_bits);
+
+ //conditionally send control word
+ if (_ctrl_word_cache != ctrl_word)
+ {
+ _iface->poke32(SPI_DIV, _div);
+ _iface->poke32(SPI_CTRL, ctrl_word);
+ _ctrl_word_cache = ctrl_word;
+ }
+
+ //send data word
+ _iface->poke32(SPI_DATA, data_out);
+
+ //conditional readback
+ if (readback)
+ {
+ return _iface->peek32(_readback);
+ }
+
+ return 0;
+ }
+
+ void set_divider(const double div)
+ {
+ _div = size_t((div/2) - 0.5);
+ }
+
+private:
+
+ wb_iface::sptr _iface;
+ const size_t _base;
+ const size_t _readback;
+ boost::uint32_t _ctrl_word_cache;
+ boost::mutex _mutex;
+ size_t _div;
+};
+
+spi_core_3000::sptr spi_core_3000::make(wb_iface::sptr iface, const size_t base, const size_t readback)
+{
+ return sptr(new spi_core_3000_impl(iface, base, readback));
+}
+
diff --git a/host/lib/usrp/cores/spi_core_3000.hpp b/host/lib/usrp/cores/spi_core_3000.hpp
new file mode 100644
index 000000000..995ad59db
--- /dev/null
+++ b/host/lib/usrp/cores/spi_core_3000.hpp
@@ -0,0 +1,39 @@
+//
+// 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_LIBUHD_USRP_SPI_CORE_3000_HPP
+#define INCLUDED_LIBUHD_USRP_SPI_CORE_3000_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/serial.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class spi_core_3000 : boost::noncopyable, public uhd::spi_iface
+{
+public:
+ typedef boost::shared_ptr<spi_core_3000> sptr;
+
+ //! makes a new spi core from iface and slave base
+ static sptr make(wb_iface::sptr iface, const size_t base, const size_t readback);
+
+ //! Set the spi clock divider to something usable
+ virtual void set_divider(const double div) = 0;
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_SPI_CORE_3000_HPP */
diff --git a/host/lib/usrp/cores/time64_core_200.cpp b/host/lib/usrp/cores/time64_core_200.cpp
new file mode 100644
index 000000000..11b310362
--- /dev/null
+++ b/host/lib/usrp/cores/time64_core_200.cpp
@@ -0,0 +1,138 @@
+//
+// Copyright 2011 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 "time64_core_200.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/assert_has.hpp>
+#include <boost/math/special_functions/round.hpp>
+
+#define REG_TIME64_TICKS_HI _base + 0
+#define REG_TIME64_TICKS_LO _base + 4
+#define REG_TIME64_FLAGS _base + 8
+#define REG_TIME64_IMM _base + 12
+#define REG_TIME64_MIMO_SYNC _base + 20 //lower byte is delay cycles
+
+//pps flags (see above)
+#define FLAG_TIME64_PPS_NEGEDGE (0 << 0)
+#define FLAG_TIME64_PPS_POSEDGE (1 << 0)
+#define FLAG_TIME64_PPS_SMA (0 << 1)
+#define FLAG_TIME64_PPS_MIMO (1 << 1) //apparently not used
+
+#define FLAG_TIME64_LATCH_NOW 1
+#define FLAG_TIME64_LATCH_NEXT_PPS 0
+
+#define FLAG_TIME64_MIMO_SYNC (1 << 8)
+
+using namespace uhd;
+
+class time64_core_200_impl : public time64_core_200{
+public:
+ time64_core_200_impl(
+ wb_iface::sptr iface, const size_t base,
+ const readback_bases_type &readback_bases,
+ const size_t mimo_delay_cycles
+ ):
+ _iface(iface), _base(base),
+ _readback_bases(readback_bases),
+ _mimo_delay_cycles(mimo_delay_cycles)
+ {
+ _sources.push_back("none");
+ _sources.push_back("external");
+ _sources.push_back("_external_");
+ if (_mimo_delay_cycles != 0) _sources.push_back("mimo");
+ }
+
+ void enable_gpsdo(void){
+ _sources.push_back("gpsdo");
+ }
+
+ void set_tick_rate(const double rate){
+ _tick_rate = rate;
+ }
+
+ uhd::time_spec_t get_time_now(void){
+ for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously
+ const boost::uint32_t ticks_hi = _iface->peek32(_readback_bases.rb_hi_now);
+ const boost::uint32_t ticks_lo = _iface->peek32(_readback_bases.rb_lo_now);
+ if (ticks_hi != _iface->peek32(_readback_bases.rb_hi_now)) continue;
+ const boost::uint64_t ticks = (boost::uint64_t(ticks_hi) << 32) | ticks_lo;
+ return time_spec_t::from_ticks(ticks, _tick_rate);
+ }
+ throw uhd::runtime_error("time64_core_200: get time now timeout");
+ }
+
+ uhd::time_spec_t get_time_last_pps(void){
+ for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously
+ const boost::uint32_t ticks_hi = _iface->peek32(_readback_bases.rb_hi_pps);
+ const boost::uint32_t ticks_lo = _iface->peek32(_readback_bases.rb_lo_pps);
+ if (ticks_hi != _iface->peek32(_readback_bases.rb_hi_pps)) continue;
+ const boost::uint64_t ticks = (boost::uint64_t(ticks_hi) << 32) | ticks_lo;
+ return time_spec_t::from_ticks(ticks, _tick_rate);
+ }
+ throw uhd::runtime_error("time64_core_200: get time last pps timeout");
+ }
+
+ void set_time_now(const uhd::time_spec_t &time){
+ const boost::uint64_t ticks = time.to_ticks(_tick_rate);
+ _iface->poke32(REG_TIME64_TICKS_LO, boost::uint32_t(ticks >> 0));
+ _iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NOW);
+ _iface->poke32(REG_TIME64_TICKS_HI, boost::uint32_t(ticks >> 32)); //latches all 3
+ }
+
+ void set_time_next_pps(const uhd::time_spec_t &time){
+ const boost::uint64_t ticks = time.to_ticks(_tick_rate);
+ _iface->poke32(REG_TIME64_TICKS_LO, boost::uint32_t(ticks >> 0));
+ _iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NEXT_PPS);
+ _iface->poke32(REG_TIME64_TICKS_HI, boost::uint32_t(ticks >> 32)); //latches all 3
+ }
+
+ void set_time_source(const std::string &source){
+ assert_has(_sources, source, "time source");
+
+ //setup pps flags
+ if (source == "external" or source == "gpsdo"){
+ _iface->poke32(REG_TIME64_FLAGS, FLAG_TIME64_PPS_SMA | FLAG_TIME64_PPS_POSEDGE);
+ }
+ else if (source == "_external_"){
+ _iface->poke32(REG_TIME64_FLAGS, FLAG_TIME64_PPS_SMA | FLAG_TIME64_PPS_NEGEDGE);
+ }
+
+ //setup mimo flags
+ if (source == "mimo"){
+ _iface->poke32(REG_TIME64_MIMO_SYNC, FLAG_TIME64_MIMO_SYNC | (_mimo_delay_cycles & 0xff));
+ }
+ else{
+ _iface->poke32(REG_TIME64_MIMO_SYNC, 0);
+ }
+ }
+
+ std::vector<std::string> get_time_sources(void){
+ return _sources;
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _base;
+ const readback_bases_type _readback_bases;
+ double _tick_rate;
+ const size_t _mimo_delay_cycles;
+ std::vector<std::string> _sources;
+};
+
+time64_core_200::sptr time64_core_200::make(wb_iface::sptr iface, const size_t base, const readback_bases_type &readback_bases, const size_t mimo_delay_cycles){
+ return sptr(new time64_core_200_impl(iface, base, readback_bases, mimo_delay_cycles));
+}
diff --git a/host/lib/usrp/cores/time64_core_200.hpp b/host/lib/usrp/cores/time64_core_200.hpp
new file mode 100644
index 000000000..315f2ba67
--- /dev/null
+++ b/host/lib/usrp/cores/time64_core_200.hpp
@@ -0,0 +1,63 @@
+//
+// Copyright 2011-2012 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_LIBUHD_USRP_TIME64_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_TIME64_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/time_spec.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+#include <string>
+#include <vector>
+
+class time64_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<time64_core_200> sptr;
+
+ struct readback_bases_type{
+ size_t rb_hi_now, rb_lo_now;
+ size_t rb_hi_pps, rb_lo_pps;
+ };
+
+ //! makes a new time64 core from iface and slave base
+ static sptr make(
+ wb_iface::sptr iface, const size_t base,
+ const readback_bases_type &readback_bases,
+ const size_t mimo_delay_cycles = 0 // 0 means no-mimo
+ );
+
+ virtual void enable_gpsdo(void) = 0;
+
+ virtual void set_tick_rate(const double rate) = 0;
+
+ virtual uhd::time_spec_t get_time_now(void) = 0;
+
+ virtual uhd::time_spec_t get_time_last_pps(void) = 0;
+
+ virtual void set_time_now(const uhd::time_spec_t &time) = 0;
+
+ virtual void set_time_next_pps(const uhd::time_spec_t &time) = 0;
+
+ virtual void set_time_source(const std::string &source) = 0;
+
+ virtual std::vector<std::string> get_time_sources(void) = 0;
+
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_TIME64_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/time_core_3000.cpp b/host/lib/usrp/cores/time_core_3000.cpp
new file mode 100644
index 000000000..45ff55271
--- /dev/null
+++ b/host/lib/usrp/cores/time_core_3000.cpp
@@ -0,0 +1,118 @@
+//
+// 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/>.
+//
+
+#include "time_core_3000.hpp"
+#include <uhd/utils/safe_call.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/thread/thread.hpp>
+
+#define REG_TIME_HI _base + 0
+#define REG_TIME_LO _base + 4
+#define REG_TIME_CTRL _base + 8
+
+#define CTRL_LATCH_TIME_PPS (1 << 1)
+#define CTRL_LATCH_TIME_NOW (1 << 0)
+
+using namespace uhd;
+
+struct time_core_3000_impl : time_core_3000
+{
+ time_core_3000_impl(
+ wb_iface::sptr iface, const size_t base,
+ const readback_bases_type &readback_bases
+ ):
+ _iface(iface),
+ _base(base),
+ _readback_bases(readback_bases)
+ {
+ this->set_tick_rate(1); //init to non zero
+ }
+
+ ~time_core_3000_impl(void)
+ {
+ UHD_SAFE_CALL
+ (
+ //NOP
+ )
+ }
+
+ void set_tick_rate(const double rate)
+ {
+ _tick_rate = rate;
+ }
+
+ void self_test(void)
+ {
+ const size_t sleep_millis = 100;
+ UHD_MSG(status) << "Performing timer loopback test... " << std::flush;
+ const time_spec_t time0 = this->get_time_now();
+ boost::this_thread::sleep(boost::posix_time::milliseconds(sleep_millis));
+ const time_spec_t time1 = this->get_time_now();
+ const double approx_secs = (time1 - time0).get_real_secs();
+ const bool test_fail = (approx_secs > 0.15) or (approx_secs < 0.05);
+ UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl;
+
+ //useful warning for debugging actual rate
+ const size_t ticks_elapsed = _tick_rate*approx_secs;
+ const size_t appox_rate = ticks_elapsed/(sleep_millis/1e3);
+ if (test_fail) UHD_MSG(warning)
+ << "Expecting clock rate: " << (_tick_rate/1e6) << " MHz\n"
+ << "Appoximate clock rate: " << (appox_rate/1e6) << " MHz\n"
+ << std::endl;
+ }
+
+ uhd::time_spec_t get_time_now(void)
+ {
+ const boost::uint64_t ticks = _iface->peek64(_readback_bases.rb_now);
+ return time_spec_t::from_ticks(ticks, _tick_rate);
+ }
+
+ uhd::time_spec_t get_time_last_pps(void)
+ {
+ const boost::uint64_t ticks = _iface->peek64(_readback_bases.rb_pps);
+ return time_spec_t::from_ticks(ticks, _tick_rate);
+ }
+
+ void set_time_now(const uhd::time_spec_t &time)
+ {
+ const boost::uint64_t ticks = time.to_ticks(_tick_rate);
+ _iface->poke32(REG_TIME_HI, boost::uint32_t(ticks >> 32));
+ _iface->poke32(REG_TIME_LO, boost::uint32_t(ticks >> 0));
+ _iface->poke32(REG_TIME_CTRL, CTRL_LATCH_TIME_NOW);
+ }
+
+ void set_time_next_pps(const uhd::time_spec_t &time)
+ {
+ const boost::uint64_t ticks = time.to_ticks(_tick_rate);
+ _iface->poke32(REG_TIME_HI, boost::uint32_t(ticks >> 32));
+ _iface->poke32(REG_TIME_LO, boost::uint32_t(ticks >> 0));
+ _iface->poke32(REG_TIME_CTRL, CTRL_LATCH_TIME_PPS);
+ }
+
+ wb_iface::sptr _iface;
+ const size_t _base;
+ const readback_bases_type _readback_bases;
+ double _tick_rate;
+};
+
+time_core_3000::sptr time_core_3000::make(
+ wb_iface::sptr iface, const size_t base,
+ const readback_bases_type &readback_bases
+)
+{
+ return time_core_3000::sptr(new time_core_3000_impl(iface, base, readback_bases));
+}
diff --git a/host/lib/usrp/cores/time_core_3000.hpp b/host/lib/usrp/cores/time_core_3000.hpp
new file mode 100644
index 000000000..ffe2f4133
--- /dev/null
+++ b/host/lib/usrp/cores/time_core_3000.hpp
@@ -0,0 +1,58 @@
+//
+// 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_LIBUHD_USRP_TIME_CORE_3000_HPP
+#define INCLUDED_LIBUHD_USRP_TIME_CORE_3000_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/time_spec.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class time_core_3000 : boost::noncopyable
+{
+public:
+ typedef boost::shared_ptr<time_core_3000> sptr;
+
+ struct readback_bases_type
+ {
+ size_t rb_now;
+ size_t rb_pps;
+ };
+
+ //! makes a new time core from iface and slave base
+ static sptr make(
+ wb_iface::sptr iface, const size_t base,
+ const readback_bases_type &readback_bases
+ );
+
+ virtual void self_test(void) = 0;
+
+ virtual void set_tick_rate(const double rate) = 0;
+
+ virtual uhd::time_spec_t get_time_now(void) = 0;
+
+ virtual uhd::time_spec_t get_time_last_pps(void) = 0;
+
+ virtual void set_time_now(const uhd::time_spec_t &time) = 0;
+
+ virtual void set_time_next_pps(const uhd::time_spec_t &time) = 0;
+
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_TIME_CORE_3000_HPP */
diff --git a/host/lib/usrp/cores/tx_dsp_core_200.cpp b/host/lib/usrp/cores/tx_dsp_core_200.cpp
new file mode 100644
index 000000000..808f13028
--- /dev/null
+++ b/host/lib/usrp/cores/tx_dsp_core_200.cpp
@@ -0,0 +1,226 @@
+//
+// Copyright 2011-2012 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 "tx_dsp_core_200.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/math/special_functions/sign.hpp>
+#include <boost/thread/thread.hpp> //sleep
+#include <algorithm>
+#include <cmath>
+
+#define REG_DSP_TX_FREQ _dsp_base + 0
+#define REG_DSP_TX_SCALE_IQ _dsp_base + 4
+#define REG_DSP_TX_INTERP _dsp_base + 8
+
+#define REG_TX_CTRL_CLEAR _ctrl_base + 0
+#define REG_TX_CTRL_FORMAT _ctrl_base + 4
+#define REG_TX_CTRL_REPORT_SID _ctrl_base + 8
+#define REG_TX_CTRL_POLICY _ctrl_base + 12
+#define REG_TX_CTRL_CYCLES_PER_UP _ctrl_base + 16
+#define REG_TX_CTRL_PACKETS_PER_UP _ctrl_base + 20
+
+#define FLAG_TX_CTRL_POLICY_WAIT (0x1 << 0)
+#define FLAG_TX_CTRL_POLICY_NEXT_PACKET (0x1 << 1)
+#define FLAG_TX_CTRL_POLICY_NEXT_BURST (0x1 << 2)
+
+//enable flag for registers: cycles and packets per update packet
+#define FLAG_TX_CTRL_UP_ENB (1ul << 31)
+
+template <class T> T ceil_log2(T num){
+ return std::ceil(std::log(num)/std::log(T(2)));
+}
+
+using namespace uhd;
+
+class tx_dsp_core_200_impl : public tx_dsp_core_200{
+public:
+ tx_dsp_core_200_impl(
+ wb_iface::sptr iface,
+ const size_t dsp_base, const size_t ctrl_base,
+ const boost::uint32_t sid
+ ):
+ _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid)
+ {
+ //init to something so update method has reasonable defaults
+ _scaling_adjustment = 1.0;
+ _dsp_extra_scaling = 1.0;
+
+ //init the tx control registers
+ this->clear();
+ this->set_underflow_policy("next_packet");
+ }
+
+ void clear(void){
+ _iface->poke32(REG_TX_CTRL_CLEAR, 1); //reset and flush technique
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+ _iface->poke32(REG_TX_CTRL_CLEAR, 0);
+ _iface->poke32(REG_TX_CTRL_REPORT_SID, _sid);
+ }
+
+ void set_underflow_policy(const std::string &policy){
+ if (policy == "next_packet"){
+ _iface->poke32(REG_TX_CTRL_POLICY, FLAG_TX_CTRL_POLICY_NEXT_PACKET);
+ }
+ else if (policy == "next_burst"){
+ _iface->poke32(REG_TX_CTRL_POLICY, FLAG_TX_CTRL_POLICY_NEXT_BURST);
+ }
+ else throw uhd::value_error("USRP TX cannot handle requested underflow policy: " + policy);
+ }
+
+ void set_tick_rate(const double rate){
+ _tick_rate = rate;
+ }
+
+ void set_link_rate(const double rate){
+ //_link_rate = rate/sizeof(boost::uint32_t); //in samps/s
+ _link_rate = rate/sizeof(boost::uint16_t); //in samps/s (allows for 8sc)
+ }
+
+ uhd::meta_range_t get_host_rates(void){
+ meta_range_t range;
+ for (int rate = 512; rate > 256; rate -= 4){
+ range.push_back(range_t(_tick_rate/rate));
+ }
+ for (int rate = 256; rate > 128; rate -= 2){
+ range.push_back(range_t(_tick_rate/rate));
+ }
+ for (int rate = 128; rate >= int(std::ceil(_tick_rate/_link_rate)); rate -= 1){
+ range.push_back(range_t(_tick_rate/rate));
+ }
+ return range;
+ }
+
+ double set_host_rate(const double rate){
+ const size_t interp_rate = boost::math::iround(_tick_rate/this->get_host_rates().clip(rate, true));
+ size_t interp = interp_rate;
+
+ //determine which half-band filters are activated
+ int hb0 = 0, hb1 = 0;
+ if (interp % 2 == 0){
+ hb0 = 1;
+ interp /= 2;
+ }
+ if (interp % 2 == 0){
+ hb1 = 1;
+ interp /= 2;
+ }
+
+ _iface->poke32(REG_DSP_TX_INTERP, (hb1 << 9) | (hb0 << 8) | (interp & 0xff));
+
+ if (interp > 1 and hb0 == 0 and hb1 == 0)
+ {
+ UHD_MSG(warning) << boost::format(
+ "The requested interpolation is odd; the user should expect CIC rolloff.\n"
+ "Select an even interpolation to ensure that a halfband filter is enabled.\n"
+ "interpolation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n"
+ ) % interp_rate % (_tick_rate/1e6) % (rate/1e6);
+ }
+
+ // Calculate CIC interpolation (i.e., without halfband interpolators)
+ // Calculate closest multiplier constant to reverse gain absent scale multipliers
+ const double rate_pow = std::pow(double(interp & 0xff), 3);
+ _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*rate_pow);
+ this->update_scalar();
+
+ return _tick_rate/interp_rate;
+ }
+
+ void update_scalar(void){
+ const double factor = 1.0 + std::max(ceil_log2(_scaling_adjustment), 0.0);
+ const double target_scalar = (1 << 17)*_scaling_adjustment/_dsp_extra_scaling/factor;
+ const boost::int32_t actual_scalar = boost::math::iround(target_scalar);
+ _fxpt_scalar_correction = target_scalar/actual_scalar*factor; //should be small
+ _iface->poke32(REG_DSP_TX_SCALE_IQ, actual_scalar);
+ }
+
+ double get_scaling_adjustment(void){
+ return _fxpt_scalar_correction*_host_extra_scaling*32767.;
+ }
+
+ double set_freq(const double freq_){
+ //correct for outside of rate (wrap around)
+ double freq = std::fmod(freq_, _tick_rate);
+ if (std::abs(freq) > _tick_rate/2.0)
+ freq -= boost::math::sign(freq)*_tick_rate;
+
+ //calculate the freq register word (signed)
+ UHD_ASSERT_THROW(std::abs(freq) <= _tick_rate/2.0);
+ static const double scale_factor = std::pow(2.0, 32);
+ const boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / _tick_rate) * scale_factor));
+
+ //update the actual frequency
+ const double actual_freq = (double(freq_word) / scale_factor) * _tick_rate;
+
+ _iface->poke32(REG_DSP_TX_FREQ, boost::uint32_t(freq_word));
+
+ return actual_freq;
+ }
+
+ uhd::meta_range_t get_freq_range(void){
+ return uhd::meta_range_t(-_tick_rate/2, +_tick_rate/2, _tick_rate/std::pow(2.0, 32));
+ }
+
+ void set_updates(const size_t cycles_per_up, const size_t packets_per_up){
+ _iface->poke32(REG_TX_CTRL_CYCLES_PER_UP, (cycles_per_up == 0)? 0 : (FLAG_TX_CTRL_UP_ENB | cycles_per_up));
+ _iface->poke32(REG_TX_CTRL_PACKETS_PER_UP, (packets_per_up == 0)? 0 : (FLAG_TX_CTRL_UP_ENB | packets_per_up));
+ }
+
+ void setup(const uhd::stream_args_t &stream_args){
+ if (not stream_args.args.has_key("noclear")) this->clear();
+
+ unsigned format_word = 0;
+ if (stream_args.otw_format == "sc16"){
+ format_word = 0;
+ _dsp_extra_scaling = 1.0;
+ _host_extra_scaling = 1.0;
+ }
+ else if (stream_args.otw_format == "sc8"){
+ format_word = (1 << 0);
+ double peak = stream_args.args.cast<double>("peak", 1.0);
+ peak = std::max(peak, 1.0/256);
+ _host_extra_scaling = 1.0/peak/256;
+ _dsp_extra_scaling = 1.0/peak;
+ }
+ else throw uhd::value_error("USRP TX cannot handle requested wire format: " + stream_args.otw_format);
+
+ _host_extra_scaling /= stream_args.args.cast<double>("fullscale", 1.0);
+
+ this->update_scalar();
+
+ _iface->poke32(REG_TX_CTRL_FORMAT, format_word);
+
+ if (stream_args.args.has_key("underflow_policy")){
+ this->set_underflow_policy(stream_args.args["underflow_policy"]);
+ }
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _dsp_base, _ctrl_base;
+ double _tick_rate, _link_rate;
+ double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction;
+ const boost::uint32_t _sid;
+};
+
+tx_dsp_core_200::sptr tx_dsp_core_200::make(wb_iface::sptr iface, const size_t dsp_base, const size_t ctrl_base, const boost::uint32_t sid){
+ return sptr(new tx_dsp_core_200_impl(iface, dsp_base, ctrl_base, sid));
+}
diff --git a/host/lib/usrp/cores/tx_dsp_core_200.hpp b/host/lib/usrp/cores/tx_dsp_core_200.hpp
new file mode 100644
index 000000000..0e1cfb6bc
--- /dev/null
+++ b/host/lib/usrp/cores/tx_dsp_core_200.hpp
@@ -0,0 +1,59 @@
+//
+// Copyright 2011 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_LIBUHD_USRP_TX_DSP_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/stream.hpp>
+#include <uhd/types/ranges.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class tx_dsp_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<tx_dsp_core_200> sptr;
+
+ static sptr make(
+ wb_iface::sptr iface,
+ const size_t dsp_base, const size_t ctrl_base,
+ const boost::uint32_t sid
+ );
+
+ virtual void clear(void) = 0;
+
+ virtual void set_tick_rate(const double rate) = 0;
+
+ virtual void set_link_rate(const double rate) = 0;
+
+ virtual double set_host_rate(const double rate) = 0;
+
+ virtual uhd::meta_range_t get_host_rates(void) = 0;
+
+ virtual double get_scaling_adjustment(void) = 0;
+
+ virtual uhd::meta_range_t get_freq_range(void) = 0;
+
+ virtual double set_freq(const double freq) = 0;
+
+ virtual void set_updates(const size_t cycles_per_up, const size_t packets_per_up) = 0;
+
+ virtual void setup(const uhd::stream_args_t &stream_args) = 0;
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/tx_dsp_core_3000.cpp b/host/lib/usrp/cores/tx_dsp_core_3000.cpp
new file mode 100644
index 000000000..ff4392a13
--- /dev/null
+++ b/host/lib/usrp/cores/tx_dsp_core_3000.cpp
@@ -0,0 +1,181 @@
+//
+// 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
+// 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 "tx_dsp_core_3000.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/math/special_functions/sign.hpp>
+#include <boost/thread/thread.hpp> //sleep
+#include <algorithm>
+#include <cmath>
+
+#define REG_DSP_TX_FREQ _dsp_base + 0
+#define REG_DSP_TX_SCALE_IQ _dsp_base + 4
+#define REG_DSP_TX_INTERP _dsp_base + 8
+
+template <class T> T ceil_log2(T num){
+ return std::ceil(std::log(num)/std::log(T(2)));
+}
+
+using namespace uhd;
+
+class tx_dsp_core_3000_impl : public tx_dsp_core_3000{
+public:
+ tx_dsp_core_3000_impl(
+ wb_iface::sptr iface,
+ const size_t dsp_base
+ ):
+ _iface(iface), _dsp_base(dsp_base)
+ {
+ //init to something so update method has reasonable defaults
+ _scaling_adjustment = 1.0;
+ _dsp_extra_scaling = 1.0;
+ this->set_tick_rate(1.0);
+ }
+
+ void set_tick_rate(const double rate){
+ _tick_rate = rate;
+ }
+
+ void set_link_rate(const double rate){
+ //_link_rate = rate/sizeof(boost::uint32_t); //in samps/s
+ _link_rate = rate/sizeof(boost::uint16_t); //in samps/s (allows for 8sc)
+ }
+
+ uhd::meta_range_t get_host_rates(void){
+ meta_range_t range;
+ for (int rate = 512; rate > 256; rate -= 4){
+ range.push_back(range_t(_tick_rate/rate));
+ }
+ for (int rate = 256; rate > 128; rate -= 2){
+ range.push_back(range_t(_tick_rate/rate));
+ }
+ for (int rate = 128; rate >= int(std::ceil(_tick_rate/_link_rate)); rate -= 1){
+ range.push_back(range_t(_tick_rate/rate));
+ }
+ return range;
+ }
+
+ double set_host_rate(const double rate){
+ const size_t interp_rate = boost::math::iround(_tick_rate/this->get_host_rates().clip(rate, true));
+ size_t interp = interp_rate;
+
+ //determine which half-band filters are activated
+ int hb0 = 0, hb1 = 0;
+ if (interp % 2 == 0){
+ hb0 = 1;
+ interp /= 2;
+ }
+ if (interp % 2 == 0){
+ hb1 = 1;
+ interp /= 2;
+ }
+
+ _iface->poke32(REG_DSP_TX_INTERP, (hb1 << 9) | (hb0 << 8) | (interp & 0xff));
+
+ if (interp > 1 and hb0 == 0 and hb1 == 0)
+ {
+ UHD_MSG(warning) << boost::format(
+ "The requested interpolation is odd; the user should expect CIC rolloff.\n"
+ "Select an even interpolation to ensure that a halfband filter is enabled.\n"
+ "interpolation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n"
+ ) % interp_rate % (_tick_rate/1e6) % (rate/1e6);
+ }
+
+ // Calculate CIC interpolation (i.e., without halfband interpolators)
+ // Calculate closest multiplier constant to reverse gain absent scale multipliers
+ const double rate_pow = std::pow(double(interp & 0xff), 3);
+ _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*rate_pow);
+ this->update_scalar();
+
+ return _tick_rate/interp_rate;
+ }
+
+ void update_scalar(void){
+ const double factor = 1.0 + std::max(ceil_log2(_scaling_adjustment), 0.0);
+ const double target_scalar = (1 << 17)*_scaling_adjustment/_dsp_extra_scaling/factor;
+ const boost::int32_t actual_scalar = boost::math::iround(target_scalar);
+ _fxpt_scalar_correction = target_scalar/actual_scalar*factor; //should be small
+ _iface->poke32(REG_DSP_TX_SCALE_IQ, actual_scalar);
+ }
+
+ double get_scaling_adjustment(void){
+ return _fxpt_scalar_correction*_host_extra_scaling*32767.;
+ }
+
+ double set_freq(const double freq_){
+ //correct for outside of rate (wrap around)
+ double freq = std::fmod(freq_, _tick_rate);
+ if (std::abs(freq) > _tick_rate/2.0)
+ freq -= boost::math::sign(freq)*_tick_rate;
+
+ //calculate the freq register word (signed)
+ UHD_ASSERT_THROW(std::abs(freq) <= _tick_rate/2.0);
+ static const double scale_factor = std::pow(2.0, 32);
+ const boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / _tick_rate) * scale_factor));
+
+ //update the actual frequency
+ const double actual_freq = (double(freq_word) / scale_factor) * _tick_rate;
+
+ _iface->poke32(REG_DSP_TX_FREQ, boost::uint32_t(freq_word));
+
+ return actual_freq;
+ }
+
+ uhd::meta_range_t get_freq_range(void){
+ return uhd::meta_range_t(-_tick_rate/2, +_tick_rate/2, _tick_rate/std::pow(2.0, 32));
+ }
+
+ void setup(const uhd::stream_args_t &stream_args){
+
+ //unsigned format_word = 0;
+ if (stream_args.otw_format == "sc16"){
+ //format_word = 0;
+ _dsp_extra_scaling = 1.0;
+ _host_extra_scaling = 1.0;
+ }
+ /*
+ else if (stream_args.otw_format == "sc8"){
+ format_word = (1 << 0);
+ double peak = stream_args.args.cast<double>("peak", 1.0);
+ peak = std::max(peak, 1.0/256);
+ _host_extra_scaling = 1.0/peak/256;
+ _dsp_extra_scaling = 1.0/peak;
+ }
+ else throw uhd::value_error("USRP TX cannot handle requested wire format: " + stream_args.otw_format);
+ */
+
+ _host_extra_scaling /= stream_args.args.cast<double>("fullscale", 1.0);
+
+ this->update_scalar();
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _dsp_base;
+ double _tick_rate, _link_rate;
+ double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction;
+};
+
+tx_dsp_core_3000::sptr tx_dsp_core_3000::make(wb_iface::sptr iface, const size_t dsp_base)
+{
+ return sptr(new tx_dsp_core_3000_impl(iface, dsp_base));
+}
diff --git a/host/lib/usrp/cores/tx_dsp_core_3000.hpp b/host/lib/usrp/cores/tx_dsp_core_3000.hpp
new file mode 100644
index 000000000..eb5ffaf0f
--- /dev/null
+++ b/host/lib/usrp/cores/tx_dsp_core_3000.hpp
@@ -0,0 +1,54 @@
+//
+// 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
+// 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_TX_DSP_CORE_3000_HPP
+#define INCLUDED_LIBUHD_USRP_TX_DSP_CORE_3000_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/stream.hpp>
+#include <uhd/types/ranges.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class tx_dsp_core_3000 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<tx_dsp_core_3000> sptr;
+
+ static sptr make(
+ wb_iface::sptr iface,
+ const size_t dsp_base
+ );
+
+ virtual void set_tick_rate(const double rate) = 0;
+
+ virtual void set_link_rate(const double rate) = 0;
+
+ virtual double set_host_rate(const double rate) = 0;
+
+ virtual uhd::meta_range_t get_host_rates(void) = 0;
+
+ virtual double get_scaling_adjustment(void) = 0;
+
+ virtual uhd::meta_range_t get_freq_range(void) = 0;
+
+ virtual double set_freq(const double freq) = 0;
+
+ virtual void setup(const uhd::stream_args_t &stream_args) = 0;
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_TX_DSP_CORE_3000_HPP */
diff --git a/host/lib/usrp/cores/tx_frontend_core_200.cpp b/host/lib/usrp/cores/tx_frontend_core_200.cpp
new file mode 100644
index 000000000..e35874173
--- /dev/null
+++ b/host/lib/usrp/cores/tx_frontend_core_200.cpp
@@ -0,0 +1,76 @@
+//
+// Copyright 2011 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 "tx_frontend_core_200.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/exception.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/math/special_functions/round.hpp>
+
+#define REG_TX_FE_DC_OFFSET_I _base + 0 //24 bits
+#define REG_TX_FE_DC_OFFSET_Q _base + 4 //24 bits
+#define REG_TX_FE_MAG_CORRECTION _base + 8 //18 bits
+#define REG_TX_FE_PHASE_CORRECTION _base + 12 //18 bits
+#define REG_TX_FE_MUX _base + 16 //8 bits (std output = 0x10, reversed = 0x01)
+
+static boost::uint32_t fs_to_bits(const double num, const size_t bits){
+ return boost::int32_t(boost::math::round(num * (1 << (bits-1))));
+}
+
+
+class tx_frontend_core_200_impl : public tx_frontend_core_200{
+public:
+ tx_frontend_core_200_impl(wb_iface::sptr iface, const size_t base):
+ _iface(iface), _base(base)
+ {
+ //NOP
+ }
+
+ void set_mux(const std::string &mode){
+ static const uhd::dict<std::string, boost::uint32_t> mode_to_mux = boost::assign::map_list_of
+ ("IQ", (0x1 << 4) | (0x0 << 0)) //DAC0Q=DUC0Q, DAC0I=DUC0I
+ ("QI", (0x0 << 4) | (0x1 << 0)) //DAC0Q=DUC0I, DAC0I=DUC0Q
+ ("I", (0xf << 4) | (0x0 << 0)) //DAC0Q=ZERO, DAC0I=DUC0I
+ ("Q", (0x0 << 4) | (0xf << 0)) //DAC0Q=DUC0I, DAC0I=ZERO
+ ;
+ _iface->poke32(REG_TX_FE_MUX, mode_to_mux[mode]);
+ }
+
+ std::complex<double> set_dc_offset(const std::complex<double> &off){
+ static const double scaler = double(1ul << 23);
+ const boost::int32_t i_dc_off = boost::math::iround(off.real()*scaler);
+ const boost::int32_t q_dc_off = boost::math::iround(off.imag()*scaler);
+
+ _iface->poke32(REG_TX_FE_DC_OFFSET_I, i_dc_off);
+ _iface->poke32(REG_TX_FE_DC_OFFSET_Q, q_dc_off);
+
+ return std::complex<double>(i_dc_off/scaler, q_dc_off/scaler);
+ }
+
+ void set_iq_balance(const std::complex<double> &cor){
+ _iface->poke32(REG_TX_FE_MAG_CORRECTION, fs_to_bits(cor.real(), 18));
+ _iface->poke32(REG_TX_FE_PHASE_CORRECTION, fs_to_bits(cor.imag(), 18));
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _base;
+};
+
+tx_frontend_core_200::sptr tx_frontend_core_200::make(wb_iface::sptr iface, const size_t base){
+ return sptr(new tx_frontend_core_200_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/tx_frontend_core_200.hpp b/host/lib/usrp/cores/tx_frontend_core_200.hpp
new file mode 100644
index 000000000..8ee0f3e6d
--- /dev/null
+++ b/host/lib/usrp/cores/tx_frontend_core_200.hpp
@@ -0,0 +1,42 @@
+//
+// Copyright 2011 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_LIBUHD_USRP_RX_FRONTEND_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_RX_FRONTEND_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+#include <complex>
+#include <string>
+
+class tx_frontend_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<tx_frontend_core_200> sptr;
+
+ static sptr make(wb_iface::sptr iface, const size_t base);
+
+ virtual void set_mux(const std::string &mode) = 0;
+
+ virtual std::complex<double> set_dc_offset(const std::complex<double> &off) = 0;
+
+ virtual void set_iq_balance(const std::complex<double> &cor) = 0;
+
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_RX_FRONTEND_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/tx_vita_core_3000.cpp b/host/lib/usrp/cores/tx_vita_core_3000.cpp
new file mode 100644
index 000000000..38eb6afb5
--- /dev/null
+++ b/host/lib/usrp/cores/tx_vita_core_3000.cpp
@@ -0,0 +1,107 @@
+//
+// 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/>.
+//
+
+#include "tx_vita_core_3000.hpp"
+#include <uhd/utils/safe_call.hpp>
+
+#define REG_CTRL_ERROR_POLICY _base + 0
+#define REG_DEFRAMER_CYCLE_FC_UPS _base + 2*4 + 0
+#define REG_DEFRAMER_PACKET_FC_UPS _base + 2*4 + 4
+
+using namespace uhd;
+
+struct tx_vita_core_3000_impl : tx_vita_core_3000
+{
+ tx_vita_core_3000_impl(
+ wb_iface::sptr iface,
+ const size_t base
+ ):
+ _iface(iface),
+ _base(base)
+ {
+ this->set_tick_rate(1); //init to non zero
+ this->set_underflow_policy("next_packet");
+ this->clear();
+ }
+
+ ~tx_vita_core_3000_impl(void)
+ {
+ UHD_SAFE_CALL
+ (
+ this->clear();
+ )
+ }
+
+ void clear(void)
+ {
+ this->configure_flow_control(0, 0);
+ this->set_underflow_policy(_policy); //clears the seq
+ }
+
+ void set_tick_rate(const double rate)
+ {
+ _tick_rate = rate;
+ }
+
+ void set_underflow_policy(const std::string &policy)
+ {
+ if (policy == "next_packet")
+ {
+ _iface->poke32(REG_CTRL_ERROR_POLICY, (1 << 1));
+ }
+ else if (policy == "next_burst")
+ {
+ _iface->poke32(REG_CTRL_ERROR_POLICY, (1 << 2));
+ }
+ else if (policy == "wait")
+ {
+ _iface->poke32(REG_CTRL_ERROR_POLICY, (1 << 0));
+ }
+ else throw uhd::value_error("USRP TX cannot handle requested underflow policy: " + policy);
+ _policy = policy;
+ }
+
+ void setup(const uhd::stream_args_t &stream_args)
+ {
+ if (stream_args.args.has_key("underflow_policy"))
+ {
+ this->set_underflow_policy(stream_args.args["underflow_policy"]);
+ }
+ }
+
+ void configure_flow_control(const size_t cycs_per_up, const size_t pkts_per_up)
+ {
+ if (cycs_per_up == 0) _iface->poke32(REG_DEFRAMER_CYCLE_FC_UPS, 0);
+ else _iface->poke32(REG_DEFRAMER_CYCLE_FC_UPS, (1 << 31) | ((cycs_per_up) & 0xffffff));
+
+ if (pkts_per_up == 0) _iface->poke32(REG_DEFRAMER_PACKET_FC_UPS, 0);
+ else _iface->poke32(REG_DEFRAMER_PACKET_FC_UPS, (1 << 31) | ((pkts_per_up) & 0xffff));
+ }
+
+ wb_iface::sptr _iface;
+ const size_t _base;
+ double _tick_rate;
+ std::string _policy;
+};
+
+tx_vita_core_3000::sptr tx_vita_core_3000::make(
+ wb_iface::sptr iface,
+ const size_t base
+)
+{
+ return tx_vita_core_3000::sptr(new tx_vita_core_3000_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/tx_vita_core_3000.hpp b/host/lib/usrp/cores/tx_vita_core_3000.hpp
new file mode 100644
index 000000000..2070936ce
--- /dev/null
+++ b/host/lib/usrp/cores/tx_vita_core_3000.hpp
@@ -0,0 +1,49 @@
+//
+// 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_LIBUHD_USRP_TX_VITA_CORE_3000_HPP
+#define INCLUDED_LIBUHD_USRP_TX_VITA_CORE_3000_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/stream.hpp>
+#include <uhd/types/ranges.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <uhd/types/stream_cmd.hpp>
+#include "wb_iface.hpp"
+#include <string>
+
+class tx_vita_core_3000 : boost::noncopyable
+{
+public:
+ typedef boost::shared_ptr<tx_vita_core_3000> sptr;
+
+ static sptr make(
+ wb_iface::sptr iface,
+ const size_t base
+ );
+
+ virtual void clear(void) = 0;
+
+ virtual void set_tick_rate(const double rate) = 0;
+
+ virtual void setup(const uhd::stream_args_t &stream_args) = 0;
+
+ virtual void configure_flow_control(const size_t cycs_per_up, const size_t pkts_per_up) = 0;
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_TX_VITA_CORE_3000_HPP */
diff --git a/host/lib/usrp/cores/user_settings_core_200.cpp b/host/lib/usrp/cores/user_settings_core_200.cpp
new file mode 100644
index 000000000..d262631b1
--- /dev/null
+++ b/host/lib/usrp/cores/user_settings_core_200.cpp
@@ -0,0 +1,43 @@
+//
+// Copyright 2012 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 "user_settings_core_200.hpp"
+
+#define REG_USER_ADDR _base + 0
+#define REG_USER_DATA _base + 4
+
+class user_settings_core_200_impl : public user_settings_core_200{
+public:
+ user_settings_core_200_impl(wb_iface::sptr iface, const size_t base):
+ _iface(iface), _base(base)
+ {
+ //NOP
+ }
+
+ void set_reg(const user_reg_t &reg){
+ _iface->poke32(REG_USER_ADDR, reg.first);
+ _iface->poke32(REG_USER_DATA, reg.second);
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _base;
+};
+
+user_settings_core_200::sptr user_settings_core_200::make(wb_iface::sptr iface, const size_t base){
+ return sptr(new user_settings_core_200_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/user_settings_core_200.hpp b/host/lib/usrp/cores/user_settings_core_200.hpp
new file mode 100644
index 000000000..1f5d13de7
--- /dev/null
+++ b/host/lib/usrp/cores/user_settings_core_200.hpp
@@ -0,0 +1,36 @@
+//
+// Copyright 2012 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_LIBUHD_USRP_USER_SETTINGS_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_USER_SETTINGS_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class user_settings_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<user_settings_core_200> sptr;
+ typedef std::pair<boost::uint8_t, boost::uint32_t> user_reg_t;
+
+ static sptr make(wb_iface::sptr iface, const size_t base);
+
+ virtual void set_reg(const user_reg_t &reg) = 0;
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_USER_SETTINGS_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/wb_iface.cpp b/host/lib/usrp/cores/wb_iface.cpp
new file mode 100644
index 000000000..9aa6d18d4
--- /dev/null
+++ b/host/lib/usrp/cores/wb_iface.cpp
@@ -0,0 +1,51 @@
+//
+// 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/>.
+//
+
+#include "wb_iface.hpp"
+#include <uhd/exception.hpp>
+
+using namespace uhd;
+
+void wb_iface::poke64(const wb_iface::wb_addr_type, const boost::uint64_t)
+{
+ throw uhd::not_implemented_error("poke64 not implemented");
+}
+
+boost::uint64_t wb_iface::peek64(const wb_iface::wb_addr_type)
+{
+ throw uhd::not_implemented_error("peek64 not implemented");
+}
+
+void wb_iface::poke32(const wb_iface::wb_addr_type, const boost::uint32_t)
+{
+ throw uhd::not_implemented_error("poke32 not implemented");
+}
+
+boost::uint32_t wb_iface::peek32(const wb_iface::wb_addr_type)
+{
+ throw uhd::not_implemented_error("peek32 not implemented");
+}
+
+void wb_iface::poke16(const wb_iface::wb_addr_type, const boost::uint16_t)
+{
+ throw uhd::not_implemented_error("poke16 not implemented");
+}
+
+boost::uint16_t wb_iface::peek16(const wb_iface::wb_addr_type)
+{
+ throw uhd::not_implemented_error("peek16 not implemented");
+}
diff --git a/host/lib/usrp/cores/wb_iface.hpp b/host/lib/usrp/cores/wb_iface.hpp
new file mode 100644
index 000000000..197788180
--- /dev/null
+++ b/host/lib/usrp/cores/wb_iface.hpp
@@ -0,0 +1,75 @@
+//
+// 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
+// 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_WB_IFACE_HPP
+#define INCLUDED_LIBUHD_USRP_WB_IFACE_HPP
+
+#include <uhd/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/shared_ptr.hpp>
+
+class /*UHD_API*/ wb_iface
+{
+public:
+ typedef boost::shared_ptr<wb_iface> sptr;
+ typedef boost::uint32_t wb_addr_type;
+
+ /*!
+ * Write a register (64 bits)
+ * \param addr the address
+ * \param data the 64bit data
+ */
+ virtual void poke64(const wb_addr_type addr, const boost::uint64_t data);
+
+ /*!
+ * Read a register (64 bits)
+ * \param addr the address
+ * \return the 64bit data
+ */
+ virtual boost::uint64_t peek64(const wb_addr_type addr);
+
+ /*!
+ * Write a register (32 bits)
+ * \param addr the address
+ * \param data the 32bit data
+ */
+ virtual void poke32(const wb_addr_type addr, const boost::uint32_t data);
+
+ /*!
+ * Read a register (32 bits)
+ * \param addr the address
+ * \return the 32bit data
+ */
+ virtual boost::uint32_t peek32(const wb_addr_type addr);
+
+ /*!
+ * Write a register (16 bits)
+ * \param addr the address
+ * \param data the 16bit data
+ */
+ virtual void poke16(const wb_addr_type addr, const boost::uint16_t data);
+
+ /*!
+ * Read a register (16 bits)
+ * \param addr the address
+ * \return the 16bit data
+ */
+ virtual boost::uint16_t peek16(const wb_addr_type addr);
+
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_WB_IFACE_HPP */