aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp')
-rw-r--r--host/lib/usrp/CMakeLists.txt27
-rw-r--r--host/lib/usrp/dboard/CMakeLists.txt26
-rw-r--r--host/lib/usrp/dboard/db_basic_and_lf.cpp20
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp18
-rw-r--r--host/lib/usrp/dboard/db_wbx.cpp613
-rw-r--r--host/lib/usrp/dboard/db_xcvr2450.cpp13
-rw-r--r--host/lib/usrp/dboard_base.cpp42
-rw-r--r--host/lib/usrp/dboard_ctor_args.hpp32
-rw-r--r--host/lib/usrp/dboard_eeprom.cpp13
-rw-r--r--host/lib/usrp/dboard_id.cpp68
-rw-r--r--host/lib/usrp/dboard_manager.cpp75
-rw-r--r--host/lib/usrp/usrp2/CMakeLists.txt29
-rw-r--r--host/lib/usrp/usrp2/dboard_iface.cpp57
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp24
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp3
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp32
16 files changed, 951 insertions, 141 deletions
diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt
new file mode 100644
index 000000000..39a72ab37
--- /dev/null
+++ b/host/lib/usrp/CMakeLists.txt
@@ -0,0 +1,27 @@
+#
+# Copyright 2010 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 will be included by cmake, use absolute paths!
+
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_base.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_eeprom.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_id.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_manager.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp
+)
diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt
new file mode 100644
index 000000000..3a6c2d84a
--- /dev/null
+++ b/host/lib/usrp/dboard/CMakeLists.txt
@@ -0,0 +1,26 @@
+#
+# Copyright 2010 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 will be included by cmake, use absolute paths!
+
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_basic_and_lf.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_rfx.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_xcvr2450.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_wbx.cpp
+)
+
diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp
index b0fbbd2ec..23ac98872 100644
--- a/host/lib/usrp/dboard/db_basic_and_lf.cpp
+++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp
@@ -34,7 +34,7 @@ using namespace boost::assign;
**********************************************************************/
class basic_rx : public rx_dboard_base{
public:
- basic_rx(ctor_args_t const& args, double max_freq);
+ basic_rx(ctor_args_t args, double max_freq);
~basic_rx(void);
void rx_get(const wax::obj &key, wax::obj &val);
@@ -46,7 +46,7 @@ private:
class basic_tx : public tx_dboard_base{
public:
- basic_tx(ctor_args_t const& args, double max_freq);
+ basic_tx(ctor_args_t args, double max_freq);
~basic_tx(void);
void tx_get(const wax::obj &key, wax::obj &val);
@@ -59,19 +59,19 @@ private:
/***********************************************************************
* Register the basic and LF dboards
**********************************************************************/
-static dboard_base::sptr make_basic_rx(dboard_base::ctor_args_t const& args){
+static dboard_base::sptr make_basic_rx(dboard_base::ctor_args_t args){
return dboard_base::sptr(new basic_rx(args, 90e9));
}
-static dboard_base::sptr make_basic_tx(dboard_base::ctor_args_t const& args){
+static dboard_base::sptr make_basic_tx(dboard_base::ctor_args_t args){
return dboard_base::sptr(new basic_tx(args, 90e9));
}
-static dboard_base::sptr make_lf_rx(dboard_base::ctor_args_t const& args){
+static dboard_base::sptr make_lf_rx(dboard_base::ctor_args_t args){
return dboard_base::sptr(new basic_rx(args, 32e6));
}
-static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t const& args){
+static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t args){
return dboard_base::sptr(new basic_tx(args, 32e6));
}
@@ -85,7 +85,7 @@ UHD_STATIC_BLOCK(reg_basic_and_lf_dboards){
/***********************************************************************
* Basic and LF RX dboard
**********************************************************************/
-basic_rx::basic_rx(ctor_args_t const& args, double max_freq) : rx_dboard_base(args){
+basic_rx::basic_rx(ctor_args_t args, double max_freq) : rx_dboard_base(args){
_max_freq = max_freq;
}
@@ -101,7 +101,7 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_NAME:
val = std::string(str(boost::format("%s - %s")
- % dboard_id::to_string(get_rx_id())
+ % get_rx_id().to_pp_string()
% get_subdev_name()
));
return;
@@ -187,7 +187,7 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){
/***********************************************************************
* Basic and LF TX dboard
**********************************************************************/
-basic_tx::basic_tx(ctor_args_t const& args, double max_freq) : tx_dboard_base(args){
+basic_tx::basic_tx(ctor_args_t args, double max_freq) : tx_dboard_base(args){
_max_freq = max_freq;
}
@@ -202,7 +202,7 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){
//handle the get request conditioned on the key
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_NAME:
- val = dboard_id::to_string(get_tx_id());
+ val = get_tx_id().to_pp_string();
return;
case SUBDEV_PROP_OTHERS:
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index 175f55eab..bbc9716b1 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -63,7 +63,7 @@ static const float _max_rx_pga0_gain = 45;
class rfx_xcvr : public xcvr_dboard_base{
public:
rfx_xcvr(
- ctor_args_t const& args,
+ ctor_args_t args,
const freq_range_t &freq_range,
bool rx_div2, bool tx_div2
);
@@ -108,23 +108,23 @@ private:
/***********************************************************************
* Register the RFX dboards (min freq, max freq, rx div2, tx div2)
**********************************************************************/
-static dboard_base::sptr make_rfx_flex400(dboard_base::ctor_args_t const& args){
+static dboard_base::sptr make_rfx_flex400(dboard_base::ctor_args_t args){
return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(400e6, 500e6), false, true));
}
-static dboard_base::sptr make_rfx_flex900(dboard_base::ctor_args_t const& args){
+static dboard_base::sptr make_rfx_flex900(dboard_base::ctor_args_t args){
return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(750e6, 1050e6), true, true));
}
-static dboard_base::sptr make_rfx_flex1800(dboard_base::ctor_args_t const& args){
+static dboard_base::sptr make_rfx_flex1800(dboard_base::ctor_args_t args){
return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(1500e6, 2100e6), false, false));
}
-static dboard_base::sptr make_rfx_flex1200(dboard_base::ctor_args_t const& args){
+static dboard_base::sptr make_rfx_flex1200(dboard_base::ctor_args_t args){
return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(1150e6, 1450e6), true, true));
}
-static dboard_base::sptr make_rfx_flex2400(dboard_base::ctor_args_t const& args){
+static dboard_base::sptr make_rfx_flex2400(dboard_base::ctor_args_t args){
return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(2300e6, 2900e6), false, false));
}
@@ -149,7 +149,7 @@ UHD_STATIC_BLOCK(reg_rfx_dboards){
* Structors
**********************************************************************/
rfx_xcvr::rfx_xcvr(
- ctor_args_t const& args,
+ ctor_args_t args,
const freq_range_t &freq_range,
bool rx_div2, bool tx_div2
) : xcvr_dboard_base(args){
@@ -351,7 +351,7 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
//handle the get request conditioned on the key
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_NAME:
- val = dboard_id::to_string(get_rx_id());
+ val = get_rx_id().to_pp_string();
return;
case SUBDEV_PROP_OTHERS:
@@ -448,7 +448,7 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
//handle the get request conditioned on the key
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_NAME:
- val = dboard_id::to_string(get_tx_id());
+ val = get_tx_id().to_pp_string();
return;
case SUBDEV_PROP_OTHERS:
diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp
new file mode 100644
index 000000000..2a8a3a9f2
--- /dev/null
+++ b/host/lib/usrp/dboard/db_wbx.cpp
@@ -0,0 +1,613 @@
+//
+// Copyright 2010 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/>.
+//
+
+static const bool wbx_debug = false;
+
+// Common IO Pins
+#define ANTSW_IO ((1 << 5)|(1 << 15)) // on UNIT_TX, 0 = TX, 1 = RX, on UNIT_RX 0 = main ant, 1 = RX2
+#define ADF4350_CE (1 << 3)
+#define ADF4350_PDBRF (1 << 2)
+#define ADF4350_MUXOUT (1 << 1) // INPUT!!!
+#define LOCKDET_MASK (1 << 0) // INPUT!!!
+
+// TX IO Pins
+#define TX_PUP_5V (1 << 7) // enables 5.0V power supply
+#define TX_PUP_3V (1 << 6) // enables 3.3V supply
+#define TXMOD_EN (1 << 4) // on UNIT_TX, 1 enables TX Modulator
+
+// RX IO Pins
+#define RX_PUP_5V (1 << 7) // enables 5.0V power supply
+#define RX_PUP_3V (1 << 6) // enables 3.3V supply
+#define RXBB_PDB (1 << 4) // on UNIT_RX, 1 powers up RX baseband
+
+// RX Attenuator Pins
+#define RX_ATTN_SHIFT 8 // lsb of RX Attenuator Control
+#define RX_ATTN_MASK (63 << RX_ATTN_SHIFT) // valid bits of RX Attenuator Control
+
+// Mixer functions
+#define TX_MIXER_ENB (TXMOD_EN|ADF4350_PDBRF)
+#define TX_MIXER_DIS 0
+
+#define RX_MIXER_ENB (RXBB_PDB|ADF4350_PDBRF)
+#define RX_MIXER_DIS 0
+
+// Pin functions
+#define TX_POWER_IO (TX_PUP_5V|TX_PUP_3V) // high enables power supply
+#define TXIO_MASK (TX_POWER_IO|ANTSW_IO|ADF4350_CE|ADF4350_PDBRF|TXMOD_EN)
+
+#define RX_POWER_IO (RX_PUP_5V|RX_PUP_3V) // high enables power supply
+#define RXIO_MASK (RX_POWER_IO|ANTSW_IO|ADF4350_CE|ADF4350_PDBRF|RXBB_PDB|RX_ATTN_MASK)
+
+// Power functions
+#define TX_POWER_UP (TX_POWER_IO|ADF4350_CE)
+#define TX_POWER_DOWN 0
+
+#define RX_POWER_UP (RX_POWER_IO|ADF4350_CE)
+#define RX_POWER_DOWN 0
+
+// Antenna constants
+#define ANT_TX 0 //the tx line is transmitting
+#define ANT_RX ANTSW_IO //the tx line is receiving
+#define ANT_TXRX 0 //the rx line is on txrx
+#define ANT_RX2 ANTSW_IO //the rx line in on rx2
+#define ANT_XX 0 //dont care how the antenna is set
+
+#include "adf4350_regs.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/static.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <uhd/usrp/dboard_base.hpp>
+#include <uhd/usrp/dboard_manager.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
+#include <boost/math/special_functions/round.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
+
+/***********************************************************************
+ * The WBX dboard
+ **********************************************************************/
+static const float _max_rx_pga0_gain = 31.5;
+static const float _max_tx_pga0_gain = 25;
+
+class wbx_xcvr : public xcvr_dboard_base{
+public:
+ wbx_xcvr(
+ ctor_args_t args,
+ const freq_range_t &freq_range
+ );
+ ~wbx_xcvr(void);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ freq_range_t _freq_range;
+ uhd::dict<dboard_iface::unit_t, bool> _div2;
+ double _rx_lo_freq, _tx_lo_freq;
+ std::string _rx_ant;
+ int _rx_pga0_attn_iobits;
+ float _rx_pga0_gain;
+ float _tx_pga0_gain;
+
+ void set_rx_lo_freq(double freq);
+ void set_tx_lo_freq(double freq);
+ void set_rx_ant(const std::string &ant);
+ void set_rx_pga0_gain(float gain);
+ void set_rx_pga0_attn(float attn);
+ void set_tx_pga0_gain(float gain);
+
+ void update_atr(void);
+
+ /*!
+ * Set the LO frequency for the particular dboard unit.
+ * \param unit which unit rx or tx
+ * \param target_freq the desired frequency in Hz
+ * \return the actual frequency in Hz
+ */
+ double set_lo_freq(dboard_iface::unit_t unit, double target_freq);
+
+ /*!
+ * Get the lock detect status of the LO.
+ * \param unit which unit rx or tx
+ * \return true for locked
+ */
+ bool get_locked(dboard_iface::unit_t unit){
+ return (this->get_iface()->read_gpio(unit) & LOCKDET_MASK) != 0;
+ }
+};
+
+/***********************************************************************
+ * Register the WBX dboard (min freq, max freq, rx div2, tx div2)
+ **********************************************************************/
+static dboard_base::sptr make_wbx(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new wbx_xcvr(args, freq_range_t(50e6, 2220e6)));
+}
+
+UHD_STATIC_BLOCK(reg_wbx_dboards){
+ dboard_manager::register_dboard(0x0052, &make_wbx, "WBX RX");
+ dboard_manager::register_dboard(0x0053, &make_wbx, "WBX TX");
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+wbx_xcvr::wbx_xcvr(
+ ctor_args_t args,
+ const freq_range_t &freq_range
+) : xcvr_dboard_base(args){
+ _freq_range = freq_range;
+
+ //enable the clocks that we need
+ this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);
+ this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true);
+
+ //set the gpio directions
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TXIO_MASK);
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RXIO_MASK);
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX GPIO Direction: RX: 0x%08x, TX: 0x%08x"
+ ) % RXIO_MASK % TXIO_MASK << std::endl;
+
+ //set some default values
+ set_rx_lo_freq((_freq_range.min + _freq_range.max)/2.0);
+ set_tx_lo_freq((_freq_range.min + _freq_range.max)/2.0);
+ set_rx_ant("RX2");
+ set_rx_pga0_gain(0);
+ set_tx_pga0_gain(0);
+}
+
+wbx_xcvr::~wbx_xcvr(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Helper Methods
+ **********************************************************************/
+void wbx_xcvr::update_atr(void){
+ //calculate atr pins
+
+ //setup the tx atr (this does not change with antenna)
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, TX_POWER_UP | ANT_XX | TX_MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, TX_POWER_UP | ANT_RX | TX_MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, TX_POWER_UP | ANT_TX | TX_MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, TX_POWER_UP | ANT_TX | TX_MIXER_ENB);
+
+ //setup the rx atr (this does not change with antenna)
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE,
+ _rx_pga0_attn_iobits | RX_POWER_UP | ANT_XX | RX_MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,
+ _rx_pga0_attn_iobits | RX_POWER_UP | ANT_XX | RX_MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX,
+ _rx_pga0_attn_iobits | RX_POWER_UP | ANT_RX2| RX_MIXER_ENB);
+
+ //set the rx atr regs that change with antenna setting
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,
+ _rx_pga0_attn_iobits | RX_POWER_UP | RX_MIXER_ENB | ((_rx_ant == "TX/RX")? ANT_TXRX : ANT_RX2));
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX RXONLY ATR REG: 0x%08x"
+ ) % (_rx_pga0_attn_iobits | RX_POWER_UP | RX_MIXER_ENB | ((_rx_ant == "TX/RX")? ANT_TXRX : ANT_RX2)) << std::endl;
+}
+
+void wbx_xcvr::set_rx_lo_freq(double freq){
+ _rx_lo_freq = set_lo_freq(dboard_iface::UNIT_RX, freq);
+}
+
+void wbx_xcvr::set_tx_lo_freq(double freq){
+ _tx_lo_freq = set_lo_freq(dboard_iface::UNIT_TX, freq);
+}
+
+void wbx_xcvr::set_rx_ant(const std::string &ant){
+ //validate input
+ UHD_ASSERT_THROW(ant == "TX/RX" or ant == "RX2");
+
+ //shadow the setting
+ _rx_ant = ant;
+
+ //write the new antenna setting to atr regs
+ update_atr();
+}
+
+void wbx_xcvr::set_rx_pga0_gain(float gain){
+ //clip the input
+ gain = std::clip<float>(gain, 0, _max_rx_pga0_gain);
+
+ //shadow the setting (does not account for precision loss)
+ _rx_pga0_gain = gain;
+
+ //convert to attenuation and update iobits for atr
+ set_rx_pga0_attn(_max_rx_pga0_gain - gain);
+
+ //write the new gain to atr regs
+ update_atr();
+}
+
+void wbx_xcvr::set_rx_pga0_attn(float attn)
+{
+ int attn_code = int(floor(attn*2));
+ _rx_pga0_attn_iobits = ((~attn_code) << RX_ATTN_SHIFT) & RX_ATTN_MASK;
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX Attenuation: %f dB, Code: %d, IO Bits %x, Mask: %x"
+ ) % attn % attn_code % (_rx_pga0_attn_iobits & RX_ATTN_MASK) % RX_ATTN_MASK << std::endl;
+}
+
+void wbx_xcvr::set_tx_pga0_gain(float gain){
+ //clip the input
+ gain = std::clip<float>(gain, 0, _max_tx_pga0_gain);
+
+ //voltage level constants
+ static const float max_volts = float(0.5), min_volts = float(1.4);
+ static const float slope = (max_volts-min_volts)/_max_rx_pga0_gain;
+
+ //calculate the voltage for the aux dac
+ float dac_volts = gain*slope + min_volts;
+
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX TX Gain: %f dB, dac_volts: %f V"
+ ) % gain % dac_volts << std::endl;
+
+ //write the new voltage to the aux dac
+ this->get_iface()->write_aux_dac(dboard_iface::UNIT_TX, 0, dac_volts);
+
+ //shadow the setting (does not account for precision loss)
+ _tx_pga0_gain = gain;
+}
+
+double wbx_xcvr::set_lo_freq(
+ dboard_iface::unit_t unit,
+ double target_freq
+){
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX tune: target frequency %f Mhz"
+ ) % (target_freq/1e6) << std::endl;
+
+ //clip the input
+ target_freq = std::clip(target_freq, _freq_range.min, _freq_range.max);
+
+ //map prescaler setting to mininmum integer divider (N) values (pg.18 prescaler)
+ static const uhd::dict<int, int> prescaler_to_min_int_div = map_list_of
+ (0,23) //adf4350_regs_t::PRESCALER_4_5
+ (1,75) //adf4350_regs_t::PRESCALER_8_9
+ ;
+
+ //map rf divider select output dividers to enums
+ static const uhd::dict<int, adf4350_regs_t::rf_divider_select_t> rfdivsel_to_enum = map_list_of
+ (1, adf4350_regs_t::RF_DIVIDER_SELECT_DIV1)
+ (2, adf4350_regs_t::RF_DIVIDER_SELECT_DIV2)
+ (4, adf4350_regs_t::RF_DIVIDER_SELECT_DIV4)
+ (8, adf4350_regs_t::RF_DIVIDER_SELECT_DIV8)
+ (16, adf4350_regs_t::RF_DIVIDER_SELECT_DIV16)
+ ;
+
+ double actual_freq, pfd_freq;
+ double ref_freq = this->get_iface()->get_clock_rate(unit);
+ int R, BS, N, FRAC, MOD;
+ int RFdiv = 1;
+ adf4350_regs_t::reference_divide_by_2_t T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED;
+ adf4350_regs_t::reference_doubler_t D = adf4350_regs_t::REFERENCE_DOUBLER_DISABLED;
+
+ //Reference doubler for 50% duty cycle
+ // if ref_freq < 12.5MHz enable regs.reference_divide_by_2
+ if(ref_freq <= 12.5e6) D = adf4350_regs_t::REFERENCE_DOUBLER_ENABLED;
+
+ //increase RF divider until acceptable VCO frequency
+ //start with target_freq*2 because mixer has divide by 2
+ double vco_freq = target_freq*2;
+ while (vco_freq < 2.2e9) {
+ vco_freq *= 2;
+ RFdiv *= 2;
+ }
+
+ //use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler)
+ adf4350_regs_t::prescaler_t prescaler = vco_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;
+
+ /*
+ * The goal here is to loop though possible R dividers,
+ * band select clock dividers, N (int) dividers, and FRAC
+ * (frac) dividers.
+ *
+ * Calculate the N and F dividers for each set of values.
+ * The loop exists when it meets all of the constraints.
+ * The resulting loop values are loaded into the registers.
+ *
+ * from pg.21
+ *
+ * f_pfd = f_ref*(1+D)/(R*(1+T))
+ * f_vco = (N + (FRAC/MOD))*f_pfd
+ * N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD
+ * f_rf = f_vco/RFdiv)
+ * f_actual = f_rf/2
+ */
+ for(R = 1; R <= 1023; R+=1){
+ //PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T)
+ pfd_freq = ref_freq*(1+D)/(R*(1+T));
+
+ //keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth)
+ if (pfd_freq > 25e6) continue;
+
+ //ignore fractional part of tuning
+ N = int(std::floor(vco_freq/pfd_freq));
+
+ //keep N > minimum int divider requirement
+ if (N < prescaler_to_min_int_div[prescaler]) continue;
+
+ for(BS=1; BS <= 255; BS+=1){
+ //keep the band select frequency at or below 100KHz
+ //constraint on band select clock
+ if (pfd_freq/BS > 100e3) continue;
+ goto done_loop;
+ }
+ } done_loop:
+
+ //Fractional-N calculation
+ MOD = 4095; //max fractional accuracy
+ FRAC = int((vco_freq/pfd_freq - N)*MOD);
+
+ //Reference divide-by-2 for 50% duty cycle
+ // if R even, move one divide by 2 to to regs.reference_divide_by_2
+ if(R % 2 == 0){
+ T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED;
+ R /= 2;
+ }
+
+ //actual frequency calculation
+ actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))/RFdiv/2);
+
+
+ if (wbx_debug) {
+ std::cerr << boost::format("WBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl;
+
+ std::cerr << boost::format("WBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d, LD=%d"
+ ) % R % BS % N % FRAC % MOD % T % D % RFdiv % get_locked(unit)<< std::endl
+ << boost::format("WBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f"
+ ) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl;
+ }
+
+ //load the register values
+ adf4350_regs_t regs;
+
+ regs.frac_12_bit = FRAC;
+ regs.int_16_bit = N;
+ regs.mod_12_bit = MOD;
+ regs.prescaler = prescaler;
+ regs.r_counter_10_bit = R;
+ regs.reference_divide_by_2 = T;
+ regs.reference_doubler = D;
+ regs.band_select_clock_div = BS;
+ regs.rf_divider_select = rfdivsel_to_enum[RFdiv];
+
+ //write the registers
+ //correct power-up sequence to write registers (5, 4, 3, 2, 1, 0)
+ int addr;
+
+ for(addr=5; addr>=0; addr--){
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX SPI Reg (0x%02x): 0x%08x"
+ ) % addr % regs.get_reg(addr) << std::endl;
+ this->get_iface()->write_spi(
+ unit, spi_config_t::EDGE_RISE,
+ regs.get_reg(addr), 32
+ );
+ }
+
+ //return the actual frequency
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX tune: actual frequency %f Mhz"
+ ) % (actual_freq/1e6) << std::endl;
+ return actual_freq;
+}
+
+/***********************************************************************
+ * RX Get and Set
+ **********************************************************************/
+void wbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = get_rx_id().to_pp_string();
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ UHD_ASSERT_THROW(name == "PGA0");
+ val = _rx_pga0_gain;
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ UHD_ASSERT_THROW(name == "PGA0");
+ val = gain_range_t(0, _max_rx_pga0_gain, float(0.5));
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(1, "PGA0");
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _rx_lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = _freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = _rx_ant;
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:{
+ prop_names_t ants = list_of("TX/RX")("RX2");
+ val = ants;
+ }
+ return;
+
+ case SUBDEV_PROP_QUADRATURE:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_LO_LOCKED:
+ val = this->get_locked(dboard_iface::UNIT_RX);
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void wbx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ set_rx_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ UHD_ASSERT_THROW(name == "PGA0");
+ set_rx_pga0_gain(val.as<float>());
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ set_rx_ant(val.as<std::string>());
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
+
+/***********************************************************************
+ * TX Get and Set
+ **********************************************************************/
+void wbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = get_tx_id().to_pp_string();
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ UHD_ASSERT_THROW(name == "PGA0");
+ val = _tx_pga0_gain;
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ UHD_ASSERT_THROW(name == "PGA0");
+ val = gain_range_t(0, _max_tx_pga0_gain, float(0.05));
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(1, "PGA0");
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _tx_lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = _freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("TX/RX");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = prop_names_t(1, "TX/RX");
+ return;
+
+ case SUBDEV_PROP_QUADRATURE:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_LO_LOCKED:
+ val = this->get_locked(dboard_iface::UNIT_TX);
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void wbx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ set_tx_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ UHD_ASSERT_THROW(name == "PGA0");
+ set_tx_pga0_gain(val.as<float>());
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ //its always set to tx/rx, so we only allow this value
+ UHD_ASSERT_THROW(val.as<std::string>() == "TX/RX");
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp
index 0dfef2a0a..3472229f4 100644
--- a/host/lib/usrp/dboard/db_xcvr2450.cpp
+++ b/host/lib/usrp/dboard/db_xcvr2450.cpp
@@ -89,7 +89,7 @@ static const uhd::dict<std::string, gain_range_t> xcvr_rx_gain_ranges = map_list
**********************************************************************/
class xcvr2450 : public xcvr_dboard_base{
public:
- xcvr2450(ctor_args_t const& args);
+ xcvr2450(ctor_args_t args);
~xcvr2450(void);
void rx_get(const wax::obj &key, wax::obj &val);
@@ -152,7 +152,7 @@ private:
/***********************************************************************
* Register the XCVR 2450 dboard
**********************************************************************/
-static dboard_base::sptr make_xcvr2450(dboard_base::ctor_args_t const& args){
+static dboard_base::sptr make_xcvr2450(dboard_base::ctor_args_t args){
return dboard_base::sptr(new xcvr2450(args));
}
@@ -165,7 +165,7 @@ UHD_STATIC_BLOCK(reg_xcvr2450_dboard){
/***********************************************************************
* Structors
**********************************************************************/
-xcvr2450::xcvr2450(ctor_args_t const& args) : xcvr_dboard_base(args){
+xcvr2450::xcvr2450(ctor_args_t args) : xcvr_dboard_base(args){
//enable only the clocks we need
this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);
@@ -373,8 +373,7 @@ static max2829_regs_t::tx_baseband_gain_t gain_to_tx_bb_reg(float &gain){
gain = 5;
return max2829_regs_t::TX_BASEBAND_GAIN_5DB;
}
- BOOST_THROW_EXCEPTION(std::runtime_error("should not get here"));
- return max2829_regs_t::TX_BASEBAND_GAIN_0DB;
+ UHD_ASSERT_THROW(false);
}
/*!
@@ -444,7 +443,7 @@ void xcvr2450::rx_get(const wax::obj &key_, wax::obj &val){
//handle the get request conditioned on the key
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_NAME:
- val = dboard_id::to_string(get_rx_id());
+ val = get_rx_id().to_pp_string();
return;
case SUBDEV_PROP_OTHERS:
@@ -542,7 +541,7 @@ void xcvr2450::tx_get(const wax::obj &key_, wax::obj &val){
//handle the get request conditioned on the key
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_NAME:
- val = dboard_id::to_string(get_tx_id());
+ val = get_tx_id().to_pp_string();
return;
case SUBDEV_PROP_OTHERS:
diff --git a/host/lib/usrp/dboard_base.cpp b/host/lib/usrp/dboard_base.cpp
index 68e4743d1..bd4b37ef3 100644
--- a/host/lib/usrp/dboard_base.cpp
+++ b/host/lib/usrp/dboard_base.cpp
@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "dboard_ctor_args.hpp"
#include <uhd/usrp/dboard_base.hpp>
#include <boost/format.hpp>
#include <stdexcept>
@@ -24,43 +25,48 @@ using namespace uhd::usrp;
/***********************************************************************
* dboard_base dboard dboard_base class
**********************************************************************/
-dboard_base::dboard_base(ctor_args_t const& args){
- boost::tie(_subdev_name, _dboard_iface, _rx_id, _tx_id) = args;
+struct dboard_base::dboard_base_impl{
+ ctor_args_impl args;
+ dboard_base_impl(ctor_args_t args) : args(*args){}
+};
+
+dboard_base::dboard_base(ctor_args_t args){
+ _impl = new dboard_base_impl(args);
}
dboard_base::~dboard_base(void){
- /* NOP */
+ delete _impl;
}
std::string dboard_base::get_subdev_name(void){
- return _subdev_name;
+ return _impl->args.sd_name;
}
dboard_iface::sptr dboard_base::get_iface(void){
- return _dboard_iface;
+ return _impl->args.db_iface;
}
dboard_id_t dboard_base::get_rx_id(void){
- return _rx_id;
+ return _impl->args.rx_id;
}
dboard_id_t dboard_base::get_tx_id(void){
- return _tx_id;
+ return _impl->args.tx_id;
}
/***********************************************************************
* xcvr dboard dboard_base class
**********************************************************************/
-xcvr_dboard_base::xcvr_dboard_base(ctor_args_t const& args) : dboard_base(args){
- if (get_rx_id() == dboard_id::NONE){
+xcvr_dboard_base::xcvr_dboard_base(ctor_args_t args) : dboard_base(args){
+ if (get_rx_id() == dboard_id_t::none()){
throw std::runtime_error(str(boost::format(
"cannot create xcvr board when the rx id is \"%s\""
- ) % dboard_id::to_string(dboard_id::NONE)));
+ ) % dboard_id_t::none().to_pp_string()));
}
- if (get_tx_id() == dboard_id::NONE){
+ if (get_tx_id() == dboard_id_t::none()){
throw std::runtime_error(str(boost::format(
"cannot create xcvr board when the tx id is \"%s\""
- ) % dboard_id::to_string(dboard_id::NONE)));
+ ) % dboard_id_t::none().to_pp_string()));
}
}
@@ -71,12 +77,12 @@ xcvr_dboard_base::~xcvr_dboard_base(void){
/***********************************************************************
* rx dboard dboard_base class
**********************************************************************/
-rx_dboard_base::rx_dboard_base(ctor_args_t const& args) : dboard_base(args){
- if (get_tx_id() != dboard_id::NONE){
+rx_dboard_base::rx_dboard_base(ctor_args_t args) : dboard_base(args){
+ if (get_tx_id() != dboard_id_t::none()){
throw std::runtime_error(str(boost::format(
"cannot create rx board when the tx id is \"%s\""
" -> expected a tx id of \"%s\""
- ) % dboard_id::to_string(get_tx_id()) % dboard_id::to_string(dboard_id::NONE)));
+ ) % get_tx_id().to_pp_string() % dboard_id_t::none().to_pp_string()));
}
}
@@ -95,12 +101,12 @@ void rx_dboard_base::tx_set(const wax::obj &, const wax::obj &){
/***********************************************************************
* tx dboard dboard_base class
**********************************************************************/
-tx_dboard_base::tx_dboard_base(ctor_args_t const& args) : dboard_base(args){
- if (get_rx_id() != dboard_id::NONE){
+tx_dboard_base::tx_dboard_base(ctor_args_t args) : dboard_base(args){
+ if (get_rx_id() != dboard_id_t::none()){
throw std::runtime_error(str(boost::format(
"cannot create tx board when the rx id is \"%s\""
" -> expected a rx id of \"%s\""
- ) % dboard_id::to_string(get_rx_id()) % dboard_id::to_string(dboard_id::NONE)));
+ ) % get_rx_id().to_pp_string() % dboard_id_t::none().to_pp_string()));
}
}
diff --git a/host/lib/usrp/dboard_ctor_args.hpp b/host/lib/usrp/dboard_ctor_args.hpp
new file mode 100644
index 000000000..13abe79e8
--- /dev/null
+++ b/host/lib/usrp/dboard_ctor_args.hpp
@@ -0,0 +1,32 @@
+//
+// Copyright 2010 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_DBOARD_CTOR_ARGS_HPP
+#define INCLUDED_DBOARD_CTOR_ARGS_HPP
+
+#include <uhd/usrp/dboard_id.hpp>
+#include <uhd/usrp/dboard_base.hpp>
+#include <uhd/usrp/dboard_iface.hpp>
+#include <string>
+
+struct uhd::usrp::dboard_base::ctor_args_impl{
+ std::string sd_name;
+ dboard_iface::sptr db_iface;
+ dboard_id_t rx_id, tx_id;
+};
+
+#endif /* INCLUDED_DBOARD_CTOR_ARGS_HPP */
diff --git a/host/lib/usrp/dboard_eeprom.cpp b/host/lib/usrp/dboard_eeprom.cpp
index 54e7a4fd9..fa3631948 100644
--- a/host/lib/usrp/dboard_eeprom.cpp
+++ b/host/lib/usrp/dboard_eeprom.cpp
@@ -80,19 +80,20 @@ dboard_eeprom_t::dboard_eeprom_t(const byte_vector_t &bytes){
UHD_ASSERT_THROW(bytes.size() >= DB_EEPROM_CLEN);
UHD_ASSERT_THROW(bytes[DB_EEPROM_MAGIC] == DB_EEPROM_MAGIC_VALUE);
UHD_ASSERT_THROW(bytes[DB_EEPROM_CHKSUM] == checksum(bytes));
- id = \
- (boost::uint16_t(bytes[DB_EEPROM_ID_LSB]) << 0) |
- (boost::uint16_t(bytes[DB_EEPROM_ID_MSB]) << 8) ;
+ id = dboard_id_t::from_uint16(0
+ | (boost::uint16_t(bytes[DB_EEPROM_ID_LSB]) << 0)
+ | (boost::uint16_t(bytes[DB_EEPROM_ID_MSB]) << 8)
+ );
}catch(const uhd::assert_error &){
- id = dboard_id::NONE;
+ id = dboard_id_t::none();
}
}
byte_vector_t dboard_eeprom_t::get_eeprom_bytes(void){
byte_vector_t bytes(DB_EEPROM_CLEN, 0); //defaults to all zeros
bytes[DB_EEPROM_MAGIC] = DB_EEPROM_MAGIC_VALUE;
- bytes[DB_EEPROM_ID_LSB] = boost::uint8_t(id >> 0);
- bytes[DB_EEPROM_ID_MSB] = boost::uint8_t(id >> 8);
+ bytes[DB_EEPROM_ID_LSB] = boost::uint8_t(id.to_uint16() >> 0);
+ bytes[DB_EEPROM_ID_MSB] = boost::uint8_t(id.to_uint16() >> 8);
bytes[DB_EEPROM_CHKSUM] = checksum(bytes);
return bytes;
}
diff --git a/host/lib/usrp/dboard_id.cpp b/host/lib/usrp/dboard_id.cpp
new file mode 100644
index 000000000..3028d2a3b
--- /dev/null
+++ b/host/lib/usrp/dboard_id.cpp
@@ -0,0 +1,68 @@
+//
+// Copyright 2010 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 <uhd/usrp/dboard_id.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/format.hpp>
+#include <sstream>
+#include <iostream>
+
+using namespace uhd::usrp;
+
+dboard_id_t::dboard_id_t(boost::uint16_t id){
+ _id = id;
+}
+
+dboard_id_t dboard_id_t::none(void){
+ return dboard_id_t();
+}
+
+dboard_id_t dboard_id_t::from_uint16(boost::uint16_t uint16){
+ return dboard_id_t(uint16);
+}
+
+boost::uint16_t dboard_id_t::to_uint16(void) const{
+ return _id;
+}
+
+//used with lexical cast to parse a hex string
+template <class T> struct to_hex{
+ T value;
+ operator T() const {return value;}
+ friend std::istream& operator>>(std::istream& in, to_hex& out){
+ in >> std::hex >> out.value;
+ return in;
+ }
+};
+
+dboard_id_t dboard_id_t::from_string(const std::string &string){
+ if (string.substr(0, 2) == "0x"){
+ return dboard_id_t::from_uint16(boost::lexical_cast<to_hex<boost::uint16_t> >(string));
+ }
+ return dboard_id_t::from_uint16(boost::lexical_cast<boost::uint16_t>(string));
+}
+
+std::string dboard_id_t::to_string(void) const{
+ return str(boost::format("0x%04x") % this->to_uint16());
+}
+
+//Note: to_pp_string is implemented in the dboard manager
+//because it needs access to the dboard registration table
+
+bool uhd::usrp::operator==(const dboard_id_t &lhs, const dboard_id_t &rhs){
+ return lhs.to_uint16() == rhs.to_uint16();
+}
diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp
index 390c1d3c9..8161727e5 100644
--- a/host/lib/usrp/dboard_manager.cpp
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "dboard_ctor_args.hpp"
#include <uhd/usrp/dboard_manager.hpp>
#include <uhd/usrp/subdev_props.hpp>
#include <uhd/utils/gain_handler.hpp>
@@ -26,6 +27,7 @@
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/assign/list_of.hpp>
+#include <iostream>
using namespace uhd;
using namespace uhd::usrp;
@@ -49,15 +51,18 @@ void dboard_manager::register_dboard(
//std::cout << "registering: " << name << std::endl;
if (get_id_to_args_map().has_key(dboard_id)){
throw std::runtime_error(str(boost::format(
- "The dboard id 0x%04x is already registered to %s."
- ) % dboard_id % dboard_id::to_string(dboard_id)));
+ "The dboard id %s is already registered to %s."
+ ) % dboard_id.to_string() % dboard_id.to_pp_string()));
}
get_id_to_args_map()[dboard_id] = args_t(dboard_ctor, name, subdev_names);
}
-std::string dboard_id::to_string(const dboard_id_t &id){
- std::string name = (get_id_to_args_map().has_key(id))? get_id_to_args_map()[id].get<1>() : "unknown";
- return str(boost::format("%s (0x%04x)") % name % id);
+std::string dboard_id_t::to_pp_string(void) const{
+ std::string name = "unknown";
+ if (get_id_to_args_map().has_key(*this)){
+ name = get_id_to_args_map()[*this].get<1>();
+ }
+ return str(boost::format("%s (%s)") % name % this->to_string());
}
/***********************************************************************
@@ -162,26 +167,27 @@ dboard_manager::sptr dboard_manager::make(
* implementation class methods
**********************************************************************/
static args_t get_dboard_args(
- dboard_id_t dboard_id,
- std::string const& xx_type
+ dboard_iface::unit_t unit,
+ dboard_id_t dboard_id
){
- //special case, its rx and the none id (0xffff)
- if (xx_type == "rx" and dboard_id == dboard_id::NONE){
- return get_dboard_args(0x0001, xx_type);
- }
-
- //special case, its tx and the none id (0xffff)
- if (xx_type == "tx" and dboard_id == dboard_id::NONE){
- return get_dboard_args(0x0000, xx_type);
+ //special case, the none id was provided, use the following ids
+ if (dboard_id == dboard_id_t::none()){
+ std::cerr << boost::format(
+ "Warning: unregistered dboard id: %s"
+ " -> defaulting to a basic board"
+ ) % dboard_id.to_pp_string() << std::endl;
+ UHD_ASSERT_THROW(get_id_to_args_map().has_key(0x0001));
+ UHD_ASSERT_THROW(get_id_to_args_map().has_key(0x0000));
+ switch(unit){
+ case dboard_iface::UNIT_RX: return get_dboard_args(unit, 0x0001);
+ case dboard_iface::UNIT_TX: return get_dboard_args(unit, 0x0000);
+ default: UHD_ASSERT_THROW(false);
+ }
}
//verify that there is a registered constructor for this id
if (not get_id_to_args_map().has_key(dboard_id)){
- /*throw std::runtime_error(str(
- boost::format("Unregistered %s dboard id: %s")
- % xx_type % dboard_id::to_string(dboard_id)
- ));*/
- return get_dboard_args(dboard_id::NONE, xx_type);
+ return get_dboard_args(unit, dboard_id_t::none());
}
//return the dboard args for this id
@@ -196,21 +202,26 @@ dboard_manager_impl::dboard_manager_impl(
_iface = iface;
dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs;
- boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(rx_dboard_id, "rx");
+ boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(dboard_iface::UNIT_RX, rx_dboard_id);
dboard_ctor_t tx_dboard_ctor; std::string tx_name; prop_names_t tx_subdevs;
- boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(tx_dboard_id, "tx");
+ boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(dboard_iface::UNIT_TX, tx_dboard_id);
//initialize the gpio pins before creating subdevs
set_nice_dboard_if();
+ //dboard constructor args
+ dboard_base::ctor_args_impl db_ctor_args;
+ db_ctor_args.db_iface = iface;
+
//make xcvr subdevs (make one subdev for both rx and tx dboards)
if (rx_dboard_ctor == tx_dboard_ctor){
UHD_ASSERT_THROW(rx_subdevs == tx_subdevs);
BOOST_FOREACH(const std::string &subdev, rx_subdevs){
- dboard_base::sptr xcvr_dboard = rx_dboard_ctor(
- dboard_base::ctor_args_t(subdev, iface, rx_dboard_id, tx_dboard_id)
- );
+ db_ctor_args.sd_name = subdev;
+ db_ctor_args.rx_id = rx_dboard_id;
+ db_ctor_args.tx_id = tx_dboard_id;
+ dboard_base::sptr xcvr_dboard = rx_dboard_ctor(&db_ctor_args);
//create a rx proxy for this xcvr board
_rx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(xcvr_dboard, subdev_proxy::RX_TYPE)
@@ -226,9 +237,10 @@ dboard_manager_impl::dboard_manager_impl(
else{
//make the rx subdevs
BOOST_FOREACH(const std::string &subdev, rx_subdevs){
- dboard_base::sptr rx_dboard = rx_dboard_ctor(
- dboard_base::ctor_args_t(subdev, iface, rx_dboard_id, dboard_id::NONE)
- );
+ db_ctor_args.sd_name = subdev;
+ db_ctor_args.rx_id = rx_dboard_id;
+ db_ctor_args.tx_id = dboard_id_t::none();
+ dboard_base::sptr rx_dboard = rx_dboard_ctor(&db_ctor_args);
//create a rx proxy for this rx board
_rx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(rx_dboard, subdev_proxy::RX_TYPE)
@@ -236,9 +248,10 @@ dboard_manager_impl::dboard_manager_impl(
}
//make the tx subdevs
BOOST_FOREACH(const std::string &subdev, tx_subdevs){
- dboard_base::sptr tx_dboard = tx_dboard_ctor(
- dboard_base::ctor_args_t(subdev, iface, dboard_id::NONE, tx_dboard_id)
- );
+ db_ctor_args.sd_name = subdev;
+ db_ctor_args.rx_id = dboard_id_t::none();
+ db_ctor_args.tx_id = tx_dboard_id;
+ dboard_base::sptr tx_dboard = tx_dboard_ctor(&db_ctor_args);
//create a tx proxy for this tx board
_tx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(tx_dboard, subdev_proxy::TX_TYPE)
diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt
new file mode 100644
index 000000000..f9907e21e
--- /dev/null
+++ b/host/lib/usrp/usrp2/CMakeLists.txt
@@ -0,0 +1,29 @@
+#
+# Copyright 2010 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 will be included by cmake, use absolute paths!
+
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_control.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/io_impl.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/mboard_impl.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.cpp
+)
diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp
index 74d80163c..372a5af07 100644
--- a/host/lib/usrp/usrp2/dboard_iface.cpp
+++ b/host/lib/usrp/usrp2/dboard_iface.cpp
@@ -29,6 +29,7 @@
using namespace uhd;
using namespace uhd::usrp;
+using namespace boost::assign;
class usrp2_dboard_iface : public dboard_iface{
public:
@@ -122,49 +123,42 @@ double usrp2_dboard_iface::get_clock_rate(unit_t){
void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){
switch(unit){
- case UNIT_RX:
- _clk_ctrl->enable_rx_dboard_clock(enb);
- return;
- case UNIT_TX:
- _clk_ctrl->enable_tx_dboard_clock(enb);
- return;
+ case UNIT_RX: _clk_ctrl->enable_rx_dboard_clock(enb); return;
+ case UNIT_TX: _clk_ctrl->enable_tx_dboard_clock(enb); return;
}
}
/***********************************************************************
* GPIO
**********************************************************************/
-static int unit_to_shift(dboard_iface::unit_t unit){
- switch(unit){
- case dboard_iface::UNIT_RX: return 0;
- case dboard_iface::UNIT_TX: return 16;
- }
- throw std::runtime_error("unknown unit type");
-}
+static const uhd::dict<dboard_iface::unit_t, int> unit_to_shift = map_list_of
+ (dboard_iface::UNIT_RX, 0)
+ (dboard_iface::UNIT_TX, 16)
+;
void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){
_ddr_shadow = \
- (_ddr_shadow & ~(0xffff << unit_to_shift(unit))) |
- (boost::uint32_t(value) << unit_to_shift(unit));
+ (_ddr_shadow & ~(0xffff << unit_to_shift[unit])) |
+ (boost::uint32_t(value) << unit_to_shift[unit]);
_iface->poke32(FR_GPIO_DDR, _ddr_shadow);
}
boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){
- return boost::uint16_t(_iface->peek32(FR_GPIO_IO) >> unit_to_shift(unit));
+ return boost::uint16_t(_iface->peek32(FR_GPIO_IO) >> unit_to_shift[unit]);
}
void usrp2_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){
//define mapping of unit to atr regs to register address
static const uhd::dict<
unit_t, uhd::dict<atr_reg_t, boost::uint32_t>
- > unit_to_atr_to_addr = boost::assign::map_list_of
- (UNIT_RX, boost::assign::map_list_of
+ > unit_to_atr_to_addr = map_list_of
+ (UNIT_RX, map_list_of
(ATR_REG_IDLE, FR_ATR_IDLE_RXSIDE)
(ATR_REG_TX_ONLY, FR_ATR_INTX_RXSIDE)
(ATR_REG_RX_ONLY, FR_ATR_INRX_RXSIDE)
(ATR_REG_FULL_DUPLEX, FR_ATR_FULL_RXSIDE)
)
- (UNIT_TX, boost::assign::map_list_of
+ (UNIT_TX, map_list_of
(ATR_REG_IDLE, FR_ATR_IDLE_TXSIDE)
(ATR_REG_TX_ONLY, FR_ATR_INTX_TXSIDE)
(ATR_REG_RX_ONLY, FR_ATR_INRX_TXSIDE)
@@ -177,19 +171,10 @@ void usrp2_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t
/***********************************************************************
* SPI
**********************************************************************/
-/*!
- * Static function to convert a unit type enum
- * to an over-the-wire value for the spi device.
- * \param unit the dboard interface unit type enum
- * \return an over the wire representation
- */
-static boost::uint8_t unit_to_otw_spi_dev(dboard_iface::unit_t unit){
- switch(unit){
- case dboard_iface::UNIT_TX: return SPI_SS_TX_DB;
- case dboard_iface::UNIT_RX: return SPI_SS_RX_DB;
- }
- throw std::invalid_argument("unknown unit type");
-}
+static const uhd::dict<dboard_iface::unit_t, int> unit_to_spi_dev = map_list_of
+ (dboard_iface::UNIT_TX, SPI_SS_TX_DB)
+ (dboard_iface::UNIT_RX, SPI_SS_RX_DB)
+;
void usrp2_dboard_iface::write_spi(
unit_t unit,
@@ -197,7 +182,7 @@ void usrp2_dboard_iface::write_spi(
boost::uint32_t data,
size_t num_bits
){
- _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, false /*no rb*/);
+ _iface->transact_spi(unit_to_spi_dev[unit], config, data, num_bits, false /*no rb*/);
}
boost::uint32_t usrp2_dboard_iface::read_write_spi(
@@ -206,7 +191,7 @@ boost::uint32_t usrp2_dboard_iface::read_write_spi(
boost::uint32_t data,
size_t num_bits
){
- return _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, true /*rb*/);
+ return _iface->transact_spi(unit_to_spi_dev[unit], config, data, num_bits, true /*rb*/);
}
/***********************************************************************
@@ -224,7 +209,7 @@ byte_vector_t usrp2_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes
* Aux DAX/ADC
**********************************************************************/
void usrp2_dboard_iface::_write_aux_dac(unit_t unit){
- static const uhd::dict<unit_t, int> unit_to_spi_dac = boost::assign::map_list_of
+ static const uhd::dict<unit_t, int> unit_to_spi_dac = map_list_of
(UNIT_RX, SPI_SS_RX_DAC)
(UNIT_TX, SPI_SS_TX_DAC)
;
@@ -248,7 +233,7 @@ void usrp2_dboard_iface::write_aux_dac(unit_t unit, int which, float value){
}
float usrp2_dboard_iface::read_aux_adc(unit_t unit, int which){
- static const uhd::dict<unit_t, int> unit_to_spi_adc = boost::assign::map_list_of
+ static const uhd::dict<unit_t, int> unit_to_spi_adc = map_list_of
(UNIT_RX, SPI_SS_RX_ADC)
(UNIT_TX, SPI_SS_TX_ADC)
;
diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp
index bd61ac376..195a9bc53 100644
--- a/host/lib/usrp/usrp2/dsp_impl.cpp
+++ b/host/lib/usrp/usrp2/dsp_impl.cpp
@@ -52,6 +52,23 @@ static boost::uint32_t calculate_freq_word_and_update_actual_freq(double &freq,
return freq_word;
}
+// Check if requested decim/interp rate is:
+// multiple of 4, enable two halfband filters
+// multiple of 2, enable one halfband filter
+// handle remainder in CIC
+static boost::uint32_t calculate_cic_word(size_t rate){
+ int hb0 = 0, hb1 = 0;
+ if (not (rate & 0x1)){
+ hb0 = 1;
+ rate /= 2;
+ }
+ if (not (rate & 0x1)){
+ hb1 = 1;
+ rate /= 2;
+ }
+ return (hb1 << 9) | (hb0 << 8) | (rate & 0xff);
+}
+
static boost::uint32_t calculate_iq_scale_word(boost::int16_t i, boost::int16_t q){
return (boost::uint16_t(i) << 16) | (boost::uint16_t(q) << 0);
}
@@ -81,7 +98,7 @@ void usrp2_impl::init_ddc_config(void){
void usrp2_impl::update_ddc_config(void){
//set the decimation
- _iface->poke32(FR_DSP_RX_DECIM_RATE, _ddc_decim);
+ _iface->poke32(FR_DSP_RX_DECIM_RATE, calculate_cic_word(_ddc_decim));
//set the scaling
static const boost::int16_t default_rx_scale_iq = 1024;
@@ -160,15 +177,14 @@ void usrp2_impl::init_duc_config(void){
void usrp2_impl::update_duc_config(void){
// Calculate CIC interpolation (i.e., without halfband interpolators)
- size_t tmp_interp = _duc_interp;
- while(tmp_interp > 128) tmp_interp /= 2;
+ size_t tmp_interp = calculate_cic_word(_duc_interp) & 0xff;
// Calculate closest multiplier constant to reverse gain absent scale multipliers
double interp_cubed = std::pow(double(tmp_interp), 3);
boost::int16_t scale = rint((4096*std::pow(2, ceil(log2(interp_cubed))))/(1.65*interp_cubed));
//set the interpolation
- _iface->poke32(FR_DSP_TX_INTERP_RATE, _ddc_decim);
+ _iface->poke32(FR_DSP_TX_INTERP_RATE, calculate_cic_word(_duc_interp));
//set the scaling
_iface->poke32(FR_DSP_TX_SCALE_IQ, calculate_iq_scale_word(scale, scale));
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index a2e99c824..7c9d003ce 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -39,6 +39,9 @@ void usrp2_impl::io_init(void){
//initially empty copy buffer
_rx_copy_buff = asio::buffer("", 0);
+ //init the expected rx seq number
+ _rx_stream_id_to_packet_seq[0] = 0;
+
//send a small data packet so the usrp2 knows the udp source port
managed_send_buffer::sptr send_buff = _data_transport->get_send_buff();
boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER);
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 2b974fb9b..1dde8c054 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -113,31 +113,23 @@ device::sptr usrp2::make(const device_addr_t &device_addr){
device_addr["addr"], num2str(USRP2_UDP_CTRL_PORT)
);
- //create a data transport
- udp_zero_copy::sptr data_transport = udp_zero_copy::make(
- device_addr["addr"], num2str(USRP2_UDP_DATA_PORT)
- );
-
- //resize the recv data transport buffers
+ //extract the receive and send buffer sizes
+ size_t recv_buff_size = 0, send_buff_size= 0 ;
if (device_addr.has_key("recv_buff_size")){
- size_t num_byes = size_t(boost::lexical_cast<double>(device_addr["recv_buff_size"]));
- size_t actual_bytes = data_transport->resize_recv_buff_size(num_byes);
- if (num_byes != actual_bytes) std::cout << boost::format(
- "Target recv buffer size: %d\n"
- "Actual recv byffer size: %d"
- ) % num_byes % actual_bytes << std::endl;
+ recv_buff_size = size_t(boost::lexical_cast<double>(device_addr["recv_buff_size"]));
}
-
- //resize the send data transport buffers
if (device_addr.has_key("send_buff_size")){
- size_t num_byes = size_t(boost::lexical_cast<double>(device_addr["send_buff_size"]));
- size_t actual_bytes = data_transport->resize_send_buff_size(num_byes);
- if (num_byes != actual_bytes) std::cout << boost::format(
- "Target send buffer size: %d\n"
- "Actual send byffer size: %d"
- ) % num_byes % actual_bytes << std::endl;
+ send_buff_size = size_t(boost::lexical_cast<double>(device_addr["send_buff_size"]));
}
+ //create a data transport
+ udp_zero_copy::sptr data_transport = udp_zero_copy::make(
+ device_addr["addr"],
+ num2str(USRP2_UDP_DATA_PORT),
+ recv_buff_size,
+ send_buff_size
+ );
+
//create the usrp2 implementation guts
return device::sptr(
new usrp2_impl(ctrl_transport, data_transport)