summaryrefslogtreecommitdiffstats
path: root/host/lib/usrp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp')
-rw-r--r--host/lib/usrp/CMakeLists.txt1
-rw-r--r--host/lib/usrp/dboard/db_basic_and_lf.cpp10
-rw-r--r--host/lib/usrp/dboard/db_dbsrx.cpp24
-rw-r--r--host/lib/usrp/dboard/db_dbsrx2.cpp24
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp30
-rw-r--r--host/lib/usrp/dboard/db_tvrx.cpp22
-rw-r--r--host/lib/usrp/dboard/db_unknown.cpp10
-rw-r--r--host/lib/usrp/dboard/db_wbx.cpp36
-rw-r--r--host/lib/usrp/dboard/db_xcvr2450.cpp48
-rw-r--r--host/lib/usrp/gps_ctrl.cpp (renamed from host/lib/usrp/usrp2/gps_ctrl.cpp)43
-rw-r--r--host/lib/usrp/mboard_eeprom.cpp12
-rw-r--r--host/lib/usrp/misc_utils.cpp22
-rw-r--r--host/lib/usrp/multi_usrp.cpp44
-rw-r--r--host/lib/usrp/single_usrp.cpp20
-rw-r--r--host/lib/usrp/subdev_spec.cpp14
-rw-r--r--host/lib/usrp/usrp1/CMakeLists.txt3
-rw-r--r--host/lib/usrp/usrp1/codec_ctrl.cpp38
-rw-r--r--host/lib/usrp/usrp1/codec_ctrl.hpp19
-rw-r--r--host/lib/usrp/usrp1/codec_impl.cpp8
-rw-r--r--host/lib/usrp/usrp1/dboard_iface.cpp10
-rw-r--r--host/lib/usrp/usrp1/io_impl.cpp39
-rw-r--r--host/lib/usrp/usrp1/mboard_impl.cpp25
-rw-r--r--host/lib/usrp/usrp1/soft_time_ctrl.cpp224
-rw-r--r--host/lib/usrp/usrp1/soft_time_ctrl.hpp69
-rw-r--r--host/lib/usrp/usrp1/usrp1_ctrl.cpp29
-rw-r--r--host/lib/usrp/usrp1/usrp1_ctrl.hpp17
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp6
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.hpp9
-rw-r--r--host/lib/usrp/usrp2/CMakeLists.txt4
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.cpp57
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.hpp12
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.cpp8
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.hpp6
-rw-r--r--host/lib/usrp/usrp2/codec_impl.cpp12
-rw-r--r--host/lib/usrp/usrp2/dboard_iface.cpp12
-rw-r--r--host/lib/usrp/usrp2/fw_common.h59
-rw-r--r--host/lib/usrp/usrp2/gps_ctrl.hpp53
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp216
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp117
-rw-r--r--host/lib/usrp/usrp2/serdes_ctrl.cpp46
-rw-r--r--host/lib/usrp/usrp2/serdes_ctrl.hpp40
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp22
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp18
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp45
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp26
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.cpp10
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp18
-rw-r--r--host/lib/usrp/usrp_e100/codec_ctrl.cpp32
-rw-r--r--host/lib/usrp/usrp_e100/codec_ctrl.hpp14
-rw-r--r--host/lib/usrp/usrp_e100/codec_impl.cpp8
-rw-r--r--host/lib/usrp/usrp_e100/dboard_iface.cpp10
-rw-r--r--host/lib/usrp/usrp_e100/dsp_impl.cpp4
-rw-r--r--host/lib/usrp/usrp_e100/mboard_impl.cpp30
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_impl.hpp2
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_regs.hpp10
55 files changed, 1113 insertions, 634 deletions
diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt
index 9dc74a5fe..bd25aec2b 100644
--- a/host/lib/usrp/CMakeLists.txt
+++ b/host/lib/usrp/CMakeLists.txt
@@ -25,6 +25,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dboard_manager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dsp_utils.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/gps_ctrl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mboard_eeprom.cpp
${CMAKE_CURRENT_SOURCE_DIR}/misc_utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/multi_usrp.cpp
diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp
index f771595b6..b311576d2 100644
--- a/host/lib/usrp/dboard/db_basic_and_lf.cpp
+++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -134,7 +134,7 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- val = float(0);
+ val = double(0);
return;
case SUBDEV_PROP_GAIN_RANGE:
@@ -192,7 +192,7 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_GAIN:
- UHD_ASSERT_THROW(val.as<float>() == float(0));
+ UHD_ASSERT_THROW(val.as<double>() == double(0));
return;
case SUBDEV_PROP_ANTENNA:
@@ -245,7 +245,7 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- val = float(0);
+ val = double(0);
return;
case SUBDEV_PROP_GAIN_RANGE:
@@ -303,7 +303,7 @@ void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_GAIN:
- UHD_ASSERT_THROW(val.as<float>() == float(0));
+ UHD_ASSERT_THROW(val.as<double>() == double(0));
return;
case SUBDEV_PROP_ANTENNA:
diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp
index 7250136f5..3ea9cea80 100644
--- a/host/lib/usrp/dboard/db_dbsrx.cpp
+++ b/host/lib/usrp/dboard/db_dbsrx.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -70,7 +70,7 @@ public:
private:
double _lo_freq;
double _bandwidth;
- uhd::dict<std::string, float> _gains;
+ uhd::dict<std::string, double> _gains;
max2118_write_regs_t _max2118_write_regs;
max2118_read_regs_t _max2118_read_regs;
boost::uint8_t _max2118_addr(void){
@@ -78,7 +78,7 @@ private:
};
void set_lo_freq(double target_freq);
- void set_gain(float gain, const std::string &name);
+ void set_gain(double gain, const std::string &name);
void set_bandwidth(double bandwidth);
void send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){
@@ -418,17 +418,17 @@ void dbsrx::set_lo_freq(double target_freq){
* \param gain the requested gain in dB
* \return 5 bit the register value
*/
-static int gain_to_gc2_vga_reg(float &gain){
+static int gain_to_gc2_vga_reg(double &gain){
int reg = 0;
gain = dbsrx_gain_ranges["GC2"].clip(gain);
// Half dB steps from 0-5dB, 1dB steps from 5-24dB
if (gain < 5) {
reg = boost::math::iround(31.0 - gain/0.5);
- gain = float(boost::math::iround(gain) * 0.5);
+ gain = double(boost::math::iround(gain) * 0.5);
} else {
reg = boost::math::iround(22.0 - (gain - 4.0));
- gain = float(boost::math::iround(gain));
+ gain = double(boost::math::iround(gain));
}
if (dbsrx_debug) std::cerr << boost::format(
@@ -444,16 +444,16 @@ static int gain_to_gc2_vga_reg(float &gain){
* \param gain the requested gain in dB
* \return dac voltage value
*/
-static float gain_to_gc1_rfvga_dac(float &gain){
+static double gain_to_gc1_rfvga_dac(double &gain){
//clip the input
gain = dbsrx_gain_ranges["GC1"].clip(gain);
//voltage level constants
- static const float max_volts = float(1.2), min_volts = float(2.7);
- static const float slope = (max_volts-min_volts)/dbsrx_gain_ranges["GC1"].stop();
+ static const double max_volts = 1.2, min_volts = 2.7;
+ static const double slope = (max_volts-min_volts)/dbsrx_gain_ranges["GC1"].stop();
//calculate the voltage for the aux dac
- float dac_volts = gain*slope + min_volts;
+ double dac_volts = gain*slope + min_volts;
if (dbsrx_debug) std::cerr << boost::format(
"DBSRX GC1 Gain: %f dB, dac_volts: %f V"
@@ -465,7 +465,7 @@ static float gain_to_gc1_rfvga_dac(float &gain){
return dac_volts;
}
-void dbsrx::set_gain(float gain, const std::string &name){
+void dbsrx::set_gain(double gain, const std::string &name){
assert_has(dbsrx_gain_ranges.keys(), name, "dbsrx gain name");
if (name == "GC2"){
_max2118_write_regs.gc2 = gain_to_gc2_vga_reg(gain);
@@ -584,7 +584,7 @@ void dbsrx::rx_set(const wax::obj &key_, const wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- this->set_gain(val.as<float>(), key.name);
+ this->set_gain(val.as<double>(), key.name);
return;
case SUBDEV_PROP_ENABLED:
diff --git a/host/lib/usrp/dboard/db_dbsrx2.cpp b/host/lib/usrp/dboard/db_dbsrx2.cpp
index cdafd6a78..defb70ff5 100644
--- a/host/lib/usrp/dboard/db_dbsrx2.cpp
+++ b/host/lib/usrp/dboard/db_dbsrx2.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -48,7 +48,7 @@ static const int dbsrx2_ref_divider = 4; // Hitachi HMC426 divider (U7)
static const prop_names_t dbsrx2_antennas = list_of("J3");
static const uhd::dict<std::string, gain_range_t> dbsrx2_gain_ranges = map_list_of
- ("GC1", gain_range_t(0, 73, float(0.05)))
+ ("GC1", gain_range_t(0, 73, 0.05))
("BBG", gain_range_t(0, 15, 1))
;
@@ -66,7 +66,7 @@ public:
private:
double _lo_freq;
double _bandwidth;
- uhd::dict<std::string, float> _gains;
+ uhd::dict<std::string, double> _gains;
max2112_write_regs_t _max2112_write_regs;
max2112_read_regs_t _max2112_read_regs;
boost::uint8_t _max2112_addr(){ //0x60 or 0x61 depending on which side
@@ -74,7 +74,7 @@ private:
}
void set_lo_freq(double target_freq);
- void set_gain(float gain, const std::string &name);
+ void set_gain(double gain, const std::string &name);
void set_bandwidth(double bandwidth);
void send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){
@@ -269,10 +269,10 @@ void dbsrx2::set_lo_freq(double target_freq){
* \param gain the requested gain in dB
* \return 4 bit the register value
*/
-static int gain_to_bbg_vga_reg(float &gain){
+static int gain_to_bbg_vga_reg(double &gain){
int reg = boost::math::iround(dbsrx2_gain_ranges["BBG"].clip(gain));
- gain = float(reg);
+ gain = double(reg);
if (dbsrx2_debug) std::cerr
<< boost::format("DBSRX2 BBG Gain:\n")
@@ -288,16 +288,16 @@ static int gain_to_bbg_vga_reg(float &gain){
* \param gain the requested gain in dB
* \return dac voltage value
*/
-static float gain_to_gc1_rfvga_dac(float &gain){
+static double gain_to_gc1_rfvga_dac(double &gain){
//clip the input
gain = dbsrx2_gain_ranges["GC1"].clip(gain);
//voltage level constants
- static const float max_volts = float(0.5), min_volts = float(2.7);
- static const float slope = (max_volts-min_volts)/dbsrx2_gain_ranges["GC1"].stop();
+ static const double max_volts = 0.5, min_volts = 2.7;
+ static const double slope = (max_volts-min_volts)/dbsrx2_gain_ranges["GC1"].stop();
//calculate the voltage for the aux dac
- float dac_volts = gain*slope + min_volts;
+ double dac_volts = gain*slope + min_volts;
if (dbsrx2_debug) std::cerr
<< boost::format("DBSRX2 GC1 Gain:\n")
@@ -310,7 +310,7 @@ static float gain_to_gc1_rfvga_dac(float &gain){
return dac_volts;
}
-void dbsrx2::set_gain(float gain, const std::string &name){
+void dbsrx2::set_gain(double gain, const std::string &name){
assert_has(dbsrx2_gain_ranges.keys(), name, "dbsrx2 gain name");
if (name == "BBG"){
_max2112_write_regs.bbg = gain_to_bbg_vga_reg(gain);
@@ -423,7 +423,7 @@ void dbsrx2::rx_set(const wax::obj &key_, const wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- this->set_gain(val.as<float>(), key.name);
+ this->set_gain(val.as<double>(), key.name);
return;
case SUBDEV_PROP_ENABLED:
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index 74a9fb37b..cd25ee9b7 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -67,11 +67,11 @@ static const prop_names_t rfx_rx_antennas = list_of("TX/RX")("RX2");
static const uhd::dict<std::string, gain_range_t> rfx_tx_gain_ranges; //empty
static const uhd::dict<std::string, gain_range_t> rfx_rx_gain_ranges = map_list_of
- ("PGA0", gain_range_t(0, 70, float(0.022)))
+ ("PGA0", gain_range_t(0, 70, 0.022))
;
static const uhd::dict<std::string, gain_range_t> rfx400_rx_gain_ranges = map_list_of
- ("PGA0", gain_range_t(0, 45, float(0.022)))
+ ("PGA0", gain_range_t(0, 45, 0.022))
;
/***********************************************************************
@@ -98,14 +98,14 @@ private:
const uhd::dict<dboard_iface::unit_t, bool> _div2;
double _rx_lo_freq, _tx_lo_freq;
std::string _rx_ant;
- uhd::dict<std::string, float> _rx_gains;
+ uhd::dict<std::string, double> _rx_gains;
void set_rx_lo_freq(double freq);
void set_tx_lo_freq(double freq);
void set_rx_ant(const std::string &ant);
void set_tx_ant(const std::string &ant);
- void set_rx_gain(float gain, const std::string &name);
- void set_tx_gain(float gain, const std::string &name);
+ void set_rx_gain(double gain, const std::string &name);
+ void set_tx_gain(double gain, const std::string &name);
/*!
* Set the LO frequency for the particular dboard unit.
@@ -240,13 +240,13 @@ void rfx_xcvr::set_tx_ant(const std::string &ant){
/***********************************************************************
* Gain Handling
**********************************************************************/
-static float rx_pga0_gain_to_dac_volts(float &gain, float range){
+static double rx_pga0_gain_to_dac_volts(double &gain, double range){
//voltage level constants (negative slope)
- static const float max_volts = float(.2), min_volts = float(1.2);
- static const float slope = (max_volts-min_volts)/(range);
+ static const double max_volts = .2, min_volts = 1.2;
+ static const double slope = (max_volts-min_volts)/(range);
//calculate the voltage for the aux dac
- float dac_volts = std::clip<float>(gain*slope + min_volts, max_volts, min_volts);
+ double dac_volts = std::clip<double>(gain*slope + min_volts, max_volts, min_volts);
//the actual gain setting
gain = (dac_volts - min_volts)/slope;
@@ -254,15 +254,15 @@ static float rx_pga0_gain_to_dac_volts(float &gain, float range){
return dac_volts;
}
-void rfx_xcvr::set_tx_gain(float, const std::string &name){
+void rfx_xcvr::set_tx_gain(double, const std::string &name){
assert_has(rfx_tx_gain_ranges.keys(), name, "rfx tx gain name");
UHD_THROW_INVALID_CODE_PATH(); //no gains to set
}
-void rfx_xcvr::set_rx_gain(float gain, const std::string &name){
+void rfx_xcvr::set_rx_gain(double gain, const std::string &name){
assert_has(_rx_gain_ranges.keys(), name, "rfx rx gain name");
if(name == "PGA0"){
- float dac_volts = rx_pga0_gain_to_dac_volts(gain,
+ double dac_volts = rx_pga0_gain_to_dac_volts(gain,
(_rx_gain_ranges["PGA0"].stop() - _rx_gain_ranges["PGA0"].start()));
_rx_gains[name] = gain;
@@ -474,7 +474,7 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- this->set_rx_gain(val.as<float>(), key.name);
+ this->set_rx_gain(val.as<double>(), key.name);
return;
case SUBDEV_PROP_ANTENNA:
@@ -571,7 +571,7 @@ void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- this->set_tx_gain(val.as<float>(), key.name);
+ this->set_tx_gain(val.as<double>(), key.name);
return;
case SUBDEV_PROP_ANTENNA:
diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp
index 2508555d0..4eb29c3e8 100644
--- a/host/lib/usrp/dboard/db_tvrx.cpp
+++ b/host/lib/usrp/dboard/db_tvrx.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -119,8 +119,8 @@ static uhd::dict<std::string, gain_range_t> get_tvrx_gain_ranges(void) {
double ifmax = tvrx_if_gains_db.back();
return map_list_of
- ("RF", gain_range_t(float(rfmin), float(rfmax), float((rfmax-rfmin)/4096.0)))
- ("IF", gain_range_t(float(ifmin), float(ifmax), float((ifmax-ifmin)/4096.0)))
+ ("RF", gain_range_t(rfmin, rfmax, (rfmax-rfmin)/4096.0))
+ ("IF", gain_range_t(ifmin, ifmax, (ifmax-ifmin)/4096.0))
;
}
@@ -141,14 +141,14 @@ public:
void rx_set(const wax::obj &key, const wax::obj &val);
private:
- uhd::dict<std::string, float> _gains;
+ uhd::dict<std::string, double> _gains;
double _lo_freq;
tuner_4937di5_regs_t _tuner_4937di5_regs;
boost::uint8_t _tuner_4937di5_addr(void){
return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x61 : 0x60; //ok really? we could rename that call
};
- void set_gain(float gain, const std::string &name);
+ void set_gain(double gain, const std::string &name);
void set_freq(double freq);
void update_regs(void){
@@ -275,7 +275,7 @@ static double gain_interp(double gain, boost::array<double, 17> db_vector, boost
* \return dac voltage value
*/
-static float rf_gain_to_voltage(float gain, double lo_freq){
+static double rf_gain_to_voltage(double gain, double lo_freq){
//clip the input
gain = get_tvrx_gain_ranges()["RF"].clip(gain);
@@ -293,7 +293,7 @@ static float rf_gain_to_voltage(float gain, double lo_freq){
"tvrx RF AGC gain: %f dB, dac_volts: %f V"
) % gain % dac_volts << std::endl;
- return float(dac_volts);
+ return dac_volts;
}
/*!
@@ -303,7 +303,7 @@ static float rf_gain_to_voltage(float gain, double lo_freq){
* \return dac voltage value
*/
-static float if_gain_to_voltage(float gain){
+static double if_gain_to_voltage(double gain){
//clip the input
gain = get_tvrx_gain_ranges()["IF"].clip(gain);
@@ -316,10 +316,10 @@ static float if_gain_to_voltage(float gain){
"tvrx IF AGC gain: %f dB, dac_volts: %f V"
) % gain % dac_volts << std::endl;
- return float(dac_volts);
+ return dac_volts;
}
-void tvrx::set_gain(float gain, const std::string &name){
+void tvrx::set_gain(double gain, const std::string &name){
assert_has(get_tvrx_gain_ranges().keys(), name, "tvrx gain name");
if (name == "RF"){
this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_B, rf_gain_to_voltage(gain, _lo_freq));
@@ -473,7 +473,7 @@ void tvrx::rx_set(const wax::obj &key_, const wax::obj &val){
//handle the get request conditioned on the key
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_GAIN:
- this->set_gain(val.as<float>(), key.name);
+ this->set_gain(val.as<double>(), key.name);
return;
case SUBDEV_PROP_FREQ:
diff --git a/host/lib/usrp/dboard/db_unknown.cpp b/host/lib/usrp/dboard/db_unknown.cpp
index 168e1971c..d91d58409 100644
--- a/host/lib/usrp/dboard/db_unknown.cpp
+++ b/host/lib/usrp/dboard/db_unknown.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -115,7 +115,7 @@ void unknown_rx::rx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- val = float(0);
+ val = double(0);
return;
case SUBDEV_PROP_GAIN_RANGE:
@@ -173,7 +173,7 @@ void unknown_rx::rx_set(const wax::obj &key_, const wax::obj &val){
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_GAIN:
- UHD_ASSERT_THROW(val.as<float>() == float(0));
+ UHD_ASSERT_THROW(val.as<double>() == double(0));
return;
case SUBDEV_PROP_ANTENNA:
@@ -217,7 +217,7 @@ void unknown_tx::tx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- val = float(0);
+ val = double(0);
return;
case SUBDEV_PROP_GAIN_RANGE:
@@ -275,7 +275,7 @@ void unknown_tx::tx_set(const wax::obj &key_, const wax::obj &val){
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_GAIN:
- UHD_ASSERT_THROW(val.as<float>() == float(0));
+ UHD_ASSERT_THROW(val.as<double>() == double(0));
return;
case SUBDEV_PROP_ANTENNA:
diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp
index dd5bd600b..135997789 100644
--- a/host/lib/usrp/dboard/db_wbx.cpp
+++ b/host/lib/usrp/dboard/db_wbx.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -94,11 +94,11 @@ static const prop_names_t wbx_tx_antennas = list_of("TX/RX");
static const prop_names_t wbx_rx_antennas = list_of("TX/RX")("RX2");
static const uhd::dict<std::string, gain_range_t> wbx_tx_gain_ranges = map_list_of
- ("PGA0", gain_range_t(0, 25, float(0.05)))
+ ("PGA0", gain_range_t(0, 25, 0.05))
;
static const uhd::dict<std::string, gain_range_t> wbx_rx_gain_ranges = map_list_of
- ("PGA0", gain_range_t(0, 31.5, float(0.5)))
+ ("PGA0", gain_range_t(0, 31.5, 0.5))
;
/***********************************************************************
@@ -116,7 +116,7 @@ public:
void tx_set(const wax::obj &key, const wax::obj &val);
private:
- uhd::dict<std::string, float> _tx_gains, _rx_gains;
+ uhd::dict<std::string, double> _tx_gains, _rx_gains;
double _rx_lo_freq, _tx_lo_freq;
std::string _tx_ant, _rx_ant;
@@ -124,8 +124,8 @@ private:
void set_tx_lo_freq(double freq);
void set_rx_ant(const std::string &ant);
void set_tx_ant(const std::string &ant);
- void set_rx_gain(float gain, const std::string &name);
- void set_tx_gain(float gain, const std::string &name);
+ void set_rx_gain(double gain, const std::string &name);
+ void set_tx_gain(double gain, const std::string &name);
void update_atr(void);
@@ -196,12 +196,12 @@ wbx_xcvr::~wbx_xcvr(void){
/***********************************************************************
* Gain Handling
**********************************************************************/
-static int rx_pga0_gain_to_iobits(float &gain){
+static int rx_pga0_gain_to_iobits(double &gain){
//clip the input
gain = wbx_rx_gain_ranges["PGA0"].clip(gain);
//convert to attenuation and update iobits for atr
- float attn = wbx_rx_gain_ranges["PGA0"].stop() - gain;
+ double attn = wbx_rx_gain_ranges["PGA0"].stop() - gain;
//calculate the attenuation
int attn_code = boost::math::iround(attn*2);
@@ -212,21 +212,21 @@ static int rx_pga0_gain_to_iobits(float &gain){
) % attn % attn_code % (iobits & RX_ATTN_MASK) % RX_ATTN_MASK << std::endl;
//the actual gain setting
- gain = wbx_rx_gain_ranges["PGA0"].stop() - float(attn_code)/2;
+ gain = wbx_rx_gain_ranges["PGA0"].stop() - double(attn_code)/2;
return iobits;
}
-static float tx_pga0_gain_to_dac_volts(float &gain){
+static double tx_pga0_gain_to_dac_volts(double &gain){
//clip the input
gain = wbx_tx_gain_ranges["PGA0"].clip(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)/wbx_tx_gain_ranges["PGA0"].stop();
+ static const double max_volts = 0.5, min_volts = 1.4;
+ static const double slope = (max_volts-min_volts)/wbx_tx_gain_ranges["PGA0"].stop();
//calculate the voltage for the aux dac
- float dac_volts = gain*slope + min_volts;
+ double dac_volts = gain*slope + min_volts;
if (wbx_debug) std::cerr << boost::format(
"WBX TX Gain: %f dB, dac_volts: %f V"
@@ -238,10 +238,10 @@ static float tx_pga0_gain_to_dac_volts(float &gain){
return dac_volts;
}
-void wbx_xcvr::set_tx_gain(float gain, const std::string &name){
+void wbx_xcvr::set_tx_gain(double gain, const std::string &name){
assert_has(wbx_tx_gain_ranges.keys(), name, "wbx tx gain name");
if(name == "PGA0"){
- float dac_volts = tx_pga0_gain_to_dac_volts(gain);
+ double dac_volts = tx_pga0_gain_to_dac_volts(gain);
_tx_gains[name] = gain;
//write the new voltage to the aux dac
@@ -250,7 +250,7 @@ void wbx_xcvr::set_tx_gain(float gain, const std::string &name){
else UHD_THROW_INVALID_CODE_PATH();
}
-void wbx_xcvr::set_rx_gain(float gain, const std::string &name){
+void wbx_xcvr::set_rx_gain(double gain, const std::string &name){
assert_has(wbx_rx_gain_ranges.keys(), name, "wbx rx gain name");
if(name == "PGA0"){
rx_pga0_gain_to_iobits(gain);
@@ -544,7 +544,7 @@ void wbx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- this->set_rx_gain(val.as<float>(), key.name);
+ this->set_rx_gain(val.as<double>(), key.name);
return;
case SUBDEV_PROP_ANTENNA:
@@ -645,7 +645,7 @@ void wbx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- this->set_tx_gain(val.as<float>(), key.name);
+ this->set_tx_gain(val.as<double>(), key.name);
return;
case SUBDEV_PROP_ANTENNA:
diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp
index e76727bec..6fb5a26a8 100644
--- a/host/lib/usrp/dboard/db_xcvr2450.cpp
+++ b/host/lib/usrp/dboard/db_xcvr2450.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -73,8 +73,8 @@ using namespace boost::assign;
static const bool xcvr2450_debug = false;
static const freq_range_t xcvr_freq_range = list_of
- (range_t<double>(2.4e9, 2.5e9))
- (range_t<double>(4.9e9, 6.0e9))
+ (range_t(2.4e9, 2.5e9))
+ (range_t(4.9e9, 6.0e9))
;
static const prop_names_t xcvr_antennas = list_of("J1")("J2");
@@ -85,9 +85,9 @@ static const uhd::dict<std::string, gain_range_t> xcvr_tx_gain_ranges = map_list
;
static const uhd::dict<std::string, gain_range_t> xcvr_rx_gain_ranges = map_list_of
("LNA", gain_range_t(list_of
- (range_t<float>(0))
- (range_t<float>(15))
- (range_t<float>(30.5))
+ (range_t(0))
+ (range_t(15))
+ (range_t(30.5))
))
("VGA", gain_range_t(0, 62, 2.0))
;
@@ -109,7 +109,7 @@ public:
private:
double _lo_freq;
double _rx_bandwidth, _tx_bandwidth;
- uhd::dict<std::string, float> _tx_gains, _rx_gains;
+ uhd::dict<std::string, double> _tx_gains, _rx_gains;
std::string _tx_ant, _rx_ant;
int _ad9515div;
max2829_regs_t _max2829_regs;
@@ -117,8 +117,8 @@ private:
void set_lo_freq(double target_freq);
void set_tx_ant(const std::string &ant);
void set_rx_ant(const std::string &ant);
- void set_tx_gain(float gain, const std::string &name);
- void set_rx_gain(float gain, const std::string &name);
+ void set_tx_gain(double gain, const std::string &name);
+ void set_rx_gain(double gain, const std::string &name);
void set_rx_bandwidth(double bandwidth);
void set_tx_bandwidth(double bandwidth);
@@ -150,12 +150,12 @@ private:
* Read the RSSI from the aux adc
* \return the rssi in dB
*/
- float get_rssi(void){
+ double get_rssi(void){
//constants for the rssi calculation
- static const float min_v = float(0.5), max_v = float(2.5);
- static const float rssi_dyn_range = 60;
+ static const double min_v = 0.5, max_v = 2.5;
+ static const double rssi_dyn_range = 60;
//calculate the rssi from the voltage
- float voltage = this->get_iface()->read_aux_adc(dboard_iface::UNIT_RX, dboard_iface::AUX_ADC_B);
+ double voltage = this->get_iface()->read_aux_adc(dboard_iface::UNIT_RX, dboard_iface::AUX_ADC_B);
return rssi_dyn_range*(voltage - min_v)/(max_v - min_v);
}
};
@@ -355,14 +355,14 @@ void xcvr2450::set_rx_ant(const std::string &ant){
* \param gain the requested gain in dB
* \return 6 bit the register value
*/
-static int gain_to_tx_vga_reg(float &gain){
+static int gain_to_tx_vga_reg(double &gain){
//calculate the register value
int reg = std::clip(boost::math::iround(gain*60/30.0) + 3, 0, 63);
//calculate the actual gain value
if (reg < 4) gain = 0;
- else if (reg < 48) gain = float(reg/2 - 1);
- else gain = float(reg/2.0 - 1.5);
+ else if (reg < 48) gain = double(reg/2 - 1);
+ else gain = double(reg/2.0 - 1.5);
//return register value
return reg;
@@ -374,7 +374,7 @@ static int gain_to_tx_vga_reg(float &gain){
* \param gain the requested gain in dB
* \return gain enum value
*/
-static max2829_regs_t::tx_baseband_gain_t gain_to_tx_bb_reg(float &gain){
+static max2829_regs_t::tx_baseband_gain_t gain_to_tx_bb_reg(double &gain){
int reg = std::clip(boost::math::iround(gain*3/5.0), 0, 3);
switch(reg){
case 0:
@@ -399,9 +399,9 @@ static max2829_regs_t::tx_baseband_gain_t gain_to_tx_bb_reg(float &gain){
* \param gain the requested gain in dB
* \return 5 bit the register value
*/
-static int gain_to_rx_vga_reg(float &gain){
+static int gain_to_rx_vga_reg(double &gain){
int reg = std::clip(boost::math::iround(gain/2.0), 0, 31);
- gain = float(reg*2);
+ gain = double(reg*2);
return reg;
}
@@ -411,7 +411,7 @@ static int gain_to_rx_vga_reg(float &gain){
* \param gain the requested gain in dB
* \return 2 bit the register value
*/
-static int gain_to_rx_lna_reg(float &gain){
+static int gain_to_rx_lna_reg(double &gain){
int reg = std::clip(boost::math::iround(gain*2/30.5) + 1, 0, 3);
switch(reg){
case 0:
@@ -422,7 +422,7 @@ static int gain_to_rx_lna_reg(float &gain){
return reg;
}
-void xcvr2450::set_tx_gain(float gain, const std::string &name){
+void xcvr2450::set_tx_gain(double gain, const std::string &name){
assert_has(xcvr_tx_gain_ranges.keys(), name, "xcvr tx gain name");
if (name == "VGA"){
_max2829_regs.tx_vga_gain = gain_to_tx_vga_reg(gain);
@@ -436,7 +436,7 @@ void xcvr2450::set_tx_gain(float gain, const std::string &name){
_tx_gains[name] = gain;
}
-void xcvr2450::set_rx_gain(float gain, const std::string &name){
+void xcvr2450::set_rx_gain(double gain, const std::string &name){
assert_has(xcvr_rx_gain_ranges.keys(), name, "xcvr rx gain name");
if (name == "VGA"){
_max2829_regs.rx_vga_gain = gain_to_rx_vga_reg(gain);
@@ -643,7 +643,7 @@ void xcvr2450::rx_set(const wax::obj &key_, const wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- this->set_rx_gain(val.as<float>(), key.name);
+ this->set_rx_gain(val.as<double>(), key.name);
return;
case SUBDEV_PROP_ANTENNA:
@@ -742,7 +742,7 @@ void xcvr2450::tx_set(const wax::obj &key_, const wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- this->set_tx_gain(val.as<float>(), key.name);
+ this->set_tx_gain(val.as<double>(), key.name);
return;
case SUBDEV_PROP_BANDWIDTH:
diff --git a/host/lib/usrp/usrp2/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp
index 2273b2cd9..3c7c00134 100644
--- a/host/lib/usrp/usrp2/gps_ctrl.cpp
+++ b/host/lib/usrp/gps_ctrl.cpp
@@ -15,7 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include "gps_ctrl.hpp"
+#include <uhd/usrp/gps_ctrl.hpp>
#include <uhd/utils/assert.hpp>
#include <boost/cstdint.hpp>
#include <string>
@@ -30,14 +30,15 @@ using namespace boost::posix_time;
using namespace boost::algorithm;
/*!
- * A usrp2 GPS control for Jackson Labs devices
+ * A GPS control for Jackson Labs devices (and other NMEA compatible GPS's)
*/
//TODO: multiple baud rate support (requires mboard_impl changes for poking UART registers)
-class usrp2_gps_ctrl_impl : public usrp2_gps_ctrl{
+class gps_ctrl_impl : public gps_ctrl{
public:
- usrp2_gps_ctrl_impl(usrp2_iface::sptr iface){
- _iface = iface;
+ gps_ctrl_impl(gps_send_fn_t send, gps_recv_fn_t recv){
+ _send = send;
+ _recv = recv;
std::string reply;
bool i_heard_some_nmea = false, i_heard_something_weird = false;
@@ -47,8 +48,8 @@ public:
// set_uart_baud_rate(GPS_UART, 115200);
//first we look for a Jackson Labs Firefly (since that's what we sell with the USRP2+...)
- _iface->read_uart(GPS_UART); //get whatever junk is in the rx buffer right now, and throw it away
- _iface->write_uart(GPS_UART, "HAAAY GUYYYYS\n"); //to elicit a response from the Firefly
+ _recv(); //get whatever junk is in the rx buffer right now, and throw it away
+ _send("HAAAY GUYYYYS\n"); //to elicit a response from the Firefly
//then we loop until we either timeout, or until we get a response that indicates we're a JL device
int timeout = GPS_TIMEOUT_TRIES;
@@ -60,13 +61,14 @@ public:
}
else if(reply.substr(0, 3) == "$GP") i_heard_some_nmea = true; //but keep looking for that "Command Error" response
else if(reply.length() != 0) i_heard_something_weird = true; //probably wrong baud rate
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
}
if((i_heard_some_nmea) && (gps_type != GPS_TYPE_JACKSON_LABS)) gps_type = GPS_TYPE_GENERIC_NMEA;
//otherwise, we can try some other common baud rates looking to see if a GPS is connected (todo, later)
if((gps_type == GPS_TYPE_NONE) && i_heard_something_weird) {
- std::cout << "Invalid reply, possible incorrect baud rate" << std::endl;
+ std::cout << "GPS invalid reply \"" << reply << "\", assuming none available" << std::endl;
}
bool found_gprmc = false;
@@ -78,15 +80,15 @@ public:
//none of these should issue replies so we don't bother looking for them
//we have to sleep between commands because the JL device, despite not acking, takes considerable time to process each command.
boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS));
- _iface->write_uart(GPS_UART, "SYST:COMM:SER:ECHO OFF\n");
+ _send("SYST:COMM:SER:ECHO OFF\n");
boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS));
- _iface->write_uart(GPS_UART, "SYST:COMM:SER:PRO OFF\n");
+ _send("SYST:COMM:SER:PRO OFF\n");
boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS));
- _iface->write_uart(GPS_UART, "GPS:GPGGA 0\n");
+ _send("GPS:GPGGA 0\n");
boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS));
- _iface->write_uart(GPS_UART, "GPS:GGAST 0\n");
+ _send("GPS:GGAST 0\n");
boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS));
- _iface->write_uart(GPS_UART, "GPS:GPRMC 1\n");
+ _send("GPS:GPRMC 1\n");
boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS));
// break;
@@ -119,15 +121,15 @@ public:
}
- ~usrp2_gps_ctrl_impl(void){
+ ~gps_ctrl_impl(void){
}
+//TODO: this isn't generalizeable to non-USRP2 USRPs.
std::string safe_gps_read() {
std::string reply;
try {
- reply = _iface->read_uart(GPS_UART);
- //std::cerr << "Got reply from GPS: " << reply.c_str() << " with length = " << reply.length() << std::endl;
+ reply = _recv();
} catch (std::runtime_error err) {
if(err.what() != std::string("usrp2 no control response")) throw; //sorry can't cope with that
else { //we don't actually have a GPS installed
@@ -185,7 +187,8 @@ public:
}
private:
- usrp2_iface::sptr _iface;
+ gps_send_fn_t _send;
+ gps_recv_fn_t _recv;
enum {
GPS_TYPE_JACKSON_LABS,
@@ -193,8 +196,8 @@ private:
GPS_TYPE_NONE
} gps_type;
- static const int GPS_UART = 2; //TODO: this should be plucked from fw_common.h or memory_map.h or somewhere in common with the firmware
static const int GPS_TIMEOUT_TRIES = 5;
+ static const int GPS_TIMEOUT_DELAY_MS = 200;
static const int FIREFLY_STUPID_DELAY_MS = 200;
};
@@ -202,6 +205,6 @@ private:
/***********************************************************************
* Public make function for the GPS control
**********************************************************************/
-usrp2_gps_ctrl::sptr usrp2_gps_ctrl::make(usrp2_iface::sptr iface){
- return sptr(new usrp2_gps_ctrl_impl(iface));
+gps_ctrl::sptr gps_ctrl::make(gps_send_fn_t send, gps_recv_fn_t recv){
+ return sptr(new gps_ctrl_impl(send, recv));
}
diff --git a/host/lib/usrp/mboard_eeprom.cpp b/host/lib/usrp/mboard_eeprom.cpp
index 863a80191..f7f4b2c68 100644
--- a/host/lib/usrp/mboard_eeprom.cpp
+++ b/host/lib/usrp/mboard_eeprom.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -97,8 +97,14 @@ static void load_n100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
N100_EEPROM_ADDR, USRP_N100_OFFSETS["name"], NAME_MAX_LEN
));
- //empty serial correction: use the mac address
- if (mb_eeprom["serial"].empty()) mb_eeprom["serial"] = mb_eeprom["mac-addr"];
+ //Empty serial correction: use the mac address to determine serial.
+ //Older usrp2 models don't have a serial burned into EEPROM.
+ //The lower mac address bits will function as the serial number.
+ if (mb_eeprom["serial"].empty()){
+ byte_vector_t mac_addr_bytes = mac_addr_t::from_string(mb_eeprom["mac-addr"]).to_bytes();
+ unsigned serial = mac_addr_bytes.at(5) | (unsigned(mac_addr_bytes.at(4) & 0x0f) << 8);
+ mb_eeprom["serial"] = boost::lexical_cast<std::string>(serial);
+ }
}
static void store_n100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp
index 5856d706f..02f4b216d 100644
--- a/host/lib/usrp/misc_utils.cpp
+++ b/host/lib/usrp/misc_utils.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -39,24 +39,24 @@ static gain_range_t get_codec_gain_range(wax::obj codec, const std::string &name
return codec[named_prop_t(CODEC_PROP_GAIN_RANGE, name)].as<gain_range_t>();
}
-static float get_codec_gain_i(wax::obj codec, const std::string &name){
- return codec[named_prop_t(CODEC_PROP_GAIN_I, name)].as<float>();
+static double get_codec_gain_i(wax::obj codec, const std::string &name){
+ return codec[named_prop_t(CODEC_PROP_GAIN_I, name)].as<double>();
}
-static float get_codec_gain_q(wax::obj codec, const std::string &name){
- return codec[named_prop_t(CODEC_PROP_GAIN_Q, name)].as<float>();
+static double get_codec_gain_q(wax::obj codec, const std::string &name){
+ return codec[named_prop_t(CODEC_PROP_GAIN_Q, name)].as<double>();
}
-static void set_codec_gain_both(wax::obj codec, const std::string &name, float gain){
+static void set_codec_gain_both(wax::obj codec, const std::string &name, double gain){
codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain;
codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain;
}
-static void set_codec_gain_i(wax::obj codec, const std::string &name, float gain){
+static void set_codec_gain_i(wax::obj codec, const std::string &name, double gain){
codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain;
}
-static void set_codec_gain_q(wax::obj codec, const std::string &name, float gain){
+static void set_codec_gain_q(wax::obj codec, const std::string &name, double gain){
codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain;
}
@@ -64,15 +64,15 @@ static void set_codec_gain_q(wax::obj codec, const std::string &name, float gain
* subdev gain group helper functions:
* do this so we dont have to bind a templated function
**********************************************************************/
-static float get_subdev_gain(wax::obj subdev, const std::string &name){
- return subdev[named_prop_t(SUBDEV_PROP_GAIN, name)].as<float>();
+static double get_subdev_gain(wax::obj subdev, const std::string &name){
+ return subdev[named_prop_t(SUBDEV_PROP_GAIN, name)].as<double>();
}
static gain_range_t get_subdev_gain_range(wax::obj subdev, const std::string &name){
return subdev[named_prop_t(SUBDEV_PROP_GAIN_RANGE, name)].as<gain_range_t>();
}
-static void set_subdev_gain(wax::obj subdev, const std::string &name, float gain){
+static void set_subdev_gain(wax::obj subdev, const std::string &name, double gain){
subdev[named_prop_t(SUBDEV_PROP_GAIN, name)] = gain;
}
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index 876f1a3fc..48eec28c1 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -117,26 +117,32 @@ public:
return _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
}
+ time_spec_t get_time_last_pps(void){
+ return _mboard(0)[MBOARD_PROP_TIME_PPS].as<time_spec_t>();
+ }
+
void set_time_next_pps(const time_spec_t &time_spec){
for (size_t m = 0; m < get_num_mboards(); m++){
- _mboard(m)[MBOARD_PROP_TIME_NEXT_PPS] = time_spec;
+ _mboard(m)[MBOARD_PROP_TIME_PPS] = time_spec;
}
}
void set_time_unknown_pps(const time_spec_t &time_spec){
- std::cout << "Set time with unknown pps edge:" << std::endl;
- std::cout << " 1) set times next pps (race condition)" << std::endl;
- set_time_next_pps(time_spec);
- boost::this_thread::sleep(boost::posix_time::seconds(1));
-
- std::cout << " 2) catch seconds rollover at pps edge" << std::endl;
- time_t last_secs = 0, curr_secs = 0;
- while(curr_secs == last_secs){
- last_secs = curr_secs;
- curr_secs = get_time_now().get_full_secs();
+ std::cout << " 1) catch time transition at pps edge" << std::endl;
+ time_spec_t time_start = get_time_now();
+ time_spec_t time_start_last_pps = get_time_last_pps();
+ while(true){
+ if (get_time_last_pps() != time_start_last_pps) break;
+ if ((get_time_now() - time_start) > time_spec_t(1.1)){
+ throw std::runtime_error(
+ "Board 0 may not be getting a PPS signal!\n"
+ "No PPS detected within the time interval.\n"
+ "See the application notes for your device.\n"
+ );
+ }
}
- std::cout << " 3) set times next pps (synchronously)" << std::endl;
+ std::cout << " 2) set times next pps (synchronously)" << std::endl;
set_time_next_pps(time_spec);
boost::this_thread::sleep(boost::posix_time::seconds(1));
@@ -233,11 +239,11 @@ public:
return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp(chan/rx_cpm()));
}
- void set_rx_gain(float gain, const std::string &name, size_t chan){
+ void set_rx_gain(double gain, const std::string &name, size_t chan){
return _rx_gain_group(chan)->set_value(gain, name);
}
- float get_rx_gain(const std::string &name, size_t chan){
+ double get_rx_gain(const std::string &name, size_t chan){
return _rx_gain_group(chan)->get_value(name);
}
@@ -273,8 +279,8 @@ public:
return _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH].as<double>();
}
- float read_rssi(size_t chan){
- return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as<float>();
+ double read_rssi(size_t chan){
+ return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as<double>();
}
dboard_iface::sptr get_rx_dboard_iface(size_t chan){
@@ -331,11 +337,11 @@ public:
return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp(chan/tx_cpm()));
}
- void set_tx_gain(float gain, const std::string &name, size_t chan){
+ void set_tx_gain(double gain, const std::string &name, size_t chan){
return _tx_gain_group(chan)->set_value(gain, name);
}
- float get_tx_gain(const std::string &name, size_t chan){
+ double get_tx_gain(const std::string &name, size_t chan){
return _tx_gain_group(chan)->get_value(name);
}
diff --git a/host/lib/usrp/single_usrp.cpp b/host/lib/usrp/single_usrp.cpp
index a0456d1f0..c37449c5f 100644
--- a/host/lib/usrp/single_usrp.cpp
+++ b/host/lib/usrp/single_usrp.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -106,12 +106,16 @@ public:
return _mboard()[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
}
+ time_spec_t get_time_last_pps(void){
+ return _mboard()[MBOARD_PROP_TIME_PPS].as<time_spec_t>();
+ }
+
void set_time_now(const time_spec_t &time_spec){
_mboard()[MBOARD_PROP_TIME_NOW] = time_spec;
}
void set_time_next_pps(const time_spec_t &time_spec){
- _mboard()[MBOARD_PROP_TIME_NEXT_PPS] = time_spec;
+ _mboard()[MBOARD_PROP_TIME_PPS] = time_spec;
}
void issue_stream_cmd(const stream_cmd_t &stream_cmd){
@@ -160,11 +164,11 @@ public:
return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp());
}
- void set_rx_gain(float gain, const std::string &name, size_t chan){
+ void set_rx_gain(double gain, const std::string &name, size_t chan){
return _rx_gain_group(chan)->set_value(gain, name);
}
- float get_rx_gain(const std::string &name, size_t chan){
+ double get_rx_gain(const std::string &name, size_t chan){
return _rx_gain_group(chan)->get_value(name);
}
@@ -200,8 +204,8 @@ public:
return _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH].as<double>();
}
- float read_rssi(size_t chan){
- return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as<float>();
+ double read_rssi(size_t chan){
+ return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as<double>();
}
dboard_iface::sptr get_rx_dboard_iface(size_t chan){
@@ -246,11 +250,11 @@ public:
return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp());
}
- void set_tx_gain(float gain, const std::string &name, size_t chan){
+ void set_tx_gain(double gain, const std::string &name, size_t chan){
return _tx_gain_group(chan)->set_value(gain, name);
}
- float get_tx_gain(const std::string &name, size_t chan){
+ double get_tx_gain(const std::string &name, size_t chan){
return _tx_gain_group(chan)->get_value(name);
}
diff --git a/host/lib/usrp/subdev_spec.cpp b/host/lib/usrp/subdev_spec.cpp
index 95d2cbb12..51c88bda3 100644
--- a/host/lib/usrp/subdev_spec.cpp
+++ b/host/lib/usrp/subdev_spec.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -16,15 +16,21 @@
//
#include <uhd/usrp/subdev_spec.hpp>
-#include <uhd/utils/algorithm.hpp>
+#include <boost/algorithm/string.hpp> //for split
+#include <boost/tokenizer.hpp>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <stdexcept>
#include <sstream>
+#include <vector>
using namespace uhd;
using namespace uhd::usrp;
+#define pair_tokenizer(inp) \
+ boost::tokenizer<boost::char_separator<char> > \
+ (inp, boost::char_separator<char>(" "))
+
subdev_spec_pair_t::subdev_spec_pair_t(
const std::string &db_name, const std::string &sd_name
):
@@ -39,9 +45,9 @@ bool usrp::operator==(const subdev_spec_pair_t &lhs, const subdev_spec_pair_t &r
}
subdev_spec_t::subdev_spec_t(const std::string &markup){
- BOOST_FOREACH(const std::string &pair, std::split_string(markup)){
+ BOOST_FOREACH(const std::string &pair, pair_tokenizer(markup)){
if (pair == "") continue;
- std::vector<std::string> db_sd = std::split_string(pair, ":");
+ std::vector<std::string> db_sd; boost::split(db_sd, pair, boost::is_any_of(":"));
switch(db_sd.size()){
case 1: this->push_back(subdev_spec_pair_t("", db_sd.front())); break;
case 2: this->push_back(subdev_spec_pair_t(db_sd.front(), db_sd.back())); break;
diff --git a/host/lib/usrp/usrp1/CMakeLists.txt b/host/lib/usrp/usrp1/CMakeLists.txt
index 519e17bfa..9e50f5728 100644
--- a/host/lib/usrp/usrp1/CMakeLists.txt
+++ b/host/lib/usrp/usrp1/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2010 Ettus Research LLC
+# Copyright 2010-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
@@ -38,6 +38,7 @@ IF(ENABLE_USRP1)
${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/soft_time_ctrl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/usrp1_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/usrp1_iface.hpp
${CMAKE_CURRENT_SOURCE_DIR}/usrp1_impl.cpp
diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp
index 18f794632..f3816b377 100644
--- a/host/lib/usrp/usrp1/codec_ctrl.cpp
+++ b/host/lib/usrp/usrp1/codec_ctrl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -35,7 +35,7 @@ using namespace uhd;
static const bool codec_debug = false;
-const gain_range_t usrp1_codec_ctrl::tx_pga_gain_range(-20, 0, float(0.1));
+const gain_range_t usrp1_codec_ctrl::tx_pga_gain_range(-20, 0, double(0.1));
const gain_range_t usrp1_codec_ctrl::rx_pga_gain_range(0, 20, 1);
/***********************************************************************
@@ -50,17 +50,18 @@ public:
~usrp1_codec_ctrl_impl(void);
//aux adc and dac control
- float read_aux_adc(aux_adc_t which);
- void write_aux_dac(aux_dac_t which, float volts);
+ double read_aux_adc(aux_adc_t which);
+ void write_aux_dac(aux_dac_t which, double volts);
//duc control
void set_duc_freq(double freq);
+ void enable_tx_digital(bool enb);
//pga gain control
- void set_tx_pga_gain(float);
- float get_tx_pga_gain(void);
- void set_rx_pga_gain(float, char);
- float get_rx_pga_gain(char);
+ void set_tx_pga_gain(double);
+ double get_tx_pga_gain(void);
+ void set_rx_pga_gain(double, char);
+ double get_rx_pga_gain(char);
//rx adc buffer control
void bypass_adc_buffers(bool bypass);
@@ -159,19 +160,19 @@ usrp1_codec_ctrl_impl::~usrp1_codec_ctrl_impl(void)
**********************************************************************/
static const int mtpgw = 255; //maximum tx pga gain word
-void usrp1_codec_ctrl_impl::set_tx_pga_gain(float gain){
+void usrp1_codec_ctrl_impl::set_tx_pga_gain(double gain){
int gain_word = int(mtpgw*(gain - tx_pga_gain_range.start())/(tx_pga_gain_range.stop() - tx_pga_gain_range.start()));
_ad9862_regs.tx_pga_gain = std::clip(gain_word, 0, mtpgw);
this->send_reg(16);
}
-float usrp1_codec_ctrl_impl::get_tx_pga_gain(void){
+double usrp1_codec_ctrl_impl::get_tx_pga_gain(void){
return (_ad9862_regs.tx_pga_gain*(tx_pga_gain_range.stop() - tx_pga_gain_range.start())/mtpgw) + tx_pga_gain_range.start();
}
static const int mrpgw = 0x14; //maximum rx pga gain word
-void usrp1_codec_ctrl_impl::set_rx_pga_gain(float gain, char which){
+void usrp1_codec_ctrl_impl::set_rx_pga_gain(double gain, char which){
int gain_word = int(mrpgw*(gain - rx_pga_gain_range.start())/(rx_pga_gain_range.stop() - rx_pga_gain_range.start()));
gain_word = std::clip(gain_word, 0, mrpgw);
switch(which){
@@ -187,7 +188,7 @@ void usrp1_codec_ctrl_impl::set_rx_pga_gain(float gain, char which){
}
}
-float usrp1_codec_ctrl_impl::get_rx_pga_gain(char which){
+double usrp1_codec_ctrl_impl::get_rx_pga_gain(char which){
int gain_word;
switch(which){
case 'A': gain_word = _ad9862_regs.rx_pga_a; break;
@@ -200,12 +201,12 @@ float usrp1_codec_ctrl_impl::get_rx_pga_gain(char which){
/***********************************************************************
* Codec Control AUX ADC Methods
**********************************************************************/
-static float aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low)
+static double aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low)
{
- return float(((boost::uint16_t(high) << 2) | low)*3.3)/0x3ff;
+ return double(((boost::uint16_t(high) << 2) | low)*3.3)/0x3ff;
}
-float usrp1_codec_ctrl_impl::read_aux_adc(aux_adc_t which)
+double usrp1_codec_ctrl_impl::read_aux_adc(aux_adc_t which)
{
//check to see if the switch needs to be set
bool write_switch = false;
@@ -259,7 +260,7 @@ float usrp1_codec_ctrl_impl::read_aux_adc(aux_adc_t which)
/***********************************************************************
* Codec Control AUX DAC Methods
**********************************************************************/
-void usrp1_codec_ctrl_impl::write_aux_dac(aux_dac_t which, float volts)
+void usrp1_codec_ctrl_impl::write_aux_dac(aux_dac_t which, double volts)
{
//special case for aux dac d (aka sigma delta word)
if (which == AUX_DAC_D) {
@@ -421,6 +422,11 @@ void usrp1_codec_ctrl_impl::set_duc_freq(double freq)
this->send_reg(23);
}
+void usrp1_codec_ctrl_impl::enable_tx_digital(bool enb){
+ _ad9862_regs.tx_digital_pd = (enb)? 0 : 1;
+ this->send_reg(8);
+}
+
/***********************************************************************
* Codec Control ADC buffer bypass
* Disable this for AC-coupled daughterboards (TVRX)
diff --git a/host/lib/usrp/usrp1/codec_ctrl.hpp b/host/lib/usrp/usrp1/codec_ctrl.hpp
index e2e8a010d..20e4015c5 100644
--- a/host/lib/usrp/usrp1/codec_ctrl.hpp
+++ b/host/lib/usrp/usrp1/codec_ctrl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -61,7 +61,7 @@ public:
* \param which which of the 4 adcs
* \return a value in volts
*/
- virtual float read_aux_adc(aux_adc_t which) = 0;
+ virtual double read_aux_adc(aux_adc_t which) = 0;
//! aux dac identifier constants
enum aux_dac_t{
@@ -76,23 +76,26 @@ public:
* \param which which of the 4 dacs
* \param volts the level in in volts
*/
- virtual void write_aux_dac(aux_dac_t which, float volts) = 0;
+ virtual void write_aux_dac(aux_dac_t which, double volts) = 0;
//! Set the TX PGA gain
- virtual void set_tx_pga_gain(float gain) = 0;
+ virtual void set_tx_pga_gain(double gain) = 0;
//! Get the TX PGA gain
- virtual float get_tx_pga_gain(void) = 0;
+ virtual double get_tx_pga_gain(void) = 0;
//! Set the RX PGA gain ('A' or 'B')
- virtual void set_rx_pga_gain(float gain, char which) = 0;
+ virtual void set_rx_pga_gain(double gain, char which) = 0;
//! Get the RX PGA gain ('A' or 'B')
- virtual float get_rx_pga_gain(char which) = 0;
+ virtual double get_rx_pga_gain(char which) = 0;
//! Set the TX modulator frequency
virtual void set_duc_freq(double freq) = 0;
-
+
+ //! Enable or disable the digital part of the DAC
+ virtual void enable_tx_digital(bool enb) = 0;
+
//! Enable or disable ADC buffer bypass
virtual void bypass_adc_buffers(bool bypass) = 0;
};
diff --git a/host/lib/usrp/usrp1/codec_impl.cpp b/host/lib/usrp/usrp1/codec_impl.cpp
index db53be53e..14ecd2d2e 100644
--- a/host/lib/usrp/usrp1/codec_impl.cpp
+++ b/host/lib/usrp/usrp1/codec_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -92,12 +92,12 @@ void usrp1_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val, dboard_
switch(key.as<codec_prop_t>()) {
case CODEC_PROP_GAIN_I:
UHD_ASSERT_THROW(key.name == adc_pga_gain_name);
- _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as<float>(), 'A');
+ _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as<double>(), 'A');
return;
case CODEC_PROP_GAIN_Q:
UHD_ASSERT_THROW(key.name == adc_pga_gain_name);
- _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as<float>(), 'B');
+ _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as<double>(), 'B');
return;
default: UHD_THROW_PROP_SET_ERROR();
@@ -151,7 +151,7 @@ void usrp1_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val, dboard_
case CODEC_PROP_GAIN_I: //only one gain for I and Q
case CODEC_PROP_GAIN_Q:
UHD_ASSERT_THROW(key.name == dac_pga_gain_name);
- _codec_ctrls[dboard_slot]->set_tx_pga_gain(val.as<float>());
+ _codec_ctrls[dboard_slot]->set_tx_pga_gain(val.as<double>());
return;
default: UHD_THROW_PROP_SET_ERROR();
diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp
index 4e47d6bf6..eec4a52db 100644
--- a/host/lib/usrp/usrp1/dboard_iface.cpp
+++ b/host/lib/usrp/usrp1/dboard_iface.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -72,8 +72,8 @@ public:
return props;
}
- void write_aux_dac(unit_t, aux_dac_t, float);
- float read_aux_adc(unit_t, aux_adc_t);
+ void write_aux_dac(unit_t, aux_dac_t, double);
+ double read_aux_adc(unit_t, aux_adc_t);
void _set_pin_ctrl(unit_t, boost::uint16_t);
void _set_atr_reg(unit_t, atr_reg_t, boost::uint16_t);
@@ -369,7 +369,7 @@ byte_vector_t usrp1_dboard_iface::read_i2c(boost::uint8_t addr,
* Aux DAX/ADC
**********************************************************************/
void usrp1_dboard_iface::write_aux_dac(dboard_iface::unit_t,
- aux_dac_t which, float value)
+ aux_dac_t which, double value)
{
//same aux dacs for each unit
static const uhd::dict<aux_dac_t, usrp1_codec_ctrl::aux_dac_t>
@@ -382,7 +382,7 @@ void usrp1_dboard_iface::write_aux_dac(dboard_iface::unit_t,
_codec->write_aux_dac(which_to_aux_dac[which], value);
}
-float usrp1_dboard_iface::read_aux_adc(dboard_iface::unit_t unit,
+double usrp1_dboard_iface::read_aux_adc(dboard_iface::unit_t unit,
aux_adc_t which)
{
static const
diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp
index 6728d9b15..9fa1b4f72 100644
--- a/host/lib/usrp/usrp1/io_impl.cpp
+++ b/host/lib/usrp/usrp1/io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -19,7 +19,6 @@
#include "usrp_commands.h"
#include "usrp1_impl.hpp"
#include <uhd/utils/thread_priority.hpp>
-#include <uhd/transport/convert_types.hpp>
#include <uhd/transport/bounded_buffer.hpp>
#include <boost/bind.hpp>
#include <boost/format.hpp>
@@ -92,6 +91,7 @@ struct usrp1_impl::io_impl{
void commit_send_buff(offset_send_buffer::sptr, offset_send_buffer::sptr, size_t);
void flush_send_buff(void);
bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &, double);
+ bool transmitting_enb;
};
/*!
@@ -184,6 +184,28 @@ void usrp1_impl::io_init(void){
_tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
_io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport));
+
+ _soft_time_ctrl = soft_time_ctrl::make(
+ boost::bind(&usrp1_impl::rx_stream_on_off, this, _1)
+ );
+
+ rx_stream_on_off(false);
+ tx_stream_on_off(false);
+}
+
+void usrp1_impl::rx_stream_on_off(bool enb){
+ return _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, enb, 0, 0, 0);
+ //drain any junk in the receive transport after stop streaming command
+ while(not enb and _data_transport->get_recv_buff().get() != NULL){
+ /* NOP */
+ }
+}
+
+void usrp1_impl::tx_stream_on_off(bool enb){
+ if (not enb) _io_impl->flush_send_buff();
+ _codec_ctrls[DBOARD_SLOT_A]->enable_tx_digital(enb);
+ _codec_ctrls[DBOARD_SLOT_B]->enable_tx_digital(enb);
+ _io_impl->transmitting_enb = enb;
}
/***********************************************************************
@@ -209,6 +231,9 @@ size_t usrp1_impl::send(
const tx_metadata_t &metadata, const io_type_t &io_type,
send_mode_t send_mode, double timeout
){
+ if (_soft_time_ctrl->send_pre(metadata, timeout)) return num_samps;
+ if (not _io_impl->transmitting_enb) tx_stream_on_off(true);
+
size_t num_samps_sent = vrt_packet_handler::send(
_io_impl->packet_handler_send_state, //last state of the send handler
buffs, num_samps, //buffer to fill
@@ -222,9 +247,11 @@ size_t usrp1_impl::send(
_tx_subdev_spec.size() //num channels
);
- //Don't honor sob because it is normal to be always bursting...
- //handle eob flag (commit the buffer)
- if (metadata.end_of_burst) _io_impl->flush_send_buff();
+ //handle eob flag (commit the buffer, disable the DACs)
+ //check num samps sent to avoid flush on incomplete/timeout
+ if (metadata.end_of_burst and num_samps_sent == num_samps){
+ this->tx_stream_on_off(false);
+ }
//handle the polling for underflow conditions
_io_impl->underflow_poll_samp_count += num_samps_sent;
@@ -296,6 +323,8 @@ size_t usrp1_impl::recv(
_rx_subdev_spec.size() //num channels
);
+ _soft_time_ctrl->recv_post(metadata, num_samps_recvd);
+
//handle the polling for overflow conditions
_io_impl->overflow_poll_samp_count += num_samps_recvd;
if (_io_impl->overflow_poll_samp_count >= _rx_samps_per_poll_interval){
diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp
index 4df5ada0a..23c8f03c4 100644
--- a/host/lib/usrp/usrp1/mboard_impl.cpp
+++ b/host/lib/usrp/usrp1/mboard_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -240,19 +240,6 @@ void usrp1_impl::mboard_init(void)
}
}
-void usrp1_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd)
-{
- switch(stream_cmd.stream_mode){
- case stream_cmd_t::STREAM_MODE_START_CONTINUOUS:
- return _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, true, 0, 0, 0);
-
- case stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS:
- return _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, false, 0, 0, 0);
-
- default: throw std::runtime_error("unsupported stream command type for USRP1");
- }
-}
-
/***********************************************************************
* Mboard Get
**********************************************************************/
@@ -326,6 +313,10 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val)
val = _iface->mb_eeprom;
return;
+ case MBOARD_PROP_TIME_NOW:
+ val = _soft_time_ctrl->get_time();
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -348,7 +339,7 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val)
switch(key.as<mboard_prop_t>()){
case MBOARD_PROP_STREAM_CMD:
- issue_stream_cmd(val.as<stream_cmd_t>());
+ _soft_time_ctrl->issue_stream_cmd(val.as<stream_cmd_t>());
return;
case MBOARD_PROP_RX_SUBDEV_SPEC:
@@ -384,6 +375,10 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val)
_iface->mb_eeprom = mboard_eeprom_t(*_iface, mboard_eeprom_t::MAP_B000);
return;
+ case MBOARD_PROP_TIME_NOW:
+ _soft_time_ctrl->set_time(val.as<time_spec_t>());
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.cpp b/host/lib/usrp/usrp1/soft_time_ctrl.cpp
new file mode 100644
index 000000000..4d6abe218
--- /dev/null
+++ b/host/lib/usrp/usrp1/soft_time_ctrl.cpp
@@ -0,0 +1,224 @@
+//
+// 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 "soft_time_ctrl.hpp"
+#include <uhd/transport/bounded_buffer.hpp>
+#include <boost/any.hpp>
+#include <boost/thread.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/local_time/local_time.hpp>
+#include <iostream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace uhd::transport;
+namespace pt = boost::posix_time;
+namespace lt = boost::local_time;
+
+static const time_spec_t TWIDDLE(0.0015);
+
+/***********************************************************************
+ * Utility helper functions
+ **********************************************************************/
+
+//TODO put these in time_spec_t (maybe useful)
+
+static const double time_dur_tps = double(pt::time_duration::ticks_per_second());
+
+time_spec_t time_dur_to_time_spec(const pt::time_duration &time_dur){
+ return time_spec_t(
+ time_dur.total_seconds(),
+ long(time_dur.fractional_seconds()),
+ time_dur_tps
+ );
+}
+
+pt::time_duration time_spec_to_time_dur(const time_spec_t &time_spec){
+ return pt::time_duration(
+ 0, 0, long(time_spec.get_full_secs()),
+ time_spec.get_tick_count(time_dur_tps)
+ );
+}
+
+/***********************************************************************
+ * Soft time control implementation
+ **********************************************************************/
+class soft_time_ctrl_impl : public soft_time_ctrl{
+public:
+
+ soft_time_ctrl_impl(const cb_fcn_type &stream_on_off):
+ _nsamps_remaining(0),
+ _stream_mode(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS),
+ _cmd_queue(bounded_buffer<boost::any>::make(2)),
+ _stream_on_off(stream_on_off)
+ {
+ //synchronously spawn a new thread
+ _update_mutex.lock(); //lock mutex before spawned
+ _thread_group.create_thread(boost::bind(&soft_time_ctrl_impl::recv_cmd_dispatcher, this));
+ _update_mutex.lock(); //lock blocks until spawned
+ _update_mutex.unlock(); //unlock mutex before done
+ }
+
+ ~soft_time_ctrl_impl(void){
+ _thread_group.interrupt_all();
+ _thread_group.join_all();
+ }
+
+ /*******************************************************************
+ * Time control
+ ******************************************************************/
+ void set_time(const time_spec_t &time){
+ boost::mutex::scoped_lock lock(_update_mutex);
+ _time_offset = boost::get_system_time() - time_spec_to_time_dur(time);
+ }
+
+ time_spec_t get_time(void){
+ boost::mutex::scoped_lock lock(_update_mutex);
+ return time_now();
+ }
+
+ UHD_INLINE time_spec_t time_now(void){
+ //internal get time without scoped lock
+ return time_dur_to_time_spec(boost::get_system_time() - _time_offset);
+ }
+
+ UHD_INLINE void sleep_until_time(
+ boost::mutex::scoped_lock &lock, const time_spec_t &time
+ ){
+ boost::condition_variable cond;
+ //use a condition variable to unlock, sleep, lock
+ cond.timed_wait(lock, _time_offset + time_spec_to_time_dur(time));
+ }
+
+ /*******************************************************************
+ * Receive control
+ ******************************************************************/
+ void recv_post(rx_metadata_t &md, size_t &nsamps){
+ boost::mutex::scoped_lock lock(_update_mutex);
+
+ //load the metadata with the expected time
+ md.has_time_spec = true;
+ md.time_spec = time_now();
+
+ //none of the stuff below matters in continuous streaming mode
+ if (_stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS) return;
+
+ //When to stop streaming:
+ //The samples have been received and the stream mode is non-continuous.
+ //Rewrite the sample count to clip to the requested number of samples.
+ if (_nsamps_remaining <= nsamps){
+ nsamps = _nsamps_remaining; //set nsamps, then stop
+ md.end_of_burst = true;
+ stream_on_off(false);
+ return;
+ }
+
+ //update the consumed samples
+ _nsamps_remaining -= nsamps;
+ }
+
+ void issue_stream_cmd(const stream_cmd_t &cmd){
+ _cmd_queue->push_with_wait(cmd);
+ }
+
+ void stream_on_off(bool enb){
+ _stream_on_off(enb);
+ _nsamps_remaining = 0;
+ }
+
+ /*******************************************************************
+ * Transmit control
+ ******************************************************************/
+ bool send_pre(const tx_metadata_t &md, double &timeout){
+ if (not md.has_time_spec) return false;
+
+ boost::mutex::scoped_lock lock(_update_mutex);
+
+ time_spec_t time_at(md.time_spec - TWIDDLE);
+
+ //handle late packets
+ if (time_at < time_now()){
+ //TODO post async message
+ return true;
+ }
+
+ timeout -= (time_at - time_now()).get_real_secs();
+ sleep_until_time(lock, time_at);
+ return false;
+ }
+
+ /*******************************************************************
+ * Thread control
+ ******************************************************************/
+ void recv_cmd_handle_cmd(const stream_cmd_t &cmd){
+ boost::mutex::scoped_lock lock(_update_mutex);
+
+ //handle the stream at time by sleeping
+ if (not cmd.stream_now){
+ time_spec_t time_at(cmd.time_spec - TWIDDLE);
+ if (time_at < time_now()){
+ //TODO inject late cmd inline error
+ }
+ else{
+ sleep_until_time(lock, time_at);
+ }
+ }
+
+ //When to stop streaming:
+ //Stop streaming when the command is a stop and streaming.
+ if (cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS
+ and _stream_mode != stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS
+ ) stream_on_off(false);
+
+ //When to start streaming:
+ //Start streaming when the command is not a stop and not streaming.
+ if (cmd.stream_mode != stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS
+ and _stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS
+ ) stream_on_off(true);
+
+ //update the state
+ _nsamps_remaining += cmd.num_samps;
+ _stream_mode = cmd.stream_mode;
+ }
+
+ void recv_cmd_dispatcher(void){
+ _update_mutex.unlock();
+ try{
+ boost::any cmd;
+ while (true){
+ _cmd_queue->pop_with_wait(cmd);
+ recv_cmd_handle_cmd(boost::any_cast<stream_cmd_t>(cmd));
+ }
+ } catch(const boost::thread_interrupted &){}
+ }
+
+private:
+ boost::mutex _update_mutex;
+ size_t _nsamps_remaining;
+ stream_cmd_t::stream_mode_t _stream_mode;
+ pt::ptime _time_offset;
+ bounded_buffer<boost::any>::sptr _cmd_queue;
+ const cb_fcn_type _stream_on_off;
+ boost::thread_group _thread_group;
+};
+
+/***********************************************************************
+ * Soft time control factor
+ **********************************************************************/
+soft_time_ctrl::sptr soft_time_ctrl::make(const cb_fcn_type &stream_on_off){
+ return sptr(new soft_time_ctrl_impl(stream_on_off));
+}
diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.hpp b/host/lib/usrp/usrp1/soft_time_ctrl.hpp
new file mode 100644
index 000000000..7fdac7fc8
--- /dev/null
+++ b/host/lib/usrp/usrp1/soft_time_ctrl.hpp
@@ -0,0 +1,69 @@
+//
+// 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_USRP1_SOFT_TIME_CTRL_HPP
+#define INCLUDED_LIBUHD_USRP_USRP1_SOFT_TIME_CTRL_HPP
+
+#include <uhd/types/stream_cmd.hpp>
+#include <uhd/types/time_spec.hpp>
+#include <uhd/types/metadata.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+
+namespace uhd{ namespace usrp{
+
+/*!
+ * The soft time control emulates some of the
+ * advanced streaming capabilities of the later USRP models.
+ * Soft time control uses the system time to emulate
+ * timed transmits, timed receive commands, device time,
+ * and inline and async error messages.
+ */
+class soft_time_ctrl : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<soft_time_ctrl> sptr;
+ typedef boost::function<void(bool)> cb_fcn_type;
+
+ /*!
+ * Make a new soft time control.
+ * \param stream_on_off a function to enable/disable rx
+ * \return a new soft time control object
+ */
+ static sptr make(const cb_fcn_type &stream_on_off);
+ //TODO pass in the error queue for async msgs
+ //TODO pass in the queue for inline msgs
+
+ //! Set the current time
+ virtual void set_time(const time_spec_t &time) = 0;
+
+ //! Get the current time
+ virtual time_spec_t get_time(void) = 0;
+
+ //! Call after the internal recv function
+ virtual void recv_post(rx_metadata_t &md, size_t &nsamps) = 0;
+
+ //! Call before the internal send function
+ virtual bool send_pre(const tx_metadata_t &md, double &timeout) = 0;
+
+ //! Issue a stream command to receive
+ virtual void issue_stream_cmd(const stream_cmd_t &cmd) = 0;
+};
+
+}} //namespace
+
+#endif /* INCLUDED_LIBUHD_USRP_USRP1_SOFT_TIME_CTRL_HPP */
diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp
index 5043aed7d..09f854813 100644
--- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp
@@ -139,13 +139,6 @@ public:
_ctrl_transport = ctrl_transport;
}
-
- ~usrp_ctrl_impl(void)
- {
- /* NOP */
- }
-
-
int usrp_load_firmware(std::string filestring, bool force)
{
const char *filename = filestring.c_str();
@@ -233,6 +226,20 @@ public:
return -1;
}
+ void usrp_init(void){
+ /* not calling because this causes junk to come at init
+ * and it does not seem to be necessary to call anyway
+ usrp_rx_enable(false);
+ usrp_rx_reset(true);
+ usrp_rx_reset(false);
+ usrp_rx_enable(true);
+ */
+
+ usrp_tx_enable(false);
+ usrp_tx_reset(true);
+ usrp_tx_reset(false);
+ usrp_tx_enable(true);
+ }
int usrp_load_fpga(std::string filestring)
{
@@ -288,7 +295,7 @@ public:
usrp_set_fpga_hash(hash);
file.close();
if (load_img_msg) std::cout << " done" << std::endl;
- return 0;
+ return 0;
}
int usrp_load_eeprom(std::string filestring)
@@ -393,6 +400,12 @@ public:
}
+ int usrp_rx_reset(bool on)
+ {
+ return usrp_control_write_cmd(VRQ_FPGA_SET_RX_RESET, on, 0);
+ }
+
+
int usrp_control_write(boost::uint8_t request,
boost::uint16_t value,
boost::uint16_t index,
diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.hpp b/host/lib/usrp/usrp1/usrp1_ctrl.hpp
index a02d9f96c..8ccfacab7 100644
--- a/host/lib/usrp/usrp1/usrp1_ctrl.hpp
+++ b/host/lib/usrp/usrp1/usrp1_ctrl.hpp
@@ -33,6 +33,9 @@ public:
*/
static sptr make(uhd::transport::usb_control::sptr ctrl_transport);
+ //! Call init after the fpga is loaded
+ virtual void usrp_init(void) = 0;
+
/*!
* Load firmware in Intel HEX Format onto device
* \param filename name of firmware file
@@ -93,20 +96,6 @@ public:
virtual int usrp_set_fpga_hash(size_t hash) = 0;
/*!
- * Set rx enable or disable
- * \param on enable or disable value
- * \return 0 on success, error code otherwise
- */
- virtual int usrp_rx_enable(bool on) = 0;
-
- /*!
- * Set rx enable or disable
- * \param on enable or disable value
- * \return 0 on success, error code otherwise
- */
- virtual int usrp_tx_enable(bool on) = 0;
-
- /*!
* Submit an IN transfer
* \param request device specific request
* \param value device specific field
diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp
index 6016b0979..c395db0b9 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -139,6 +139,7 @@ static device::sptr usrp1_make(const device_addr_t &device_addr){
usb_control::sptr ctrl_transport = usb_control::make(handle);
usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport);
usrp_ctrl->usrp_load_fpga(usrp1_fpga_image);
+ usrp_ctrl->usrp_init();
usb_zero_copy::sptr data_transport = usb_zero_copy::make(
handle, // identifier
6, // IN endpoint
@@ -192,9 +193,6 @@ usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport,
//initialize the send/recv
io_init();
- //turn on the transmitter
- _ctrl_transport->usrp_tx_enable(true);
-
//init the subdev specs
this->mboard_set(MBOARD_PROP_RX_SUBDEV_SPEC, subdev_spec_t());
this->mboard_set(MBOARD_PROP_TX_SUBDEV_SPEC, subdev_spec_t());
diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp
index ff4d40762..057725394 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.hpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -19,6 +19,7 @@
#include "usrp1_ctrl.hpp"
#include "clock_ctrl.hpp"
#include "codec_ctrl.hpp"
+#include "soft_time_ctrl.hpp"
#include <uhd/device.hpp>
#include <uhd/utils/pimpl.hpp>
#include <uhd/types/dict.hpp>
@@ -114,13 +115,17 @@ private:
const uhd::usrp::dboard_id_t &rx_dboard_id
);
+ //soft time control emulation
+ uhd::usrp::soft_time_ctrl::sptr _soft_time_ctrl;
+
//interface to ioctls and file descriptor
usrp1_iface::sptr _iface;
//handle io stuff
UHD_PIMPL_DECL(io_impl) _io_impl;
void io_init(void);
- void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd);
+ void rx_stream_on_off(bool);
+ void tx_stream_on_off(bool);
void handle_overrun(size_t);
//underrun and overrun poll intervals
diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt
index 527669852..e8811a8fb 100644
--- a/host/lib/usrp/usrp2/CMakeLists.txt
+++ b/host/lib/usrp/usrp2/CMakeLists.txt
@@ -34,12 +34,8 @@ IF(ENABLE_USRP2)
${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/gps_ctrl.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/gps_ctrl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/serdes_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/serdes_ctrl.hpp
${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.hpp
${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp
diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp
index 428d5539b..27ccefb2b 100644
--- a/host/lib/usrp/usrp2/clock_ctrl.cpp
+++ b/host/lib/usrp/usrp2/clock_ctrl.cpp
@@ -22,10 +22,13 @@
#include <uhd/utils/assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/math/special_functions/round.hpp>
#include <iostream>
using namespace uhd;
+static const bool enb_test_clk = false;
+
/*!
* A usrp2 clock control specific to the ad9510 ic.
*/
@@ -66,13 +69,12 @@ public:
this->enable_external_ref(false);
this->enable_rx_dboard_clock(false);
this->enable_tx_dboard_clock(false);
+ this->enable_mimo_clock_out(false);
/* private clock enables, must be set here */
this->enable_dac_clock(true);
this->enable_adc_clock(true);
-
- /* always driving the mimo reference */
- this->enable_mimo_clock_out(true);
+ this->enable_test_clock(enb_test_clk);
}
~usrp2_clock_ctrl_impl(void){
@@ -83,6 +85,7 @@ public:
this->enable_dac_clock(false);
this->enable_adc_clock(false);
this->enable_mimo_clock_out(false);
+ this->enable_test_clock(false);
}
void enable_mimo_clock_out(bool enb){
@@ -246,6 +249,54 @@ public:
double get_master_clock_rate(void){
return 100e6;
}
+
+ void set_mimo_clock_delay(double delay) {
+ //delay_val is a 5-bit value (0-31) for fine control
+ //the equations below determine delay for a given ramp current, # of caps and fine delay register
+ //delay range:
+ //range_ns = 200*((caps+3)/i_ramp_ua)*1.3286
+ //offset (zero delay):
+ //offset_ns = 0.34 + (1600 - i_ramp_ua)*1e-4 + ((caps-1)/ramp)*6
+ //delay_ns = offset_ns + range_ns * delay / 31
+
+ int delay_val = boost::math::iround(delay/9.744e-9*31);
+
+ if(delay_val == 0) {
+ switch(clk_regs.exp) {
+ case 5:
+ _ad9510_regs.delay_control_out5 = 1;
+ break;
+ case 6:
+ _ad9510_regs.delay_control_out6 = 1;
+ break;
+ default:
+ break; //delay not supported on U2 rev 3
+ }
+ } else {
+ switch(clk_regs.exp) {
+ case 5:
+ _ad9510_regs.delay_control_out5 = 0;
+ _ad9510_regs.ramp_current_out5 = ad9510_regs_t::RAMP_CURRENT_OUT5_200UA;
+ _ad9510_regs.ramp_capacitor_out5 = ad9510_regs_t::RAMP_CAPACITOR_OUT5_4CAPS;
+ _ad9510_regs.delay_fine_adjust_out5 = delay_val;
+ this->write_reg(0x34);
+ this->write_reg(0x35);
+ this->write_reg(0x36);
+ break;
+ case 6:
+ _ad9510_regs.delay_control_out6 = 0;
+ _ad9510_regs.ramp_current_out6 = ad9510_regs_t::RAMP_CURRENT_OUT6_200UA;
+ _ad9510_regs.ramp_capacitor_out6 = ad9510_regs_t::RAMP_CAPACITOR_OUT6_4CAPS;
+ _ad9510_regs.delay_fine_adjust_out6 = delay_val;
+ this->write_reg(0x38);
+ this->write_reg(0x39);
+ this->write_reg(0x3A);
+ break;
+ default:
+ break;
+ }
+ }
+ }
private:
/*!
diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp
index db6c52c83..9ccbc959e 100644
--- a/host/lib/usrp/usrp2/clock_ctrl.hpp
+++ b/host/lib/usrp/usrp2/clock_ctrl.hpp
@@ -91,8 +91,18 @@ public:
virtual void enable_test_clock(bool enb) = 0;
/*!
- * TODO other clock control api here....
+ * Enable/disable the ref clock output over the serdes cable.
+ * \param enb true to enable
+ */
+ virtual void enable_mimo_clock_out(bool enb) = 0;
+
+ /*!
+ * Set the output delay of the mimo clock
+ * Used to synchronise daisy-chained USRPs over the MIMO cable
+ * Can also be used to adjust delay for uneven reference cable lengths
+ * \param delay the clock delay in seconds
*/
+ virtual void set_mimo_clock_delay(double delay) = 0;
};
diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp
index 3a34afe11..890969b5a 100644
--- a/host/lib/usrp/usrp2/codec_ctrl.cpp
+++ b/host/lib/usrp/usrp2/codec_ctrl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -124,7 +124,7 @@ public:
this->send_ad9777_reg(0x01); //set the register
}
- void set_rx_digital_gain(float gain) { //fine digital gain
+ void set_rx_digital_gain(double gain) { //fine digital gain
switch(_iface->get_rev()){
case usrp2_iface::USRP_N200:
case usrp2_iface::USRP_N210:
@@ -136,7 +136,7 @@ public:
}
}
- void set_rx_digital_fine_gain(float gain) { //gain correction
+ void set_rx_digital_fine_gain(double gain) { //gain correction
switch(_iface->get_rev()){
case usrp2_iface::USRP_N200:
case usrp2_iface::USRP_N210:
@@ -148,7 +148,7 @@ public:
}
}
- void set_rx_analog_gain(bool gain) { //turns on/off analog 3.5dB preamp
+ void set_rx_analog_gain(bool /*gain*/) { //turns on/off analog 3.5dB preamp
switch(_iface->get_rev()){
case usrp2_iface::USRP_N200:
case usrp2_iface::USRP_N210:
diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp
index c8d977a1f..ca300e2b1 100644
--- a/host/lib/usrp/usrp2/codec_ctrl.hpp
+++ b/host/lib/usrp/usrp2/codec_ctrl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -54,14 +54,14 @@ public:
* \param gain from 0-6dB
*/
- virtual void set_rx_digital_gain(float gain) = 0;
+ virtual void set_rx_digital_gain(double gain) = 0;
/*!
* Set the digital gain correction on the USRP2+ ADC (ADS62P44).
* \param gain from 0-0.5dB
*/
- virtual void set_rx_digital_fine_gain(float gain) = 0;
+ virtual void set_rx_digital_fine_gain(double gain) = 0;
};
diff --git a/host/lib/usrp/usrp2/codec_impl.cpp b/host/lib/usrp/usrp2/codec_impl.cpp
index 8299ce0a6..d7078d985 100644
--- a/host/lib/usrp/usrp2/codec_impl.cpp
+++ b/host/lib/usrp/usrp2/codec_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -28,10 +28,10 @@ using namespace uhd;
using namespace uhd::usrp;
using namespace boost::assign;
-//this only applies to USRP2P
+//this only applies to N2XX
static const uhd::dict<std::string, gain_range_t> codec_rx_gain_ranges = map_list_of
- ("digital", gain_range_t(0, float(6.0), float(0.5)))
- ("digital-fine", gain_range_t(0, float(0.5), float(0.05)));
+ ("digital", gain_range_t(0, 6.0, 0.5))
+ ("digital-fine", gain_range_t(0, 0.5, 0.05));
/***********************************************************************
@@ -111,7 +111,7 @@ void usrp2_mboard_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){
switch(key.as<codec_prop_t>()) {
case CODEC_PROP_GAIN_I:
case CODEC_PROP_GAIN_Q:
- this->rx_codec_set_gain(val.as<float>(), key.name);
+ this->rx_codec_set_gain(val.as<double>(), key.name);
return;
default: UHD_THROW_PROP_SET_ERROR();
@@ -122,7 +122,7 @@ void usrp2_mboard_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){
* Helper function to set RX codec gain
***********************************************************************/
-void usrp2_mboard_impl::rx_codec_set_gain(float gain, const std::string &name){
+void usrp2_mboard_impl::rx_codec_set_gain(double gain, const std::string &name){
assert_has(codec_rx_gain_ranges.keys(), name, "codec rx gain name");
_codec_rx_gains[name] = gain;
diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp
index 54c1c735c..c539b0058 100644
--- a/host/lib/usrp/usrp2/dboard_iface.cpp
+++ b/host/lib/usrp/usrp2/dboard_iface.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -44,8 +44,8 @@ public:
return props;
}
- void write_aux_dac(unit_t, aux_dac_t, float);
- float read_aux_adc(unit_t, aux_adc_t);
+ void write_aux_dac(unit_t, aux_dac_t, double);
+ double read_aux_adc(unit_t, aux_adc_t);
void _set_pin_ctrl(unit_t, boost::uint16_t);
void _set_atr_reg(unit_t, atr_reg_t, boost::uint16_t);
@@ -294,7 +294,7 @@ void usrp2_dboard_iface::_write_aux_dac(unit_t unit){
);
}
-void usrp2_dboard_iface::write_aux_dac(unit_t unit, aux_dac_t which, float value){
+void usrp2_dboard_iface::write_aux_dac(unit_t unit, aux_dac_t which, double value){
_dac_regs[unit].data = boost::math::iround(4095*value/3.3);
_dac_regs[unit].cmd = ad5623_regs_t::CMD_WR_UP_DAC_CHAN_N;
@@ -317,7 +317,7 @@ void usrp2_dboard_iface::write_aux_dac(unit_t unit, aux_dac_t which, float value
this->_write_aux_dac(unit);
}
-float usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){
+double usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){
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)
@@ -346,5 +346,5 @@ float usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){
)));
//convert to voltage and return
- return float(3.3*ad7922_regs.result/4095);
+ return 3.3*ad7922_regs.result/4095;
}
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index a9c39e650..a22f805e1 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -18,23 +18,20 @@
#ifndef INCLUDED_USRP2_FW_COMMON_H
#define INCLUDED_USRP2_FW_COMMON_H
+#include <stdint.h>
+
/*!
* Structs and constants for usrp2 communication.
* This header is shared by the firmware and host code.
* Therefore, this header may only contain valid C code.
*/
#ifdef __cplusplus
- #include <boost/cstdint.hpp>
- #define __stdint(type) boost::type
extern "C" {
-#else
- #include <stdint.h>
- #define __stdint(type) type
#endif
//fpga and firmware compatibility numbers
-#define USRP2_FPGA_COMPAT_NUM 3
-#define USRP2_FW_COMPAT_NUM 7
+#define USRP2_FPGA_COMPAT_NUM 4
+#define USRP2_FW_COMPAT_NUM 8
//used to differentiate control packets over data port
#define USRP2_INVALID_VRT_HEADER 0
@@ -42,7 +39,9 @@ extern "C" {
// udp ports for the usrp2 communication
// Dynamic and/or private ports: 49152-65535
#define USRP2_UDP_CTRL_PORT 49152
-#define USRP2_UDP_DATA_PORT 49153
+//#define USRP2_UDP_UPDATE_PORT 49154
+#define USRP2_UDP_DATA_PORT 49156
+#define USRP2_UDP_ERR0_PORT 49157
////////////////////////////////////////////////////////////////////////
// I2C addresses
@@ -104,40 +103,38 @@ typedef enum{
} usrp2_clk_edge_t;
typedef struct{
- __stdint(uint32_t) proto_ver;
- __stdint(uint32_t) id;
- __stdint(uint32_t) seq;
+ uint32_t proto_ver;
+ uint32_t id;
+ uint32_t seq;
union{
- __stdint(uint32_t) ip_addr;
+ uint32_t ip_addr;
struct {
- __stdint(uint32_t) dev;
- __stdint(uint32_t) data;
- __stdint(uint8_t) miso_edge;
- __stdint(uint8_t) mosi_edge;
- __stdint(uint8_t) num_bits;
- __stdint(uint8_t) readback;
+ uint32_t dev;
+ uint32_t data;
+ uint8_t miso_edge;
+ uint8_t mosi_edge;
+ uint8_t num_bits;
+ uint8_t readback;
} spi_args;
struct {
- __stdint(uint8_t) addr;
- __stdint(uint8_t) bytes;
- __stdint(uint8_t) data[20];
+ uint8_t addr;
+ uint8_t bytes;
+ uint8_t data[20];
} i2c_args;
struct {
- __stdint(uint32_t) addr;
- __stdint(uint32_t) data;
- __stdint(uint32_t) addrhi;
- __stdint(uint32_t) datahi;
- __stdint(uint8_t) num_bytes; //1, 2, 4, 8
+ uint32_t addr;
+ uint32_t data;
+ uint32_t _pad[2];
+ uint8_t num_bytes; //1, 2, 4
} poke_args;
struct {
- __stdint(uint8_t) dev;
- __stdint(uint8_t) bytes;
- __stdint(uint8_t) data[20];
+ uint8_t dev;
+ uint8_t bytes;
+ uint8_t data[20];
} uart_args;
} data;
} usrp2_ctrl_data_t;
-#undef __stdint
#ifdef __cplusplus
}
#endif
diff --git a/host/lib/usrp/usrp2/gps_ctrl.hpp b/host/lib/usrp/usrp2/gps_ctrl.hpp
deleted file mode 100644
index 5936a6fb6..000000000
--- a/host/lib/usrp/usrp2/gps_ctrl.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// 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_GPS_CTRL_HPP
-#define INCLUDED_GPS_CTRL_HPP
-
-#include "usrp2_iface.hpp"
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-using namespace boost::posix_time;
-
-class usrp2_gps_ctrl : boost::noncopyable{
-public:
- typedef boost::shared_ptr<usrp2_gps_ctrl> sptr;
-
- /*!
- * Make a GPS config for Jackson Labs or generic NMEA GPS devices
- */
- static sptr make(usrp2_iface::sptr iface);
-
- /*!
- * Get the current GPS time and date
- * \return current GPS time and date as boost::posix_time::ptime object
- */
- virtual ptime get_time(void) = 0;
-
- /*!
- * Tell you if there's a supported GPS connected or not
- * \return true if a supported GPS is connected
- */
- virtual bool gps_detected(void) = 0;
-
- //TODO: other fun things you can do with a GPS.
-
-};
-
-#endif /* INCLUDED_CLOCK_CTRL_HPP */
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index cbc0a0817..30eaecae2 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -20,12 +20,13 @@
#include "usrp2_regs.hpp"
#include <uhd/utils/byteswap.hpp>
#include <uhd/utils/thread_priority.hpp>
-#include <uhd/transport/convert_types.hpp>
-#include <uhd/transport/alignment_buffer.hpp>
+#include <uhd/transport/bounded_buffer.hpp>
#include <boost/format.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <iostream>
+#include <list>
using namespace uhd;
using namespace uhd::usrp;
@@ -108,16 +109,24 @@ private:
* - vrt packet handler states
**********************************************************************/
struct usrp2_impl::io_impl{
- typedef alignment_buffer<managed_recv_buffer::sptr, time_spec_t> alignment_buffer_type;
- io_impl(size_t num_recv_frames, size_t send_frame_size, size_t width):
+ io_impl(size_t send_frame_size, size_t width):
packet_handler_recv_state(width),
- recv_pirate_booty(alignment_buffer_type::make(num_recv_frames-3, width)),
async_msg_fifo(bounded_buffer<async_metadata_t>::make(100/*messages deep*/))
{
- for (size_t i = 0; i < width; i++) fc_mons.push_back(
- flow_control_monitor::sptr(new flow_control_monitor(usrp2_impl::sram_bytes/send_frame_size))
- );
+ for (size_t i = 0; i < width; i++){
+ fc_mons.push_back(flow_control_monitor::sptr(
+ new flow_control_monitor(usrp2_impl::sram_bytes/send_frame_size)
+ ));
+ //init empty packet infos
+ vrt::if_packet_info_t packet_info;
+ packet_info.packet_count = 0xf;
+ packet_info.has_tsi = true;
+ packet_info.tsi = 0;
+ packet_info.has_tsf = true;
+ packet_info.tsf = 0;
+ prev_infos.push_back(packet_info);
+ }
}
~io_impl(void){
@@ -126,11 +135,6 @@ struct usrp2_impl::io_impl{
recv_pirate_crew.join_all();
}
- bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, double timeout){
- boost::this_thread::disable_interruption di; //disable because the wait can throw
- return recv_pirate_booty->pop_elems_with_timed_wait(buffs, timeout);
- }
-
bool get_send_buffs(
const std::vector<zero_copy_if::sptr> &trans,
vrt_packet_handler::managed_send_buffs_t &buffs,
@@ -151,6 +155,15 @@ struct usrp2_impl::io_impl{
return true;
}
+ bool get_recv_buffs(
+ const std::vector<zero_copy_if::sptr> &xports,
+ vrt_packet_handler::managed_recv_buffs_t &buffs,
+ double timeout
+ );
+
+ //previous state for each buffer
+ std::vector<vrt::if_packet_info_t> prev_infos;
+
//flow control monitors
std::vector<flow_control_monitor::sptr> fc_mons;
@@ -162,29 +175,28 @@ struct usrp2_impl::io_impl{
void recv_pirate_loop(zero_copy_if::sptr, usrp2_mboard_impl::sptr, size_t);
boost::thread_group recv_pirate_crew;
bool recv_pirate_crew_raiding;
- alignment_buffer_type::sptr recv_pirate_booty;
bounded_buffer<async_metadata_t>::sptr async_msg_fifo;
boost::mutex spawn_mutex;
};
/***********************************************************************
* Receive Pirate Loop
- * - while raiding, loot for recv buffers
- * - put booty into the alignment buffer
+ * - while raiding, loot for message packet
+ * - update flow control condition count
+ * - put async message packets into queue
**********************************************************************/
void usrp2_impl::io_impl::recv_pirate_loop(
- zero_copy_if::sptr zc_if,
+ zero_copy_if::sptr zc_if_err0,
usrp2_mboard_impl::sptr mboard,
size_t index
){
set_thread_priority_safe();
recv_pirate_crew_raiding = true;
- size_t next_packet_seq = 0;
spawn_mutex.unlock();
while(recv_pirate_crew_raiding){
- managed_recv_buffer::sptr buff = zc_if->get_recv_buff();
+ managed_recv_buffer::sptr buff = zc_if_err0->get_recv_buff();
if (not buff.get()) continue; //ignore timeout/error buffers
try{
@@ -194,26 +206,6 @@ void usrp2_impl::io_impl::recv_pirate_loop(
const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>();
vrt::if_hdr_unpack_be(vrt_hdr, if_packet_info);
- //handle the rx data stream
- if (if_packet_info.sid == usrp2_impl::RECV_SID){
- //handle the packet count / sequence number
- if (if_packet_info.packet_count != next_packet_seq){
- //std::cerr << "S" << (if_packet_info.packet_count - next_packet_seq)%16;
- std::cerr << "O" << std::flush; //report overflow (drops in the kernel)
- }
- next_packet_seq = (if_packet_info.packet_count+1)%16;
-
- //extract the timespec and round to the nearest packet
- UHD_ASSERT_THROW(if_packet_info.has_tsi and if_packet_info.has_tsf);
- time_spec_t time(
- time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), mboard->get_master_clock_freq()
- );
-
- //push the packet into the buffer with the new time
- recv_pirate_booty->push_with_pop_on_full(buff, time, index);
- continue;
- }
-
//handle a tx async report message
if (if_packet_info.sid == usrp2_impl::ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
@@ -253,21 +245,10 @@ void usrp2_impl::io_impl::recv_pirate_loop(
void usrp2_impl::io_init(void){
//the assumption is that all data transports should be identical
- const size_t num_recv_frames = _data_transports.front()->get_num_recv_frames();
const size_t send_frame_size = _data_transports.front()->get_send_frame_size();
//create new io impl
- _io_impl = UHD_PIMPL_MAKE(io_impl, (num_recv_frames, send_frame_size, _data_transports.size()));
-
- //TODO temporary fix for weird power up state, remove when FPGA fixed
- {
- //send an initial packet to all transports
- tx_metadata_t md; md.end_of_burst = true;
- this->send(
- std::vector<const void *>(_data_transports.size(), NULL), 0, md,
- io_type_t::COMPLEX_FLOAT32, device::SEND_MODE_ONE_PACKET, 0
- );
- }
+ _io_impl = UHD_PIMPL_MAKE(io_impl, (send_frame_size, _data_transports.size()));
//create a new pirate thread for each zc if (yarr!!)
for (size_t i = 0; i < _data_transports.size(); i++){
@@ -276,7 +257,7 @@ void usrp2_impl::io_init(void){
//spawn a new pirate to plunder the recv booty
_io_impl->recv_pirate_crew.create_thread(boost::bind(
&usrp2_impl::io_impl::recv_pirate_loop,
- _io_impl.get(), _data_transports.at(i),
+ _io_impl.get(), _err0_transports.at(i),
_mboards.at(i), i
));
//block here until the spawned thread unlocks
@@ -328,6 +309,133 @@ size_t usrp2_impl::send(
}
/***********************************************************************
+ * Alignment logic on receive
+ **********************************************************************/
+static UHD_INLINE boost::posix_time::time_duration to_time_dur(double timeout){
+ return boost::posix_time::microseconds(long(timeout*1e6));
+}
+
+static UHD_INLINE double from_time_dur(const boost::posix_time::time_duration &time_dur){
+ return 1e-6*time_dur.total_microseconds();
+}
+
+static UHD_INLINE time_spec_t extract_time_spec(
+ const vrt::if_packet_info_t &packet_info
+){
+ return time_spec_t( //assumes has_tsi and has_tsf are true
+ time_t(packet_info.tsi), size_t(packet_info.tsf),
+ 100e6 //tick rate does not have to be correct for comparison purposes
+ );
+}
+
+static UHD_INLINE void extract_packet_info(
+ managed_recv_buffer::sptr &buff,
+ vrt::if_packet_info_t &prev_info,
+ time_spec_t &time, bool &clear, bool &msg
+){
+ //extract packet info
+ vrt::if_packet_info_t next_info;
+ next_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t);
+ vrt::if_hdr_unpack_be(buff->cast<const boost::uint32_t *>(), next_info);
+
+ //handle the packet count / sequence number
+ if ((prev_info.packet_count+1)%16 != next_info.packet_count){
+ std::cerr << "O" << std::flush; //report overflow (drops in the kernel)
+ }
+
+ time = extract_time_spec(next_info);
+ clear = extract_time_spec(prev_info) > time;
+ msg = next_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA;
+ prev_info = next_info;
+}
+
+static UHD_INLINE bool handle_msg_packet(
+ vrt_packet_handler::managed_recv_buffs_t &buffs, size_t index
+){
+ for (size_t i = 0; i < buffs.size(); i++){
+ if (i == index) continue;
+ buffs[i].reset(); //set NULL
+ }
+ return true;
+}
+
+UHD_INLINE bool usrp2_impl::io_impl::get_recv_buffs(
+ const std::vector<zero_copy_if::sptr> &xports,
+ vrt_packet_handler::managed_recv_buffs_t &buffs,
+ double timeout
+){
+ if (buffs.size() == 1){
+ buffs[0] = xports[0]->get_recv_buff(timeout);
+ if (buffs[0].get() == NULL) return false;
+ bool clear, msg; time_spec_t time; //unused variables
+ //call extract_packet_info to handle printing the overflows
+ extract_packet_info(buffs[0], this->prev_infos[0], time, clear, msg);
+ return true;
+ }
+ //-------------------- begin alignment logic ---------------------//
+ boost::system_time exit_time = boost::get_system_time() + to_time_dur(timeout);
+ managed_recv_buffer::sptr buff_tmp;
+ std::list<size_t> _all_indexes, indexes_to_do;
+ for (size_t i = 0; i < buffs.size(); i++) _all_indexes.push_back(i);
+ bool clear, msg;
+ time_spec_t expected_time;
+
+ //respond to a clear by starting from scratch
+ got_clear:
+ indexes_to_do = _all_indexes;
+ clear = false;
+
+ //do an initial pop to load an initial sequence id
+ size_t index = indexes_to_do.front();
+ buff_tmp = xports[index]->get_recv_buff(from_time_dur(exit_time - boost::get_system_time()));
+ if (buff_tmp.get() == NULL) return false;
+ extract_packet_info(buff_tmp, this->prev_infos[index], expected_time, clear, msg);
+ if (clear) goto got_clear;
+ buffs[index] = buff_tmp;
+ if (msg) return handle_msg_packet(buffs, index);
+ indexes_to_do.pop_front();
+
+ //get an aligned set of elements from the buffers:
+ while(indexes_to_do.size() != 0){
+
+ //pop an element off for this index
+ index = indexes_to_do.front();
+ buff_tmp = xports[index]->get_recv_buff(from_time_dur(exit_time - boost::get_system_time()));
+ if (buff_tmp.get() == NULL) return false;
+ time_spec_t this_time;
+ extract_packet_info(buff_tmp, this->prev_infos[index], this_time, clear, msg);
+ if (clear) goto got_clear;
+ buffs[index] = buff_tmp;
+ if (msg) return handle_msg_packet(buffs, index);
+
+ //if the sequence id matches:
+ // remove this index from the list and continue
+ if (this_time == expected_time){
+ indexes_to_do.pop_front();
+ continue;
+ }
+
+ //if the sequence id is older:
+ // continue with the same index to try again
+ else if (this_time < expected_time){
+ continue;
+ }
+
+ //if the sequence id is newer:
+ // use the new expected time for comparison
+ // add all other indexes back into the list
+ else{
+ expected_time = this_time;
+ indexes_to_do = _all_indexes;
+ indexes_to_do.remove(index);
+ continue;
+ }
+ }
+ return true;
+ //-------------------- end alignment logic -----------------------//
+}
+
+/***********************************************************************
* Receive Data
**********************************************************************/
size_t usrp2_impl::get_max_recv_samps_per_packet(void) const{
@@ -357,7 +465,7 @@ size_t usrp2_impl::recv(
io_type, _rx_otw_type, //input and output types to convert
_mboards.front()->get_master_clock_freq(), //master clock tick rate
uhd::transport::vrt::if_hdr_unpack_be,
- boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout),
+ boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _data_transports, _1, timeout),
boost::bind(&handle_overflow, _mboards, _1)
);
}
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 766ea993c..95f7013e7 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -17,6 +17,7 @@
#include "usrp2_impl.hpp"
#include "usrp2_regs.hpp"
+#include <uhd/usrp/gps_ctrl.hpp>
#include <uhd/usrp/misc_utils.hpp>
#include <uhd/usrp/dsp_utils.hpp>
#include <uhd/usrp/mboard_props.hpp>
@@ -25,11 +26,13 @@
#include <uhd/utils/algorithm.hpp>
#include <boost/bind.hpp>
#include <iostream>
-#include <boost/date_time/posix_time/posix_time.hpp>
+
+static const double mimo_clock_delay_usrp2_rev4 = 4.18e-9;
+static const double mimo_clock_delay_usrp_n2xx = 3.55e-9;
+static const size_t mimo_clock_sync_delay_cycles = 137;
using namespace uhd;
using namespace uhd::usrp;
-using namespace boost::posix_time;
/***********************************************************************
* Structors
@@ -38,8 +41,9 @@ usrp2_mboard_impl::usrp2_mboard_impl(
size_t index,
transport::udp_simple::sptr ctrl_transport,
transport::zero_copy_if::sptr data_transport,
- size_t recv_samps_per_packet,
- const device_addr_t &flow_control_hints
+ transport::zero_copy_if::sptr err0_transport,
+ const device_addr_t &device_args,
+ size_t recv_samps_per_packet
):
_index(index),
_iface(usrp2_iface::make(ctrl_transport))
@@ -47,19 +51,24 @@ usrp2_mboard_impl::usrp2_mboard_impl(
//Send a small data packet so the usrp2 knows the udp source port.
//This setup must happen before further initialization occurs
//or the async update packets will cause ICMP destination unreachable.
- transport::managed_send_buffer::sptr send_buff = data_transport->get_send_buff();
+ transport::managed_send_buffer::sptr send_buff;
static const boost::uint32_t data[2] = {
uhd::htonx(boost::uint32_t(0 /* don't care seq num */)),
uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER))
};
+ send_buff = data_transport->get_send_buff();
+ std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));
+ send_buff->commit(sizeof(data));
+ send_buff = err0_transport->get_send_buff();
std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));
send_buff->commit(sizeof(data));
//contruct the interfaces to mboard perifs
_clock_ctrl = usrp2_clock_ctrl::make(_iface);
_codec_ctrl = usrp2_codec_ctrl::make(_iface);
- _serdes_ctrl = usrp2_serdes_ctrl::make(_iface);
- //_gps_ctrl = usrp2_gps_ctrl::make(_iface);
+ //_gps_ctrl = gps_ctrl::make(
+ // _iface->get_gps_write_fn(),
+ // _iface->get_gps_read_fn());
//if(_gps_ctrl->gps_detected()) std::cout << "GPS time: " << _gps_ctrl->get_time() << std::endl;
@@ -98,14 +107,14 @@ usrp2_mboard_impl::usrp2_mboard_impl(
_iface->poke32(_iface->regs.tx_ctrl_policy, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET);
//setting the cycles per update (disabled by default)
- const double ups_per_sec = flow_control_hints.cast<double>("ups_per_sec", 0.0);
+ const double ups_per_sec = device_args.cast<double>("ups_per_sec", 0.0);
if (ups_per_sec > 0.0){
const size_t cycles_per_up = size_t(_clock_ctrl->get_master_clock_rate()/ups_per_sec);
_iface->poke32(_iface->regs.tx_ctrl_cycles_per_up, U2_FLAG_TX_CTRL_UP_ENB | cycles_per_up);
}
//setting the packets per update (enabled by default)
- const double ups_per_fifo = flow_control_hints.cast<double>("ups_per_fifo", 8.0);
+ const double ups_per_fifo = device_args.cast<double>("ups_per_fifo", 8.0);
if (ups_per_fifo > 0.0){
const size_t packets_per_up = size_t(usrp2_impl::sram_bytes/ups_per_fifo/data_transport->get_send_frame_size());
_iface->poke32(_iface->regs.tx_ctrl_packets_per_up, U2_FLAG_TX_CTRL_UP_ENB | packets_per_up);
@@ -118,7 +127,26 @@ usrp2_mboard_impl::usrp2_mboard_impl(
init_duc_config();
//initialize the clock configuration
- init_clock_config();
+ if (device_args.has_key("mimo_mode")){
+ if (device_args["mimo_mode"] == "master"){
+ _mimo_clocking_mode_is_master = true;
+ }
+ else if (device_args["mimo_mode"] == "slave"){
+ _mimo_clocking_mode_is_master = false;
+ }
+ else throw std::runtime_error(
+ "mimo_mode must be set to master or slave"
+ );
+ }
+ else {
+ _mimo_clocking_mode_is_master = (_iface->peek32(_iface->regs.status) & (1 << 8)) != 0;
+ }
+ std::cout << boost::format("mboard%d MIMO %s") % _index %
+ (_mimo_clocking_mode_is_master?"master":"slave") << std::endl;
+
+ //init the clock config
+ _clock_config = clock_config_t::internal();
+ update_clock_config();
//init the codec before the dboard
codec_init();
@@ -139,23 +167,12 @@ usrp2_mboard_impl::~usrp2_mboard_impl(void){
/***********************************************************************
* Helper Methods
**********************************************************************/
-void usrp2_mboard_impl::init_clock_config(void){
- //setup the clock configuration settings
- _clock_config.ref_source = clock_config_t::REF_INT;
- _clock_config.pps_source = clock_config_t::PPS_SMA;
- _clock_config.pps_polarity = clock_config_t::PPS_NEG;
-
- //update the clock config (sends a control packet)
- update_clock_config();
-}
-
void usrp2_mboard_impl::update_clock_config(void){
boost::uint32_t pps_flags = 0;
//translate pps source enums
switch(_clock_config.pps_source){
case clock_config_t::PPS_SMA: pps_flags |= U2_FLAG_TIME64_PPS_SMA; break;
- case clock_config_t::PPS_MIMO: pps_flags |= U2_FLAG_TIME64_PPS_MIMO; break;
default: throw std::runtime_error("unhandled clock configuration pps source");
}
@@ -176,7 +193,6 @@ void usrp2_mboard_impl::update_clock_config(void){
switch(_clock_config.ref_source){
case clock_config_t::REF_INT : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x12); break;
case clock_config_t::REF_SMA : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x1C); break;
- case clock_config_t::REF_MIMO: _iface->poke32(_iface->regs.misc_ctrl_clock, 0x15); break;
default: throw std::runtime_error("unhandled clock configuration reference source");
}
_clock_ctrl->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO
@@ -187,7 +203,6 @@ void usrp2_mboard_impl::update_clock_config(void){
switch(_clock_config.ref_source){
case clock_config_t::REF_INT : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x10); break;
case clock_config_t::REF_SMA : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x1C); break;
- case clock_config_t::REF_MIMO: _iface->poke32(_iface->regs.misc_ctrl_clock, 0x15); break;
default: throw std::runtime_error("unhandled clock configuration reference source");
}
_clock_ctrl->enable_external_ref(_clock_config.ref_source != clock_config_t::REF_INT);
@@ -195,6 +210,36 @@ void usrp2_mboard_impl::update_clock_config(void){
case usrp2_iface::USRP_NXXX: break;
}
+
+ //Handle the serdes clocking based on master/slave mode:
+ // - Masters always drive the clock over serdes.
+ // - Slaves always lock to this serdes clock.
+ // - Slaves lock their time over the serdes.
+ if (_mimo_clocking_mode_is_master){
+ _clock_ctrl->enable_mimo_clock_out(true);
+ switch(_iface->get_rev()){
+ case usrp2_iface::USRP_N200:
+ case usrp2_iface::USRP_N210:
+ _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp_n2xx);
+ break;
+
+ case usrp2_iface::USRP2_REV4:
+ _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp2_rev4);
+ break;
+
+ default: break; //not handled
+ }
+ _iface->poke32(_iface->regs.time64_mimo_sync, 0);
+ }
+ else{
+ _iface->poke32(_iface->regs.misc_ctrl_clock, 0x15);
+ _clock_ctrl->enable_external_ref(true);
+ _clock_ctrl->enable_mimo_clock_out(false);
+ _iface->poke32(_iface->regs.time64_mimo_sync,
+ (1 << 8) | (mimo_clock_sync_delay_cycles & 0xff)
+ );
+ }
+
}
void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){
@@ -279,15 +324,21 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){
val = _clock_config;
return;
- case MBOARD_PROP_TIME_NOW:{
- usrp2_iface::pair64 time64(
- _iface->peek64(_iface->regs.time64_secs_rb, _iface->regs.time64_ticks_rb)
- );
- val = time_spec_t(
- time64.first, time64.second, get_master_clock_freq()
- );
- }
+ case MBOARD_PROP_TIME_NOW: while(true){
+ uint32_t secs = _iface->peek32(_iface->regs.time64_secs_rb_imm);
+ uint32_t ticks = _iface->peek32(_iface->regs.time64_ticks_rb_imm);
+ if (secs != _iface->peek32(_iface->regs.time64_secs_rb_imm)) continue;
+ val = time_spec_t(secs, ticks, get_master_clock_freq());
return;
+ }
+
+ case MBOARD_PROP_TIME_PPS: while(true){
+ uint32_t secs = _iface->peek32(_iface->regs.time64_secs_rb_pps);
+ uint32_t ticks = _iface->peek32(_iface->regs.time64_ticks_rb_pps);
+ if (secs != _iface->peek32(_iface->regs.time64_secs_rb_pps)) continue;
+ val = time_spec_t(secs, ticks, get_master_clock_freq());
+ return;
+ }
case MBOARD_PROP_RX_SUBDEV_SPEC:
val = _rx_subdev_spec;
@@ -321,7 +372,7 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){
set_time_spec(val.as<time_spec_t>(), true);
return;
- case MBOARD_PROP_TIME_NEXT_PPS:
+ case MBOARD_PROP_TIME_PPS:
set_time_spec(val.as<time_spec_t>(), false);
return;
diff --git a/host/lib/usrp/usrp2/serdes_ctrl.cpp b/host/lib/usrp/usrp2/serdes_ctrl.cpp
deleted file mode 100644
index 1cda22f45..000000000
--- a/host/lib/usrp/usrp2/serdes_ctrl.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// 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 "serdes_ctrl.hpp"
-#include "usrp2_regs.hpp"
-
-using namespace uhd;
-
-/*!
- * A usrp2 serdes control implementation
- */
-class usrp2_serdes_ctrl_impl : public usrp2_serdes_ctrl{
-public:
- usrp2_serdes_ctrl_impl(usrp2_iface::sptr iface){
- _iface = iface;
- _iface->poke32(_iface->regs.misc_ctrl_serdes, U2_FLAG_MISC_CTRL_SERDES_ENABLE | U2_FLAG_MISC_CTRL_SERDES_RXEN);
- }
-
- ~usrp2_serdes_ctrl_impl(void){
- _iface->poke32(_iface->regs.misc_ctrl_serdes, 0); //power-down
- }
-
-private:
- usrp2_iface::sptr _iface;
-};
-
-/***********************************************************************
- * Public make function for the usrp2 serdes control
- **********************************************************************/
-usrp2_serdes_ctrl::sptr usrp2_serdes_ctrl::make(usrp2_iface::sptr iface){
- return sptr(new usrp2_serdes_ctrl_impl(iface));
-}
diff --git a/host/lib/usrp/usrp2/serdes_ctrl.hpp b/host/lib/usrp/usrp2/serdes_ctrl.hpp
deleted file mode 100644
index 3c909c531..000000000
--- a/host/lib/usrp/usrp2/serdes_ctrl.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// 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_SERDES_CTRL_HPP
-#define INCLUDED_SERDES_CTRL_HPP
-
-#include "usrp2_iface.hpp"
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-
-class usrp2_serdes_ctrl : boost::noncopyable{
-public:
- typedef boost::shared_ptr<usrp2_serdes_ctrl> sptr;
-
- /*!
- * Make a serdes control object for the usrp2 serdes port.
- * \param _iface a pointer to the usrp2 interface object
- * \return a new serdes control object
- */
- static sptr make(usrp2_iface::sptr iface);
-
- //TODO fill me in with virtual methods
-
-};
-
-#endif /* INCLUDED_SERDES_CTRL_HPP */
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index ffbe8eedb..149c5011f 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -93,20 +93,6 @@ public:
return this->peek<boost::uint16_t>(addr);
}
- pair64 peek64(boost::uint32_t addrlo, boost::uint32_t addrhi){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO);
- out_data.data.poke_args.addr = htonl(addrlo);
- out_data.data.poke_args.addrhi = htonl(addrhi);
- out_data.data.poke_args.num_bytes = sizeof(boost::uint64_t);
-
- //send and recv
- usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
- UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE);
- return pair64(ntohl(in_data.data.poke_args.data), ntohl(in_data.data.poke_args.datahi));
- }
-
/***********************************************************************
* SPI
**********************************************************************/
@@ -232,6 +218,14 @@ public:
}
return result;
}
+
+ gps_send_fn_t get_gps_write_fn(void) {
+ return boost::bind(&usrp2_iface_impl::write_uart, this, 2, _1); //2 is the GPS UART port on USRP2
+ }
+
+ gps_recv_fn_t get_gps_read_fn(void) {
+ return boost::bind(&usrp2_iface_impl::read_uart, this, 2); //2 is the GPS UART port on USRP2
+ }
/***********************************************************************
* Send/Recv over control
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
index af3ed6c9f..49cb0e6dc 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.hpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.hpp
@@ -24,11 +24,17 @@
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <boost/cstdint.hpp>
+#include <boost/function.hpp>
#include <utility>
#include <string>
#include "fw_common.h"
#include "usrp2_regs.hpp"
+
+//TODO: kill this crap when you have the top level GPS include file
+typedef boost::function<void(std::string)> gps_send_fn_t;
+typedef boost::function<std::string(void)> gps_recv_fn_t;
+
/*!
* The usrp2 interface class:
* Provides a set of functions to implementation layer.
@@ -37,7 +43,6 @@
class usrp2_iface : public uhd::i2c_iface, boost::noncopyable{
public:
typedef boost::shared_ptr<usrp2_iface> sptr;
- typedef std::pair<boost::uint32_t, boost::uint32_t> pair64;
/*!
* Make a new usrp2 interface with the control transport.
@@ -54,14 +59,6 @@ public:
virtual usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &data) = 0;
/*!
- * Read a dual register (64 bits)
- * \param addrlo the address for the low-32 bits
- * \param addrhi the address for the high-32 bits
- * \return a pair of 32 bit integers lo, hi
- */
- virtual pair64 peek64(boost::uint32_t addrlo, boost::uint32_t addrhi) = 0;
-
- /*!
* Write a register (32 bits)
* \param addr the address
* \param data the 32bit data
@@ -109,6 +106,9 @@ public:
virtual void write_uart(boost::uint8_t dev, const std::string &buf) = 0;
virtual std::string read_uart(boost::uint8_t dev) = 0;
+
+ virtual gps_recv_fn_t get_gps_read_fn(void) = 0;
+ virtual gps_send_fn_t get_gps_write_fn(void) = 0;
//! The list of possible revision types
enum rev_type {
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index c3bbe4d65..059ddf65f 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -22,7 +22,7 @@
#include <uhd/utils/assert.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/warning.hpp>
-#include <uhd/utils/algorithm.hpp>
+#include <boost/algorithm/string.hpp> //for split
#include <boost/assign/list_of.hpp>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
@@ -31,6 +31,7 @@
#include <boost/bind.hpp>
#include <boost/asio.hpp> //htonl and ntohl
#include <iostream>
+#include <vector>
using namespace uhd;
using namespace uhd::usrp;
@@ -47,8 +48,8 @@ template <class T> std::string num2str(T num){
//! separate indexed device addresses into a vector of device addresses
device_addrs_t sep_indexed_dev_addrs(const device_addr_t &dev_addr){
//------------ support old deprecated way and print warning --------
- if (dev_addr.has_key("addr")){
- std::vector<std::string> addrs = std::split_string(dev_addr["addr"]);
+ if (dev_addr.has_key("addr") and not dev_addr["addr"].empty()){
+ std::vector<std::string> addrs; boost::split(addrs, dev_addr["addr"], boost::is_any_of(" "));
if (addrs.size() > 1){
device_addr_t fixed_dev_addr = dev_addr;
fixed_dev_addr.pop("addr");
@@ -197,24 +198,36 @@ static device_addrs_t usrp2_find(const device_addr_t &hint_){
* Make
**********************************************************************/
static device::sptr usrp2_make(const device_addr_t &device_addr){
-sep_indexed_dev_addrs(device_addr);
+
+ //setup the dsp transport hints (default to a large recv buff)
+ device_addr_t dsp_xport_hints = device_addr;
+ if (not dsp_xport_hints.has_key("recv_buff_size")){
+ //set to half-a-second of buffering at max rate
+ dsp_xport_hints["recv_buff_size"] = "50e6";
+ }
+
//create a ctrl and data transport for each address
std::vector<udp_simple::sptr> ctrl_transports;
std::vector<zero_copy_if::sptr> data_transports;
+ std::vector<zero_copy_if::sptr> err0_transports;
+ const device_addrs_t device_addrs = sep_indexed_dev_addrs(device_addr);
- BOOST_FOREACH(const device_addr_t &dev_addr_i, sep_indexed_dev_addrs(device_addr)){
+ BOOST_FOREACH(const device_addr_t &dev_addr_i, device_addrs){
ctrl_transports.push_back(udp_simple::make_connected(
dev_addr_i["addr"], num2str(USRP2_UDP_CTRL_PORT)
));
data_transports.push_back(udp_zero_copy::make(
- dev_addr_i["addr"], num2str(USRP2_UDP_DATA_PORT), device_addr
+ dev_addr_i["addr"], num2str(USRP2_UDP_DATA_PORT), dsp_xport_hints
+ ));
+ err0_transports.push_back(udp_zero_copy::make(
+ dev_addr_i["addr"], num2str(USRP2_UDP_ERR0_PORT), device_addr_t()
));
}
//create the usrp2 implementation guts
- return device::sptr(
- new usrp2_impl(ctrl_transports, data_transports, device_addr)
- );
+ return device::sptr(new usrp2_impl(
+ ctrl_transports, data_transports, err0_transports, device_addrs
+ ));
}
UHD_STATIC_BLOCK(register_usrp2_device){
@@ -227,9 +240,11 @@ UHD_STATIC_BLOCK(register_usrp2_device){
usrp2_impl::usrp2_impl(
std::vector<udp_simple::sptr> ctrl_transports,
std::vector<zero_copy_if::sptr> data_transports,
- const device_addr_t &flow_control_hints
+ std::vector<zero_copy_if::sptr> err0_transports,
+ const device_addrs_t &device_args
):
- _data_transports(data_transports)
+ _data_transports(data_transports),
+ _err0_transports(err0_transports)
{
//setup rx otw type
_rx_otw_type.width = 16;
@@ -244,11 +259,11 @@ usrp2_impl::usrp2_impl(
//!!!!! set the otw type here before continuing, its used below
//create a new mboard handler for each control transport
- for(size_t i = 0; i < ctrl_transports.size(); i++){
+ for(size_t i = 0; i < device_args.size(); i++){
_mboards.push_back(usrp2_mboard_impl::sptr(new usrp2_mboard_impl(
i, ctrl_transports[i], data_transports[i],
- this->get_max_recv_samps_per_packet(),
- flow_control_hints
+ err0_transports[i], device_args[i],
+ this->get_max_recv_samps_per_packet()
)));
//use an empty name when there is only one mboard
std::string name = (ctrl_transports.size() > 1)? boost::lexical_cast<std::string>(i) : "";
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index aa8eb0155..ad95b2a4a 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -21,8 +21,7 @@
#include "usrp2_iface.hpp"
#include "clock_ctrl.hpp"
#include "codec_ctrl.hpp"
-#include "gps_ctrl.hpp"
-#include "serdes_ctrl.hpp"
+#include <uhd/usrp/gps_ctrl.hpp>
#include <uhd/device.hpp>
#include <uhd/utils/pimpl.hpp>
#include <uhd/types/dict.hpp>
@@ -86,8 +85,9 @@ public:
size_t index,
uhd::transport::udp_simple::sptr,
uhd::transport::zero_copy_if::sptr,
- size_t recv_samps_per_packet,
- const uhd::device_addr_t &flow_control_hints
+ uhd::transport::zero_copy_if::sptr,
+ const uhd::device_addr_t &device_args,
+ size_t recv_samps_per_packet
);
~usrp2_mboard_impl(void);
@@ -100,13 +100,13 @@ public:
private:
size_t _index;
bool _continuous_streaming;
+ bool _mimo_clocking_mode_is_master;
//interfaces
usrp2_iface::sptr _iface;
usrp2_clock_ctrl::sptr _clock_ctrl;
usrp2_codec_ctrl::sptr _codec_ctrl;
- usrp2_serdes_ctrl::sptr _serdes_ctrl;
- usrp2_gps_ctrl::sptr _gps_ctrl;
+ gps_ctrl::sptr _gps_ctrl;
//properties for this mboard
void get(const wax::obj &, wax::obj &);
@@ -120,7 +120,6 @@ private:
//methods and shadows for clock configuration
uhd::clock_config_t _clock_config;
- void init_clock_config(void);
void update_clock_config(void);
void set_time_spec(const uhd::time_spec_t &time_spec, bool now);
@@ -133,8 +132,8 @@ private:
wax_obj_proxy::sptr _rx_codec_proxy;
wax_obj_proxy::sptr _tx_codec_proxy;
- void rx_codec_set_gain(float, const std::string &);
- uhd::dict<std::string, float> _codec_rx_gains;
+ void rx_codec_set_gain(double, const std::string &);
+ uhd::dict<std::string, double> _codec_rx_gains;
//properties interface for rx dboard
void rx_dboard_get(const wax::obj &, wax::obj &);
@@ -187,12 +186,14 @@ public:
* Create a new usrp2 impl base.
* \param ctrl_transports the udp transports for control
* \param data_transports the udp transports for data
- * \param flow_control_hints optional flow control params
+ * \param err0_transports the udp transports for error
+ * \param device_args optional misc device parameters
*/
usrp2_impl(
std::vector<uhd::transport::udp_simple::sptr> ctrl_transports,
std::vector<uhd::transport::zero_copy_if::sptr> data_transports,
- const uhd::device_addr_t &flow_control_hints
+ std::vector<uhd::transport::zero_copy_if::sptr> err0_transports,
+ const uhd::device_addrs_t &device_args
);
~usrp2_impl(void);
@@ -223,6 +224,7 @@ private:
//io impl methods and members
std::vector<uhd::transport::zero_copy_if::sptr> _data_transports;
+ std::vector<uhd::transport::zero_copy_if::sptr> _err0_transports;
uhd::otw_type_t _rx_otw_type, _tx_otw_type;
UHD_PIMPL_DECL(io_impl) _io_impl;
void io_init(void);
diff --git a/host/lib/usrp/usrp2/usrp2_regs.cpp b/host/lib/usrp/usrp2/usrp2_regs.cpp
index dd0433816..84907c32e 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.cpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -57,9 +57,13 @@ usrp2_regs_t usrp2_get_regs(bool use_n2xx_map) {
x.time64_flags = sr_addr(misc_output_base, x.sr_time64 + 2);
x.time64_imm = sr_addr(misc_output_base, x.sr_time64 + 3);
x.time64_tps = sr_addr(misc_output_base, x.sr_time64 + 4);
- x.time64_secs_rb = bp_base + 4*10;
- x.time64_ticks_rb = bp_base + 4*11;
+ x.time64_mimo_sync = sr_addr(misc_output_base, x.sr_time64 + 5);
+ x.status = bp_base + 4*8;
+ x.time64_secs_rb_imm = bp_base + 4*10;
+ x.time64_ticks_rb_imm = bp_base + 4*11;
x.compat_num_rb = bp_base + 4*12;
+ x.time64_secs_rb_pps = bp_base + 4*14;
+ x.time64_ticks_rb_pps = bp_base + 4*15;
x.dsp_tx_freq = sr_addr(misc_output_base, x.sr_tx_dsp + 0);
x.dsp_tx_scale_iq = sr_addr(misc_output_base, x.sr_tx_dsp + 1);
x.dsp_tx_interp_rate = sr_addr(misc_output_base, x.sr_tx_dsp + 2);
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index 9936d634a..977b342cb 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -25,10 +25,10 @@
#define USRP2_ATR_BASE 0xE400
#define USRP2_BP_STATUS_BASE 0xCC00
-#define USRP2P_MISC_OUTPUT_BASE 0x2000
-#define USRP2P_GPIO_BASE 0x3200
-#define USRP2P_ATR_BASE 0x3800
-#define USRP2P_BP_STATUS_BASE 0x3300
+#define USRP2P_MISC_OUTPUT_BASE 0x5000
+#define USRP2P_GPIO_BASE 0x6200
+#define USRP2P_ATR_BASE 0x6800
+#define USRP2P_BP_STATUS_BASE 0x6300
typedef struct {
int sr_misc;
@@ -57,8 +57,12 @@ typedef struct {
int time64_flags; // flags -- see chart below
int time64_imm; // set immediate (0=latch on next pps, 1=latch immediate, default=0)
int time64_tps; // ticks per second rollover count
- int time64_secs_rb;
- int time64_ticks_rb;
+ int time64_mimo_sync;
+ int status;
+ int time64_secs_rb_imm;
+ int time64_ticks_rb_imm;
+ int time64_secs_rb_pps;
+ int time64_ticks_rb_pps;
int compat_num_rb;
int dsp_tx_freq;
int dsp_tx_scale_iq;
diff --git a/host/lib/usrp/usrp_e100/codec_ctrl.cpp b/host/lib/usrp/usrp_e100/codec_ctrl.cpp
index 18d9daca0..b33c8ae65 100644
--- a/host/lib/usrp/usrp_e100/codec_ctrl.cpp
+++ b/host/lib/usrp/usrp_e100/codec_ctrl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -31,7 +31,7 @@ using namespace uhd;
static const bool codec_debug = false;
-const gain_range_t usrp_e100_codec_ctrl::tx_pga_gain_range(-20, 0, float(0.1));
+const gain_range_t usrp_e100_codec_ctrl::tx_pga_gain_range(-20, 0, double(0.1));
const gain_range_t usrp_e100_codec_ctrl::rx_pga_gain_range(0, 20, 1);
/***********************************************************************
@@ -44,14 +44,14 @@ public:
~usrp_e100_codec_ctrl_impl(void);
//aux adc and dac control
- float read_aux_adc(aux_adc_t which);
- void write_aux_dac(aux_dac_t which, float volts);
+ double read_aux_adc(aux_adc_t which);
+ void write_aux_dac(aux_dac_t which, double volts);
//pga gain control
- void set_tx_pga_gain(float);
- float get_tx_pga_gain(void);
- void set_rx_pga_gain(float, char);
- float get_rx_pga_gain(char);
+ void set_tx_pga_gain(double);
+ double get_tx_pga_gain(void);
+ void set_rx_pga_gain(double, char);
+ double get_rx_pga_gain(char);
private:
usrp_e100_iface::sptr _iface;
@@ -135,19 +135,19 @@ usrp_e100_codec_ctrl_impl::~usrp_e100_codec_ctrl_impl(void){
**********************************************************************/
static const int mtpgw = 255; //maximum tx pga gain word
-void usrp_e100_codec_ctrl_impl::set_tx_pga_gain(float gain){
+void usrp_e100_codec_ctrl_impl::set_tx_pga_gain(double gain){
int gain_word = int(mtpgw*(gain - tx_pga_gain_range.start())/(tx_pga_gain_range.stop() - tx_pga_gain_range.start()));
_ad9862_regs.tx_pga_gain = std::clip(gain_word, 0, mtpgw);
this->send_reg(16);
}
-float usrp_e100_codec_ctrl_impl::get_tx_pga_gain(void){
+double usrp_e100_codec_ctrl_impl::get_tx_pga_gain(void){
return (_ad9862_regs.tx_pga_gain*(tx_pga_gain_range.stop() - tx_pga_gain_range.start())/mtpgw) + tx_pga_gain_range.start();
}
static const int mrpgw = 0x14; //maximum rx pga gain word
-void usrp_e100_codec_ctrl_impl::set_rx_pga_gain(float gain, char which){
+void usrp_e100_codec_ctrl_impl::set_rx_pga_gain(double gain, char which){
int gain_word = int(mrpgw*(gain - rx_pga_gain_range.start())/(rx_pga_gain_range.stop() - rx_pga_gain_range.start()));
gain_word = std::clip(gain_word, 0, mrpgw);
switch(which){
@@ -163,7 +163,7 @@ void usrp_e100_codec_ctrl_impl::set_rx_pga_gain(float gain, char which){
}
}
-float usrp_e100_codec_ctrl_impl::get_rx_pga_gain(char which){
+double usrp_e100_codec_ctrl_impl::get_rx_pga_gain(char which){
int gain_word;
switch(which){
case 'A': gain_word = _ad9862_regs.rx_pga_a; break;
@@ -176,11 +176,11 @@ float usrp_e100_codec_ctrl_impl::get_rx_pga_gain(char which){
/***********************************************************************
* Codec Control AUX ADC Methods
**********************************************************************/
-static float aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low){
- return float((boost::uint16_t(high) << 2) | low)*3.3/0x3ff;
+static double aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low){
+ return double((boost::uint16_t(high) << 2) | low)*3.3/0x3ff;
}
-float usrp_e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){
+double usrp_e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){
//check to see if the switch needs to be set
bool write_switch = false;
switch(which){
@@ -233,7 +233,7 @@ float usrp_e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){
/***********************************************************************
* Codec Control AUX DAC Methods
**********************************************************************/
-void usrp_e100_codec_ctrl_impl::write_aux_dac(aux_dac_t which, float volts){
+void usrp_e100_codec_ctrl_impl::write_aux_dac(aux_dac_t which, double volts){
//special case for aux dac d (aka sigma delta word)
if (which == AUX_DAC_D){
boost::uint16_t dac_word = std::clip(boost::math::iround(volts*0xfff/3.3), 0, 0xfff);
diff --git a/host/lib/usrp/usrp_e100/codec_ctrl.hpp b/host/lib/usrp/usrp_e100/codec_ctrl.hpp
index 74ce9bd9a..05d7aab38 100644
--- a/host/lib/usrp/usrp_e100/codec_ctrl.hpp
+++ b/host/lib/usrp/usrp_e100/codec_ctrl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -57,7 +57,7 @@ public:
* \param which which of the 4 adcs
* \return a value in volts
*/
- virtual float read_aux_adc(aux_adc_t which) = 0;
+ virtual double read_aux_adc(aux_adc_t which) = 0;
//! aux dac identifier constants
enum aux_dac_t{
@@ -72,19 +72,19 @@ public:
* \param which which of the 4 dacs
* \param volts the level in in volts
*/
- virtual void write_aux_dac(aux_dac_t which, float volts) = 0;
+ virtual void write_aux_dac(aux_dac_t which, double volts) = 0;
//! Set the TX PGA gain
- virtual void set_tx_pga_gain(float gain) = 0;
+ virtual void set_tx_pga_gain(double gain) = 0;
//! Get the TX PGA gain
- virtual float get_tx_pga_gain(void) = 0;
+ virtual double get_tx_pga_gain(void) = 0;
//! Set the RX PGA gain ('A' or 'B')
- virtual void set_rx_pga_gain(float gain, char which) = 0;
+ virtual void set_rx_pga_gain(double gain, char which) = 0;
//! Get the RX PGA gain ('A' or 'B')
- virtual float get_rx_pga_gain(char which) = 0;
+ virtual double get_rx_pga_gain(char which) = 0;
};
#endif /* INCLUDED_USRP_E100_CODEC_CTRL_HPP */
diff --git a/host/lib/usrp/usrp_e100/codec_impl.cpp b/host/lib/usrp/usrp_e100/codec_impl.cpp
index 6fd44bad3..0d91fb42c 100644
--- a/host/lib/usrp/usrp_e100/codec_impl.cpp
+++ b/host/lib/usrp/usrp_e100/codec_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -86,12 +86,12 @@ void usrp_e100_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){
switch(key.as<codec_prop_t>()){
case CODEC_PROP_GAIN_I:
UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- _codec_ctrl->set_rx_pga_gain(val.as<float>(), 'A');
+ _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'A');
return;
case CODEC_PROP_GAIN_Q:
UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- _codec_ctrl->set_rx_pga_gain(val.as<float>(), 'B');
+ _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'B');
return;
default: UHD_THROW_PROP_SET_ERROR();
@@ -141,7 +141,7 @@ void usrp_e100_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val){
case CODEC_PROP_GAIN_I: //only one gain for I and Q
case CODEC_PROP_GAIN_Q:
UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- _codec_ctrl->set_tx_pga_gain(val.as<float>());
+ _codec_ctrl->set_tx_pga_gain(val.as<double>());
return;
default: UHD_THROW_PROP_SET_ERROR();
diff --git a/host/lib/usrp/usrp_e100/dboard_iface.cpp b/host/lib/usrp/usrp_e100/dboard_iface.cpp
index a5032f86f..e4c3856c9 100644
--- a/host/lib/usrp/usrp_e100/dboard_iface.cpp
+++ b/host/lib/usrp/usrp_e100/dboard_iface.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -60,8 +60,8 @@ public:
return props;
}
- void write_aux_dac(unit_t, aux_dac_t, float);
- float read_aux_adc(unit_t, aux_adc_t);
+ void write_aux_dac(unit_t, aux_dac_t, double);
+ double read_aux_adc(unit_t, aux_adc_t);
void _set_pin_ctrl(unit_t, boost::uint16_t);
void _set_atr_reg(unit_t, atr_reg_t, boost::uint16_t);
@@ -270,7 +270,7 @@ byte_vector_t usrp_e100_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_b
/***********************************************************************
* Aux DAX/ADC
**********************************************************************/
-void usrp_e100_dboard_iface::write_aux_dac(dboard_iface::unit_t, aux_dac_t which, float value){
+void usrp_e100_dboard_iface::write_aux_dac(dboard_iface::unit_t, aux_dac_t which, double value){
//same aux dacs for each unit
static const uhd::dict<aux_dac_t, usrp_e100_codec_ctrl::aux_dac_t> which_to_aux_dac = map_list_of
(AUX_DAC_A, usrp_e100_codec_ctrl::AUX_DAC_A)
@@ -281,7 +281,7 @@ void usrp_e100_dboard_iface::write_aux_dac(dboard_iface::unit_t, aux_dac_t which
_codec->write_aux_dac(which_to_aux_dac[which], value);
}
-float usrp_e100_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, aux_adc_t which){
+double usrp_e100_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, aux_adc_t which){
static const uhd::dict<
unit_t, uhd::dict<aux_adc_t, usrp_e100_codec_ctrl::aux_adc_t>
> unit_to_which_to_aux_adc = map_list_of
diff --git a/host/lib/usrp/usrp_e100/dsp_impl.cpp b/host/lib/usrp/usrp_e100/dsp_impl.cpp
index 43a3bd3be..7d358a607 100644
--- a/host/lib/usrp/usrp_e100/dsp_impl.cpp
+++ b/host/lib/usrp/usrp_e100/dsp_impl.cpp
@@ -38,7 +38,7 @@ void usrp_e100_impl::rx_ddc_init(void){
//initial config and update
rx_ddc_set(DSP_PROP_FREQ_SHIFT, double(0));
- rx_ddc_set(DSP_PROP_HOST_RATE, double(64e6/10));
+ rx_ddc_set(DSP_PROP_HOST_RATE, double(16e6));
}
/***********************************************************************
@@ -121,7 +121,7 @@ void usrp_e100_impl::tx_duc_init(void){
//initial config and update
tx_duc_set(DSP_PROP_FREQ_SHIFT, double(0));
- tx_duc_set(DSP_PROP_HOST_RATE, double(64e6/10));
+ tx_duc_set(DSP_PROP_HOST_RATE, double(16e6));
}
/***********************************************************************
diff --git a/host/lib/usrp/usrp_e100/mboard_impl.cpp b/host/lib/usrp/usrp_e100/mboard_impl.cpp
index fe26cd63d..f52d2e6fb 100644
--- a/host/lib/usrp/usrp_e100/mboard_impl.cpp
+++ b/host/lib/usrp/usrp_e100/mboard_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-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
@@ -36,11 +36,13 @@ void usrp_e100_impl::mboard_init(void){
boost::bind(&usrp_e100_impl::mboard_set, this, _1, _2)
);
- //init the clock config
- _clock_config.ref_source = clock_config_t::REF_AUTO;
- _clock_config.pps_source = clock_config_t::PPS_SMA;
- _clock_config.pps_polarity = clock_config_t::PPS_NEG;
+ //set the ticks per seconds into the vita time control
+ _iface->poke32(UE_REG_TIME64_TPS,
+ boost::uint32_t(_clock_ctrl->get_fpga_clock_rate())
+ );
+ //init the clock config
+ _clock_config = clock_config_t::internal();
update_clock_config();
}
@@ -134,6 +136,22 @@ void usrp_e100_impl::mboard_get(const wax::obj &key_, wax::obj &val){
val = _iface->mb_eeprom;
return;
+ case MBOARD_PROP_TIME_NOW: while(true){
+ uint32_t secs = _iface->peek32(UE_REG_RB_TIME_NOW_SECS);
+ uint32_t ticks = _iface->peek32(UE_REG_RB_TIME_NOW_TICKS);
+ if (secs != _iface->peek32(UE_REG_RB_TIME_NOW_SECS)) continue;
+ val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate());
+ return;
+ }
+
+ case MBOARD_PROP_TIME_PPS: while(true){
+ uint32_t secs = _iface->peek32(UE_REG_RB_TIME_PPS_SECS);
+ uint32_t ticks = _iface->peek32(UE_REG_RB_TIME_PPS_TICKS);
+ if (secs != _iface->peek32(UE_REG_RB_TIME_PPS_SECS)) continue;
+ val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate());
+ return;
+ }
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -150,7 +168,7 @@ void usrp_e100_impl::mboard_set(const wax::obj &key, const wax::obj &val){
return;
case MBOARD_PROP_TIME_NOW:
- case MBOARD_PROP_TIME_NEXT_PPS:{
+ case MBOARD_PROP_TIME_PPS:{
time_spec_t time_spec = val.as<time_spec_t>();
_iface->poke32(UE_REG_TIME64_TICKS, time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate()));
boost::uint32_t imm_flags = (key.as<mboard_prop_t>() == MBOARD_PROP_TIME_NOW)? 1 : 0;
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
index de158ea5e..864e82099 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
+++ b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
@@ -30,7 +30,7 @@
#ifndef INCLUDED_USRP_E100_IMPL_HPP
#define INCLUDED_USRP_E100_IMPL_HPP
-static const boost::uint16_t USRP_E_COMPAT_NUM = 0x02;
+static const boost::uint16_t USRP_E_COMPAT_NUM = 0x03;
//! load an fpga image from a bin file into the usrp-e fpga
extern void usrp_e100_load_fpga(const std::string &bin_file);
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp b/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp
index 625fb2c35..a57fe5171 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp
+++ b/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp
@@ -114,6 +114,16 @@
#define UE_REG_ATR_FULL_RXSIDE UE_REG_ATR_BASE + 12
#define UE_REG_ATR_FULL_TXSIDE UE_REG_ATR_BASE + 14
+///////////////////////////////////////////////////
+// Slave 7 -- Readback Mux 32
+
+#define UE_REG_RB_MUX_32_BASE UE_REG_SLAVE(7)
+
+#define UE_REG_RB_TIME_NOW_SECS UE_REG_RB_MUX_32_BASE + 0
+#define UE_REG_RB_TIME_NOW_TICKS UE_REG_RB_MUX_32_BASE + 4
+#define UE_REG_RB_TIME_PPS_SECS UE_REG_RB_MUX_32_BASE + 8
+#define UE_REG_RB_TIME_PPS_TICKS UE_REG_RB_MUX_32_BASE + 12
+
/////////////////////////////////////////////////
// DSP RX Regs
////////////////////////////////////////////////