summaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/usrp2
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2011-01-19 22:23:46 -0800
committerJosh Blum <josh@joshknows.com>2011-01-19 22:23:46 -0800
commit9239878b0b81c3a368bf11cfc2fe48bfb05ff902 (patch)
treef41a5e58eac89b35cb99537a0a0b64662384a9f2 /host/lib/usrp/usrp2
parentfc138381ee4bd8d191795230b7447071a85e1f28 (diff)
parent7d918c5f6acc9a5d2c8ae03e2e67b403f7efd5ff (diff)
downloaduhd-9239878b0b81c3a368bf11cfc2fe48bfb05ff902.tar.gz
uhd-9239878b0b81c3a368bf11cfc2fe48bfb05ff902.tar.bz2
uhd-9239878b0b81c3a368bf11cfc2fe48bfb05ff902.zip
Merge branch 'next'
Conflicts: host/lib/usrp/usrp2/codec_impl.cpp
Diffstat (limited to 'host/lib/usrp/usrp2')
-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.cpp207
-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
20 files changed, 437 insertions, 551 deletions
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.cpp b/host/lib/usrp/usrp2/gps_ctrl.cpp
deleted file mode 100644
index 2273b2cd9..000000000
--- a/host/lib/usrp/usrp2/gps_ctrl.cpp
+++ /dev/null
@@ -1,207 +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 "gps_ctrl.hpp"
-#include <uhd/utils/assert.hpp>
-#include <boost/cstdint.hpp>
-#include <string>
-#include <boost/date_time/posix_time/posix_time.hpp>
-#include <boost/thread.hpp>
-#include <boost/algorithm/string/trim.hpp>
-#include <boost/tokenizer.hpp>
-
-using namespace uhd;
-using namespace boost::gregorian;
-using namespace boost::posix_time;
-using namespace boost::algorithm;
-
-/*!
- * A usrp2 GPS control for Jackson Labs devices
- */
-
-//TODO: multiple baud rate support (requires mboard_impl changes for poking UART registers)
-class usrp2_gps_ctrl_impl : public usrp2_gps_ctrl{
-public:
- usrp2_gps_ctrl_impl(usrp2_iface::sptr iface){
- _iface = iface;
-
- std::string reply;
- bool i_heard_some_nmea = false, i_heard_something_weird = false;
-
- gps_type = GPS_TYPE_NONE;
-
-// 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
-
- //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;
- while(timeout--) {
- reply = safe_gps_read();
- if(trim_right_copy(reply) == "Command Error") {
- gps_type = GPS_TYPE_JACKSON_LABS;
- break;
- }
- 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
- }
-
- 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;
- }
-
- bool found_gprmc = false;
-
- switch(gps_type) {
- case GPS_TYPE_JACKSON_LABS:
- std::cout << "Found a Jackson Labs GPS" << std::endl;
- //issue some setup stuff so it spits out the appropriate data
- //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");
- boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS));
- _iface->write_uart(GPS_UART, "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");
- boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS));
- _iface->write_uart(GPS_UART, "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");
- boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS));
-
-// break;
-
- case GPS_TYPE_GENERIC_NMEA:
- if(gps_type == GPS_TYPE_GENERIC_NMEA) std::cout << "Found a generic NMEA GPS device" << std::endl;
- found_gprmc = false;
- //here we loop around looking for a GPRMC packet. if we don't get one, we don't have a usable GPS.
- timeout = GPS_TIMEOUT_TRIES;
- while(timeout--) {
- reply = safe_gps_read();
- if(reply.substr(0, 6) == "$GPRMC") {
- found_gprmc = true;
- break;
- }
- }
- if(!found_gprmc) {
- if(gps_type == GPS_TYPE_JACKSON_LABS) std::cout << "Firefly GPS not locked or warming up." << std::endl;
- else std::cout << "GPS does not output GPRMC packets. Cannot retrieve time." << std::endl;
- gps_type = GPS_TYPE_NONE;
- }
- break;
-
- case GPS_TYPE_NONE:
- default:
- break;
-
- }
-
-
- }
-
- ~usrp2_gps_ctrl_impl(void){
-
- }
-
- 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;
- } 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
- reply = std::string();
- }
- }
- return reply;
- }
-
- ptime get_time(void) {
- std::string reply;
- ptime now;
- boost::tokenizer<boost::escaped_list_separator<char> > tok(reply);
- std::vector<std::string> toked;
- int timeout = GPS_TIMEOUT_TRIES;
- bool found_gprmc = false;
- switch(gps_type) {
- case GPS_TYPE_JACKSON_LABS: //deprecated in favor of a single NMEA parser
- case GPS_TYPE_GENERIC_NMEA:
-
- while(timeout--) {
- reply = safe_gps_read();
- if(reply.substr(0, 6) == "$GPRMC") {
- found_gprmc = true;
- break;
- }
- }
- UHD_ASSERT_THROW(found_gprmc);
-
- tok.assign(reply);
- toked.assign(tok.begin(), tok.end());
-
- UHD_ASSERT_THROW(toked.size() == 11); //if it's not we got something weird in there
-
- now = ptime( date(
- greg_year(boost::lexical_cast<int>(toked[8].substr(4, 2)) + 2000), //just trust me on this one
- greg_month(boost::lexical_cast<int>(toked[8].substr(2, 2))),
- greg_day(boost::lexical_cast<int>(toked[8].substr(0, 2)))
- ),
- hours( boost::lexical_cast<int>(toked[1].substr(0, 2)))
- + minutes(boost::lexical_cast<int>(toked[1].substr(2, 2)))
- + seconds(boost::lexical_cast<int>(toked[1].substr(4, 2)))
- );
- break;
- case GPS_TYPE_NONE:
- default:
- throw std::runtime_error("get_time(): Unsupported GPS or no GPS detected\n");
- break;
- }
- return now;
- }
-
- bool gps_detected(void) {
- return (gps_type != GPS_TYPE_NONE);
- }
-
-private:
- usrp2_iface::sptr _iface;
-
- enum {
- GPS_TYPE_JACKSON_LABS,
- GPS_TYPE_GENERIC_NMEA,
- 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 FIREFLY_STUPID_DELAY_MS = 200;
-
-};
-
-/***********************************************************************
- * 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));
-}
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;