summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--firmware/zpu/lib/hal_io.c14
-rw-r--r--host/Modules/UHDPackage.cmake2
-rw-r--r--host/Modules/UHDVersion.cmake4
-rw-r--r--host/README.txt3
-rw-r--r--host/docs/usrp2.rst48
-rw-r--r--host/examples/benchmark_rx_rate.cpp39
-rw-r--r--host/examples/rx_ascii_art_dft.cpp53
-rw-r--r--host/include/uhd/usrp/dboard_props.hpp1
-rw-r--r--host/include/uhd/usrp/gps_ctrl.hpp6
-rw-r--r--host/lib/device.cpp7
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp2
-rw-r--r--host/lib/usrp/dboard/CMakeLists.txt6
-rw-r--r--host/lib/usrp/dboard/db_dbsrx.cpp6
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp39
-rw-r--r--host/lib/usrp/dboard/db_sbx.cpp793
-rw-r--r--host/lib/usrp/dboard/db_wbx_common.cpp (renamed from host/lib/usrp/dboard/db_wbx.cpp)295
-rw-r--r--host/lib/usrp/dboard/db_wbx_common.hpp72
-rw-r--r--host/lib/usrp/dboard/db_wbx_simple.cpp251
-rw-r--r--host/lib/usrp/dboard/db_xcvr2450.cpp2
-rw-r--r--host/lib/usrp/dboard_manager.cpp198
-rw-r--r--host/lib/usrp/gps_ctrl.cpp14
-rw-r--r--host/lib/usrp/mboard_eeprom.cpp23
-rw-r--r--host/lib/usrp/usrp1/dboard_impl.cpp12
-rw-r--r--host/lib/usrp/usrp1/io_impl.cpp6
-rw-r--r--host/lib/usrp/usrp1/mboard_impl.cpp2
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.hpp2
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp14
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp2
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp44
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp28
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp7
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp1
-rw-r--r--host/lib/usrp/usrp_e100/dboard_impl.cpp15
-rw-r--r--host/lib/usrp/usrp_e100/io_impl.cpp17
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_impl.cpp12
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_impl.hpp9
-rw-r--r--host/utils/CMakeLists.txt11
-rw-r--r--host/utils/uhd_usrp_probe.cpp23
-rw-r--r--host/utils/usrp1_init_eeprom.cpp6
-rwxr-xr-xhost/utils/usrp2_card_burner.py22
-rw-r--r--host/utils/usrp_burn_db_eeprom.cpp15
41 files changed, 1728 insertions, 398 deletions
diff --git a/firmware/zpu/lib/hal_io.c b/firmware/zpu/lib/hal_io.c
index 1d137943c..4ed694b9d 100644
--- a/firmware/zpu/lib/hal_io.c
+++ b/firmware/zpu/lib/hal_io.c
@@ -255,12 +255,14 @@ fngets(hal_uart_name_t u, char * const s, int len)
int
fngets_noblock(hal_uart_name_t u, char * const s, int len)
{
- char *x = s;
-
- while(((*x=(char)hal_uart_getc_noblock(u)) != '\n') && (*x != 255) && ((x-s) < len)) x++;
- *x = 0;
- //printf("Returning from fngets() with string %d of length %d\n", s[0], x-s);
- return (x-s);
+ int i;
+ for(i=0; i < len; i++) {
+ s[i] = (char) hal_uart_getc_noblock(u);
+ if((s[i] == 255) || (s[i] == '\n')) break;
+ }
+ s[i] = 0;
+
+ return i;
}
char *
diff --git a/host/Modules/UHDPackage.cmake b/host/Modules/UHDPackage.cmake
index 416d89998..c230f1b1e 100644
--- a/host/Modules/UHDPackage.cmake
+++ b/host/Modules/UHDPackage.cmake
@@ -18,6 +18,8 @@
########################################################################
INCLUDE(UHDVersion) #sets version information
+SET(UHD_RELEASE_MODE "${UHD_RELEASE_MODE}" CACHE BOOL "set UHD to release mode to build installers")
+
########################################################################
# Setup additional defines for OS types
########################################################################
diff --git a/host/Modules/UHDVersion.cmake b/host/Modules/UHDVersion.cmake
index 86d3133a8..abee8f509 100644
--- a/host/Modules/UHDVersion.cmake
+++ b/host/Modules/UHDVersion.cmake
@@ -26,8 +26,8 @@ FIND_PACKAGE(Git QUIET)
# - increment patch on for bug fixes and docs
########################################################################
SET(UHD_VERSION_MAJOR 003)
-SET(UHD_VERSION_MINOR 000)
-SET(UHD_VERSION_PATCH 001)
+SET(UHD_VERSION_MINOR 001)
+SET(UHD_VERSION_PATCH 000)
########################################################################
# Version information discovery through git log
diff --git a/host/README.txt b/host/README.txt
index b510493d5..64d0307ed 100644
--- a/host/README.txt
+++ b/host/README.txt
@@ -21,10 +21,11 @@ LF RX
LF TX
RFX Series
XCVR 2450
-WBX Series
+WBX + Simple GDB
DBSRX
DBSRX2
TVRX
+SBX
###############################################
# Documentation
diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst
index 161170f2c..2eb3ee796 100644
--- a/host/docs/usrp2.rst
+++ b/host/docs/usrp2.rst
@@ -345,3 +345,51 @@ Test the PPS input with the following app:
cd <install-path>/share/uhd/examples
./test_pps_input --args=<args>
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Internal GPSDO
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+USRP-N2XX models can have an optional internal GPSDO.
+To use the GPSDO with UHD, you must burn an EEPROM setting
+so that UHD knows that the internal GPSDO was installed.
+
+**Installation instructions:**
+
+1. Remove the daughterboard.
+2. Move J510 jumper on the motherboard from 1-2 to 2-3 in order to switch from external 10 MHz Ref Clock to GPSDO’s 10 MHz Ref Clock
+3. Screw the GPSDO module in place with the screws provided. The screws are treated to avoid loosening with vibration.
+4. Connect the GPSDO power cable to J509 on the motherboard, and then to connector D on the GPSDO module
+5. Connect an SMB to SMA cable between connectors B and J506 (PPS2)
+6. Connect an SMB to SMA cable between connectors C and J507 (CLK REF2)
+7. Connect the serial cable between connectors A and J312 (RS232-3) on the motherboard. If J312 on your USRP isn’t a keyed connector, please ensure to connect pin1 (TX) of connector A to pin3 (RX) on J312.
+8. Remove the washer and nut from the MMCX to SMA-Bulkhead cable. Connect it to connector E and then insert SMA-Bulkhead connector through the hole in the rear panel. Tighten nut to fasten in place.
+9. Replace the daughterboard pushing all the cables underneath.
+
+Then run the following commands:
+::
+
+ cd <install-path>/share/uhd/utils
+ ./usrp_burn_mb_eeprom --args=<optional device args> --key=gpsdo --val=internal
+
+**Removal instructions:**
+
+Restore the jumper setting, disconnect the cables, and unscrew the GPSDO unit.
+Then run the following commands:
+::
+
+ cd <install-path>/share/uhd/utils
+ ./usrp_burn_mb_eeprom --args=<optional device args> --key=gpsdo --val=none
+
+------------------------------------------------------------------------
+Miscellaneous
+------------------------------------------------------------------------
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Available Sensors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The following sensors are available for the USRP2/N-Series motherboards;
+they can be queried through the API.
+
+* mimo_locked - clock reference locked over the MIMO cable
+* ref_locked - clock reference locked (internal/external)
+* gps_time - GPS seconds (available when GPSDO installed)
diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp
index 118bf413c..50af1b98b 100644
--- a/host/examples/benchmark_rx_rate.cpp
+++ b/host/examples/benchmark_rx_rate.cpp
@@ -114,7 +114,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//variables to be set by po
std::string args;
double duration;
- double only_rate;
+ double rate;
//setup the program options
po::options_description desc("Allowed options");
@@ -122,7 +122,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("help", "help message")
("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
("duration", po::value<double>(&duration)->default_value(10.0), "duration for each test in seconds")
- ("rate", po::value<double>(&only_rate), "specify to perform a single test as this rate (sps)")
+ ("rate", po::value<double>(&rate), "specify to perform a single test as this rate (sps)")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
@@ -134,26 +134,31 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
return ~0;
}
+ //verify that rate was specified
+ if (not vm.count("rate")){
+ std::cerr << "Please specify the sample rate with --rate" << std::endl;
+ return ~0;
+ }
+
//create a usrp device
std::cout << std::endl;
+ uhd::device_addrs_t device_addrs = uhd::device::find(args);
+ if (device_addrs.empty()){
+ std::cerr << "Could not find any devices for: " << args << std::endl;
+ return ~0;
+ }
+ if (device_addrs.at(0).get("type", "") == "usrp1"){
+ std::cerr << "*** Warning! ***" << std::endl;
+ std::cerr << "Benchmark RX results will be inaccurate on USRP1 due to soft-time control.\n" << std::endl;
+ }
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
- uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
+ uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(device_addrs.at(0));
std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
- if (not vm.count("rate")){
- usrp->set_rx_rate(500e3); //initial rate
- while(true){
- double rate = usrp->get_rx_rate();
- test_device(usrp, rate, duration);
- usrp->set_rx_rate(rate*2); //double the rate
- if (usrp->get_rx_rate() == rate) break;
- }
- }
- else{
- usrp->set_rx_rate(only_rate);
- double rate = usrp->get_rx_rate();
- test_device(usrp, rate, duration);
- }
+ //start the test
+ usrp->set_rx_rate(rate);
+ rate = usrp->get_rx_rate();
+ test_device(usrp, rate, duration);
//finished
std::cout << std::endl << "Done!" << std::endl << std::endl;
diff --git a/host/examples/rx_ascii_art_dft.cpp b/host/examples/rx_ascii_art_dft.cpp
index c407ecf91..fa8c4d4a4 100644
--- a/host/examples/rx_ascii_art_dft.cpp
+++ b/host/examples/rx_ascii_art_dft.cpp
@@ -32,9 +32,9 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::set_thread_priority_safe();
//variables to be set by po
- std::string args;
+ std::string args, ant, subdev;
size_t num_bins;
- double rate, freq, gain, frame_rate;
+ double rate, freq, gain, bw, frame_rate;
float ref_lvl, dyn_rng;
//setup the program options
@@ -44,8 +44,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("args", po::value<std::string>(&args)->default_value(""), "multi uhd device address args")
// hardware parameters
("rate", po::value<double>(&rate), "rate of incoming samples (sps)")
- ("freq", po::value<double>(&freq)->default_value(0), "RF center frequency in Hz")
- ("gain", po::value<double>(&gain)->default_value(0), "gain for the RF chain")
+ ("freq", po::value<double>(&freq), "RF center frequency in Hz")
+ ("gain", po::value<double>(&gain), "gain for the RF chain")
+ ("ant", po::value<std::string>(&ant), "daughterboard antenna selection")
+ ("subdev", po::value<std::string>(&subdev), "daughterboard subdevice specification")
+ ("bw", po::value<double>(&bw), "daughterboard IF filter bandwidth in Hz")
// display parameters
("num-bins", po::value<size_t>(&num_bins)->default_value(512), "the number of bins in the DFT")
("frame-rate", po::value<double>(&frame_rate)->default_value(5), "frame rate of the display (fps)")
@@ -66,22 +69,48 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
+
+ //always select the subdevice first, the channel mapping affects the other settings
+ if (vm.count("subdev")) usrp->set_rx_subdev_spec(subdev);
+
std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
- //set the rx sample rate
+ //set the sample rate
+ if (not vm.count("rate")){
+ std::cerr << "Please specify the sample rate with --rate" << std::endl;
+ return ~0;
+ }
std::cout << boost::format("Setting RX Rate: %f Msps...") % (rate/1e6) << std::endl;
usrp->set_rx_rate(rate);
std::cout << boost::format("Actual RX Rate: %f Msps...") % (usrp->get_rx_rate()/1e6) << std::endl << std::endl;
- //set the rx center frequency
- std::cout << boost::format("Setting RX Freq: %f Mhz...") % (freq/1e6) << std::endl;
+ //set the center frequency
+ if (not vm.count("freq")){
+ std::cerr << "Please specify the center frequency with --freq" << std::endl;
+ return ~0;
+ }
+ std::cout << boost::format("Setting RX Freq: %f MHz...") % (freq/1e6) << std::endl;
usrp->set_rx_freq(freq);
- std::cout << boost::format("Actual RX Freq: %f Mhz...") % (usrp->get_rx_freq()/1e6) << std::endl << std::endl;
+ std::cout << boost::format("Actual RX Freq: %f MHz...") % (usrp->get_rx_freq()/1e6) << std::endl << std::endl;
+
+ //set the rf gain
+ if (vm.count("gain")){
+ std::cout << boost::format("Setting RX Gain: %f dB...") % gain << std::endl;
+ usrp->set_rx_gain(gain);
+ std::cout << boost::format("Actual RX Gain: %f dB...") % usrp->get_rx_gain() << std::endl << std::endl;
+ }
+
+ //set the IF filter bandwidth
+ if (vm.count("bw")){
+ std::cout << boost::format("Setting RX Bandwidth: %f MHz...") % bw << std::endl;
+ usrp->set_rx_bandwidth(bw);
+ std::cout << boost::format("Actual RX Bandwidth: %f MHz...") % usrp->get_rx_bandwidth() << std::endl << std::endl;
+ }
+
+ //set the antenna
+ if (vm.count("ant")) usrp->set_rx_antenna(ant);
- //set the rx rf gain
- std::cout << boost::format("Setting RX Gain: %f dB...") % gain << std::endl;
- usrp->set_rx_gain(gain);
- std::cout << boost::format("Actual RX Gain: %f dB...") % usrp->get_rx_gain() << std::endl << std::endl;
+ boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow for some setup time
//allocate recv buffer and metatdata
uhd::rx_metadata_t md;
diff --git a/host/include/uhd/usrp/dboard_props.hpp b/host/include/uhd/usrp/dboard_props.hpp
index 35721ab47..29211ec8c 100644
--- a/host/include/uhd/usrp/dboard_props.hpp
+++ b/host/include/uhd/usrp/dboard_props.hpp
@@ -32,6 +32,7 @@ namespace uhd{ namespace usrp{
DBOARD_PROP_SUBDEV, //ro, wax::obj
DBOARD_PROP_SUBDEV_NAMES, //ro, prop_names_t
DBOARD_PROP_DBOARD_EEPROM, //rw, dboard_eeprom_t
+ DBOARD_PROP_GBOARD_EEPROM, //rw, dboard_eeprom_t
DBOARD_PROP_DBOARD_IFACE, //ro, dboard_iface::sptr
DBOARD_PROP_CODEC, //ro, wax::obj
DBOARD_PROP_GAIN_GROUP //ro, gain_group
diff --git a/host/include/uhd/usrp/gps_ctrl.hpp b/host/include/uhd/usrp/gps_ctrl.hpp
index 21d400b3b..bd679b165 100644
--- a/host/include/uhd/usrp/gps_ctrl.hpp
+++ b/host/include/uhd/usrp/gps_ctrl.hpp
@@ -42,6 +42,12 @@ public:
* \return current GPS time and date as boost::posix_time::ptime object
*/
virtual ptime get_time(void) = 0;
+
+ /*!
+ * Get the epoch time (as time_t, which is int)
+ * \return current GPS time and date as time_t
+ */
+ virtual time_t get_epoch_time(void) = 0;
/*!
* Tell you if there's a supported GPS connected or not
diff --git a/host/lib/device.cpp b/host/lib/device.cpp
index 1b3daa103..b2b0238d2 100644
--- a/host/lib/device.cpp
+++ b/host/lib/device.cpp
@@ -25,10 +25,13 @@
#include <boost/weak_ptr.hpp>
#include <boost/functional/hash.hpp>
#include <boost/tuple/tuple.hpp>
+#include <boost/thread/mutex.hpp>
#include <iostream>
using namespace uhd;
+static boost::mutex _device_mutex;
+
/***********************************************************************
* Helper Functions
**********************************************************************/
@@ -70,6 +73,8 @@ void device::register_device(
* Discover
**********************************************************************/
device_addrs_t device::find(const device_addr_t &hint){
+ boost::mutex::scoped_lock lock(_device_mutex);
+
device_addrs_t device_addrs;
BOOST_FOREACH(const dev_fcn_reg_t &fcn, get_dev_fcn_regs()){
@@ -93,6 +98,8 @@ device_addrs_t device::find(const device_addr_t &hint){
* Make
**********************************************************************/
device::sptr device::make(const device_addr_t &hint, size_t which){
+ boost::mutex::scoped_lock lock(_device_mutex);
+
typedef boost::tuple<device_addr_t, make_t> dev_addr_make_t;
std::vector<dev_addr_make_t> dev_addr_makers;
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp
index e42cab1d1..ec2077d30 100644
--- a/host/lib/transport/libusb1_zero_copy.cpp
+++ b/host/lib/transport/libusb1_zero_copy.cpp
@@ -277,10 +277,10 @@ private:
bool _threads_running;
void run_event_loop(boost::barrier &spawn_barrier){
+ _threads_running = true;
spawn_barrier.wait();
set_thread_priority_safe();
libusb_context *context = libusb::session::get_global_session()->get_context();
- _threads_running = true;
try{
while(_threads_running){
timeval tv;
diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt
index 7bd201294..0eff5c4bd 100644
--- a/host/lib/usrp/dboard/CMakeLists.txt
+++ b/host/lib/usrp/dboard/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
@@ -23,7 +23,9 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/db_basic_and_lf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/db_rfx.cpp
${CMAKE_CURRENT_SOURCE_DIR}/db_xcvr2450.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/db_wbx.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/db_sbx.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/db_wbx_common.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/db_wbx_simple.cpp
${CMAKE_CURRENT_SOURCE_DIR}/db_dbsrx.cpp
${CMAKE_CURRENT_SOURCE_DIR}/db_unknown.cpp
${CMAKE_CURRENT_SOURCE_DIR}/db_tvrx.cpp
diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp
index b984608ca..8fdd4f953 100644
--- a/host/lib/usrp/dboard/db_dbsrx.cpp
+++ b/host/lib/usrp/dboard/db_dbsrx.cpp
@@ -543,7 +543,7 @@ void dbsrx::rx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_ANTENNA:
- val = std::string("J3");
+ val = dbsrx_antennas.at(0);
return;
case SUBDEV_PROP_ANTENNA_NAMES:
@@ -589,6 +589,10 @@ void dbsrx::rx_set(const wax::obj &key_, const wax::obj &val){
this->set_lo_freq(val.as<double>());
return;
+ case SUBDEV_PROP_ANTENNA:
+ assert_has(dbsrx_antennas, val.as<std::string>(), "DBSRX antenna name");
+ return;
+
case SUBDEV_PROP_GAIN:
this->set_gain(val.as<double>(), key.name);
return;
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index f938c749a..725b5cc03 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -312,8 +312,7 @@ double rfx_xcvr::set_lo_freq(
(8, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_8)
;
- std::vector<double> clock_rates = this->get_iface()->get_clock_rates(unit);
- double actual_freq = 0, ref_freq = 0;
+ double actual_freq=0, ref_freq = this->get_iface()->get_clock_rate(unit);
int R=0, BS=0, P=0, B=0, A=0;
/*
@@ -326,31 +325,27 @@ double rfx_xcvr::set_lo_freq(
* fvco = [P*B + A] * fref/R
* fvco*R/fref = P*B + A = N
*/
- for(R = 1; R <= 32; R+=((R==1)?1:2)){
- BOOST_FOREACH(ref_freq, uhd::reversed(uhd::sorted(clock_rates))){
- BOOST_FOREACH(BS, bandsel_to_enum.keys()){
- if (ref_freq/R/BS > 1e6) continue; //constraint on band select clock
- BOOST_FOREACH(P, prescaler_to_enum.keys()){
- //calculate B and A from N
- double N = target_freq*R/ref_freq;
- B = int(std::floor(N/P));
- A = boost::math::iround(N - P*B);
- if (B < A or B > 8191 or B < 3 or A > 31) continue; //constraints on A, B
- //calculate the actual frequency
- actual_freq = double(P*B + A)*ref_freq/R;
- if (actual_freq/P > 300e6) continue; //constraint on prescaler output
- //constraints met: exit loop
- goto done_loop;
- }
+ for(R = 2; R <= 32; R+=2){
+ BOOST_FOREACH(BS, bandsel_to_enum.keys()){
+ if (ref_freq/R/BS > 1e6) continue; //constraint on band select clock
+ BOOST_FOREACH(P, prescaler_to_enum.keys()){
+ //calculate B and A from N
+ double N = target_freq*R/ref_freq;
+ B = int(std::floor(N/P));
+ A = boost::math::iround(N - P*B);
+ if (B < A or B > 8191 or B < 3 or A > 31) continue; //constraints on A, B
+ //calculate the actual frequency
+ actual_freq = double(P*B + A)*ref_freq/R;
+ if (actual_freq/P > 300e6) continue; //constraint on prescaler output
+ //constraints met: exit loop
+ goto done_loop;
}
}
} done_loop:
if (rfx_debug) std::cerr << boost::format(
- "RFX tune: R=%d, BS=%d, P=%d, B=%d, A=%d, DIV2=%d, ref=%fMHz"
- ) % R % BS % P % B % A % int(_div2[unit] && (!is_rx_rfx400)) % (ref_freq/1e6) << std::endl;
-
- this->get_iface()->set_clock_rate(unit, ref_freq);
+ "RFX tune: R=%d, BS=%d, P=%d, B=%d, A=%d, DIV2=%d"
+ ) % R % BS % P % B % A % int(_div2[unit] && (!is_rx_rfx400)) << std::endl;
//load the register values
adf4360_regs_t regs;
diff --git a/host/lib/usrp/dboard/db_sbx.cpp b/host/lib/usrp/dboard/db_sbx.cpp
new file mode 100644
index 000000000..d0c3c63ac
--- /dev/null
+++ b/host/lib/usrp/dboard/db_sbx.cpp
@@ -0,0 +1,793 @@
+//
+// 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/>.
+//
+
+// Common IO Pins
+#define LO_LPF_EN (1 << 15)
+#define ADF4350_CE (1 << 3)
+#define ADF4350_PDBRF (1 << 2)
+#define ADF4350_MUXOUT (1 << 1) // INPUT!!!
+#define LOCKDET_MASK (1 << 0) // INPUT!!!
+
+// TX IO Pins
+#define TRSW (1 << 14) // 0 = TX, 1 = RX
+#define TX_LED_TXRX (1 << 7) // LED for TX Antenna Selection TX/RX
+#define TX_LED_LD (1 << 6) // LED for TX Lock Detect
+#define DIS_POWER_TX (1 << 5) // on UNIT_TX, 0 powers up TX
+#define TX_ENABLE (1 << 4) // on UNIT_TX, 0 disables TX Mixer
+
+// RX IO Pins
+#define LNASW (1 << 14) // 0 = TX/RX, 1 = RX2
+#define RX_LED_RX1RX2 (1 << 7) // LED for RX Antenna Selection RX1/RX2
+#define RX_LED_LD (1 << 6) // LED for RX Lock Detect
+#define DIS_POWER_RX (1 << 5) // on UNIT_RX, 0 powers up RX
+#define RX_DISABLE (1 << 4) // on UNIT_RX, 1 disables RX Mixer and Baseband
+
+// RX Attenuator Pins
+#define RX_ATTN_SHIFT 8 // lsb of RX Attenuator Control
+#define RX_ATTN_MASK (63 << RX_ATTN_SHIFT) // valid bits of RX Attenuator Control
+
+// TX Attenuator Pins
+#define TX_ATTN_SHIFT 8 // lsb of RX Attenuator Control
+#define TX_ATTN_MASK (63 << TX_ATTN_SHIFT) // valid bits of RX Attenuator Control
+
+// Mixer functions
+#define TX_MIXER_ENB (ADF4350_PDBRF)
+#define TX_MIXER_DIS 0
+
+#define RX_MIXER_ENB (ADF4350_PDBRF)
+#define RX_MIXER_DIS 0
+
+// Pin functions
+#define TX_LED_IO (TX_LED_TXRX|TX_LED_LD) // LED gpio lines, pull down for LED
+#define TXIO_MASK (LO_LPF_EN|TRSW|ADF4350_CE|ADF4350_PDBRF|TX_ATTN_MASK|DIS_POWER_TX|TX_ENABLE)
+
+#define RX_LED_IO (RX_LED_RX1RX2|RX_LED_LD) // LED gpio lines, pull down for LED
+#define RXIO_MASK (LO_LPF_EN|LNASW|ADF4350_CE|ADF4350_PDBRF|RX_ATTN_MASK|DIS_POWER_RX|RX_DISABLE)
+
+// Power functions
+#define TX_POWER_UP (ADF4350_CE|TX_ENABLE)
+#define TX_POWER_DOWN (DIS_POWER_TX)
+
+#define RX_POWER_UP (ADF4350_CE)
+#define RX_POWER_DOWN (DIS_POWER_RX)
+
+// Antenna constants
+#define ANT_TX TRSW //the tx line is transmitting
+#define ANT_RX 0 //the tx line is receiving
+#define ANT_TXRX 0 //the rx line is on txrx
+#define ANT_RX2 LNASW //the rx line in on rx2
+#define ANT_XX LNASW //dont care how the antenna is set
+
+#include "adf4350_regs.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/types/sensors.hpp>
+#include <uhd/utils/assert_has.hpp>
+#include <uhd/utils/static.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <uhd/utils/warning.hpp>
+#include <uhd/usrp/dboard_base.hpp>
+#include <uhd/usrp/dboard_manager.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/thread.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
+
+/***********************************************************************
+ * The SBX dboard constants
+ **********************************************************************/
+static const bool sbx_debug = false;
+
+static const freq_range_t sbx_freq_range(68.75e6, 4.4e9);
+
+static const freq_range_t sbx_tx_lo_2dbm = list_of
+ (range_t(0.35e9, 0.37e9))
+;
+
+static const freq_range_t sbx_enable_tx_lo_filter = list_of
+ (range_t(0.4e9, 1.5e9))
+;
+
+static const freq_range_t sbx_enable_rx_lo_filter = list_of
+ (range_t(0.4e9, 1.5e9))
+;
+
+static const prop_names_t sbx_tx_antennas = list_of("TX/RX");
+
+static const prop_names_t sbx_rx_antennas = list_of("TX/RX")("RX2");
+
+static const uhd::dict<std::string, gain_range_t> sbx_tx_gain_ranges = map_list_of
+ ("PGA0", gain_range_t(0, 31.5, double(0.5)))
+;
+
+static const uhd::dict<std::string, gain_range_t> sbx_rx_gain_ranges = map_list_of
+ ("PGA0", gain_range_t(0, 31.5, double(0.5)))
+;
+
+/***********************************************************************
+ * The SBX dboard
+ **********************************************************************/
+class sbx_xcvr : public xcvr_dboard_base{
+public:
+ sbx_xcvr(ctor_args_t args);
+ ~sbx_xcvr(void);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ uhd::dict<std::string, double> _tx_gains, _rx_gains;
+ double _rx_lo_freq, _tx_lo_freq;
+ std::string _tx_ant, _rx_ant;
+
+ 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(double gain, const std::string &name);
+ void set_tx_gain(double gain, const std::string &name);
+
+ void update_atr(void);
+
+ /*!
+ * Set the LO frequency for the particular dboard unit.
+ * \param unit which unit rx or tx
+ * \param target_freq the desired frequency in Hz
+ * \return the actual frequency in Hz
+ */
+ double set_lo_freq(dboard_iface::unit_t unit, double target_freq);
+
+ /*!
+ * Get the lock detect status of the LO.
+ * \param unit which unit rx or tx
+ * \return true for locked
+ */
+ bool get_locked(dboard_iface::unit_t unit){
+ return (this->get_iface()->read_gpio(unit) & LOCKDET_MASK) != 0;
+ }
+
+ /*!
+ * Flash the LEDs
+ */
+ void flash_leds(void) {
+ //Remove LED gpios from ATR control temporarily and set to outputs
+ this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, TXIO_MASK);
+ this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, RXIO_MASK);
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, (TXIO_MASK|RX_LED_IO));
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO));
+
+ /*
+ //flash All LEDs
+ for (int i = 0; i < 3; i++) {
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, RX_LED_IO, RX_LED_IO);
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX, TX_LED_IO, TX_LED_IO);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, 0, RX_LED_IO);
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX, 0, TX_LED_IO);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+ }
+ */
+
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX, TX_LED_LD, TX_LED_IO);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX, TX_LED_TXRX|TX_LED_LD, TX_LED_IO);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, RX_LED_LD, RX_LED_IO);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, RX_LED_RX1RX2|RX_LED_LD, RX_LED_IO);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, RX_LED_LD, RX_LED_IO);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, 0, RX_LED_IO);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX, TX_LED_LD, TX_LED_IO);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX, 0, TX_LED_IO);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+
+ /*
+ //flash All LEDs
+ for (int i = 0; i < 3; i++) {
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, 0, RX_LED_IO);
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX, 0, TX_LED_IO);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, RX_LED_IO, RX_LED_IO);
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX, TX_LED_IO, TX_LED_IO);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+ }
+ */
+ //Put LED gpios back in ATR control and update atr
+ this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, (TXIO_MASK|TX_LED_IO));
+ this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO));
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, (TXIO_MASK|TX_LED_IO));
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO));
+ }
+
+};
+
+/***********************************************************************
+ * Register the SBX dboard (min freq, max freq, rx div2, tx div2)
+ **********************************************************************/
+static dboard_base::sptr make_sbx(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new sbx_xcvr(args));
+}
+
+UHD_STATIC_BLOCK(reg_sbx_dboards){
+ dboard_manager::register_dboard(0x0054, 0x0055, &make_sbx, "SBX");
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+sbx_xcvr::sbx_xcvr(ctor_args_t args) : xcvr_dboard_base(args){
+
+ //enable the clocks that we need
+ this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);
+ this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true);
+
+ //set the gpio directions and atr controls (identically)
+ this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, (TXIO_MASK|TX_LED_IO));
+ this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO));
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, (TXIO_MASK|TX_LED_IO));
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO));
+
+ //flash LEDs
+ flash_leds();
+
+ if (sbx_debug) std::cerr << boost::format(
+ "SBX GPIO Direction: RX: 0x%08x, TX: 0x%08x"
+ ) % RXIO_MASK % TXIO_MASK << std::endl;
+
+ //set some default values
+ set_rx_lo_freq((sbx_freq_range.start() + sbx_freq_range.stop())/2.0);
+ set_tx_lo_freq((sbx_freq_range.start() + sbx_freq_range.stop())/2.0);
+ set_rx_ant("RX2");
+
+ BOOST_FOREACH(const std::string &name, sbx_tx_gain_ranges.keys()){
+ set_tx_gain(sbx_tx_gain_ranges[name].start(), name);
+ }
+ BOOST_FOREACH(const std::string &name, sbx_rx_gain_ranges.keys()){
+ set_rx_gain(sbx_rx_gain_ranges[name].start(), name);
+ }
+}
+
+sbx_xcvr::~sbx_xcvr(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Gain Handling
+ **********************************************************************/
+static int rx_pga0_gain_to_iobits(double &gain){
+ //clip the input
+ gain = sbx_rx_gain_ranges["PGA0"].clip(gain);
+
+ //convert to attenuation and update iobits for atr
+ double attn = sbx_rx_gain_ranges["PGA0"].stop() - gain;
+
+ //calculate the RX attenuation
+ int attn_code = int(floor(attn*2));
+ int iobits = ((~attn_code) << RX_ATTN_SHIFT) & RX_ATTN_MASK;
+
+
+ if (sbx_debug) std::cerr << boost::format(
+ "SBX TX Attenuation: %f dB, Code: %d, IO Bits %x, Mask: %x"
+ ) % attn % attn_code % (iobits & RX_ATTN_MASK) % RX_ATTN_MASK << std::endl;
+
+ //the actual gain setting
+ gain = sbx_rx_gain_ranges["PGA0"].stop() - double(attn_code)/2;
+
+ return iobits;
+}
+
+static int tx_pga0_gain_to_iobits(double &gain){
+ //clip the input
+ gain = sbx_tx_gain_ranges["PGA0"].clip(gain);
+
+ //convert to attenuation and update iobits for atr
+ double attn = sbx_tx_gain_ranges["PGA0"].stop() - gain;
+
+ //calculate the TX attenuation
+ int attn_code = int(floor(attn*2));
+ int iobits = ((~attn_code) << TX_ATTN_SHIFT) & TX_ATTN_MASK;
+
+
+ if (sbx_debug) std::cerr << boost::format(
+ "SBX TX Attenuation: %f dB, Code: %d, IO Bits %x, Mask: %x"
+ ) % attn % attn_code % (iobits & TX_ATTN_MASK) % TX_ATTN_MASK << std::endl;
+
+ //the actual gain setting
+ gain = sbx_tx_gain_ranges["PGA0"].stop() - double(attn_code)/2;
+
+ return iobits;
+}
+
+void sbx_xcvr::set_tx_gain(double gain, const std::string &name){
+ assert_has(sbx_tx_gain_ranges.keys(), name, "sbx tx gain name");
+ if(name == "PGA0"){
+ tx_pga0_gain_to_iobits(gain);
+ _tx_gains[name] = gain;
+
+ //write the new gain to atr regs
+ update_atr();
+ }
+ else UHD_THROW_INVALID_CODE_PATH();
+}
+
+void sbx_xcvr::set_rx_gain(double gain, const std::string &name){
+ assert_has(sbx_rx_gain_ranges.keys(), name, "sbx rx gain name");
+ if(name == "PGA0"){
+ rx_pga0_gain_to_iobits(gain);
+ _rx_gains[name] = gain;
+
+ //write the new gain to atr regs
+ update_atr();
+ }
+ else UHD_THROW_INVALID_CODE_PATH();
+}
+
+/***********************************************************************
+ * Antenna Handling
+ **********************************************************************/
+void sbx_xcvr::update_atr(void){
+ //calculate atr pins
+ int rx_pga0_iobits = rx_pga0_gain_to_iobits(_rx_gains["PGA0"]);
+ int tx_pga0_iobits = tx_pga0_gain_to_iobits(_tx_gains["PGA0"]);
+ int rx_lo_lpf_en = (_rx_lo_freq == sbx_enable_rx_lo_filter.clip(_rx_lo_freq)) ? LO_LPF_EN : 0;
+ int tx_lo_lpf_en = (_tx_lo_freq == sbx_enable_tx_lo_filter.clip(_tx_lo_freq)) ? LO_LPF_EN : 0;
+ int rx_ld_led = get_locked(dboard_iface::UNIT_RX) ? 0 : RX_LED_LD;
+ int tx_ld_led = get_locked(dboard_iface::UNIT_TX) ? 0 : TX_LED_LD;
+ int rx_ant_led = _rx_ant == "TX/RX" ? RX_LED_RX1RX2 : 0;
+ int tx_ant_led = _rx_ant == "TX/RX" ? 0 : TX_LED_TXRX;
+
+ //setup the tx atr (this does not change with antenna)
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE,
+ tx_pga0_iobits | tx_lo_lpf_en | tx_ld_led | tx_ant_led | TX_POWER_UP | ANT_XX | TX_MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,
+ tx_pga0_iobits | tx_lo_lpf_en | tx_ld_led | tx_ant_led | TX_POWER_UP | ANT_TX | TX_MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX,
+ tx_pga0_iobits | tx_lo_lpf_en | tx_ld_led | tx_ant_led | TX_POWER_UP | ANT_TX | TX_MIXER_ENB);
+
+ //setup the rx atr (this does not change with antenna)
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE,
+ rx_pga0_iobits | rx_lo_lpf_en | rx_ld_led | rx_ant_led | RX_POWER_UP | ANT_XX | RX_MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,
+ rx_pga0_iobits | rx_lo_lpf_en | rx_ld_led | rx_ant_led | RX_POWER_UP | ANT_RX2 | RX_MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX,
+ rx_pga0_iobits | rx_lo_lpf_en | rx_ld_led | rx_ant_led | RX_POWER_UP | ANT_RX2 | RX_MIXER_ENB);
+
+ //set the atr regs that change with antenna setting
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY,
+ tx_pga0_iobits | tx_lo_lpf_en | tx_ld_led | tx_ant_led | TX_POWER_UP | TX_MIXER_DIS |
+ ((_rx_ant == "TX/RX")? ANT_RX : ANT_TX));
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,
+ rx_pga0_iobits | rx_lo_lpf_en | rx_ld_led | rx_ant_led | RX_POWER_UP | RX_MIXER_ENB |
+ ((_rx_ant == "TX/RX")? ANT_TXRX : ANT_RX2));
+
+ if (sbx_debug) std::cerr << boost::format(
+ "SBX RXONLY ATR REG: 0x%08x"
+ ) % (rx_pga0_iobits | RX_POWER_UP | RX_MIXER_ENB | ((_rx_ant == "TX/RX")? ANT_TXRX : ANT_RX2)) << std::endl;
+}
+
+void sbx_xcvr::set_rx_ant(const std::string &ant){
+ //validate input
+ assert_has(sbx_rx_antennas, ant, "sbx rx antenna name");
+
+ //shadow the setting
+ _rx_ant = ant;
+
+ //write the new antenna setting to atr regs
+ update_atr();
+}
+
+void sbx_xcvr::set_tx_ant(const std::string &ant){
+ assert_has(sbx_tx_antennas, ant, "sbx tx antenna name");
+ //only one antenna option, do nothing
+}
+
+/***********************************************************************
+ * Tuning
+ **********************************************************************/
+void sbx_xcvr::set_rx_lo_freq(double freq){
+ _rx_lo_freq = set_lo_freq(dboard_iface::UNIT_RX, freq);
+}
+
+void sbx_xcvr::set_tx_lo_freq(double freq){
+ _tx_lo_freq = set_lo_freq(dboard_iface::UNIT_TX, freq);
+}
+
+double sbx_xcvr::set_lo_freq(
+ dboard_iface::unit_t unit,
+ double target_freq
+){
+ if (sbx_debug) std::cerr << boost::format(
+ "SBX tune: target frequency %f Mhz"
+ ) % (target_freq/1e6) << std::endl;
+
+ //clip the input
+ target_freq = sbx_freq_range.clip(target_freq);
+
+ //map prescaler setting to mininmum integer divider (N) values (pg.18 prescaler)
+ static const uhd::dict<int, int> prescaler_to_min_int_div = map_list_of
+ (0,23) //adf4350_regs_t::PRESCALER_4_5
+ (1,75) //adf4350_regs_t::PRESCALER_8_9
+ ;
+
+ //map rf divider select output dividers to enums
+ static const uhd::dict<int, adf4350_regs_t::rf_divider_select_t> rfdivsel_to_enum = map_list_of
+ (1, adf4350_regs_t::RF_DIVIDER_SELECT_DIV1)
+ (2, adf4350_regs_t::RF_DIVIDER_SELECT_DIV2)
+ (4, adf4350_regs_t::RF_DIVIDER_SELECT_DIV4)
+ (8, adf4350_regs_t::RF_DIVIDER_SELECT_DIV8)
+ (16, adf4350_regs_t::RF_DIVIDER_SELECT_DIV16)
+ ;
+
+ double actual_freq, pfd_freq;
+ double ref_freq = this->get_iface()->get_clock_rate(unit);
+ int R=0, BS=0, N=0, FRAC=0, MOD=0;
+ int RFdiv = 1;
+ adf4350_regs_t::reference_divide_by_2_t T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED;
+ adf4350_regs_t::reference_doubler_t D = adf4350_regs_t::REFERENCE_DOUBLER_DISABLED;
+
+ //Reference doubler for 50% duty cycle
+ // if ref_freq < 12.5MHz enable regs.reference_divide_by_2
+ if(ref_freq <= 12.5e6) D = adf4350_regs_t::REFERENCE_DOUBLER_ENABLED;
+
+ //increase RF divider until acceptable VCO frequency
+ //start with target_freq*2 because mixer has divide by 2
+ double vco_freq = target_freq;
+ while (vco_freq < 2.2e9) {
+ vco_freq *= 2;
+ RFdiv *= 2;
+ }
+
+ //use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler)
+ adf4350_regs_t::prescaler_t prescaler = vco_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;
+
+ /*
+ * The goal here is to loop though possible R dividers,
+ * band select clock dividers, N (int) dividers, and FRAC
+ * (frac) dividers.
+ *
+ * Calculate the N and F dividers for each set of values.
+ * The loop exists when it meets all of the constraints.
+ * The resulting loop values are loaded into the registers.
+ *
+ * from pg.21
+ *
+ * f_pfd = f_ref*(1+D)/(R*(1+T))
+ * f_vco = (N + (FRAC/MOD))*f_pfd
+ * N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD
+ * f_rf = f_vco/RFdiv)
+ * f_actual = f_rf/2
+ */
+ for(R = 1; R <= 1023; R+=1){
+ //PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T)
+ pfd_freq = ref_freq*(1+D)/(R*(1+T));
+
+ //keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth)
+ if (pfd_freq > 25e6) continue;
+
+ //ignore fractional part of tuning
+ N = int(std::floor(vco_freq/pfd_freq));
+
+ //keep N > minimum int divider requirement
+ if (N < prescaler_to_min_int_div[prescaler]) continue;
+
+ for(BS=1; BS <= 255; BS+=1){
+ //keep the band select frequency at or below 100KHz
+ //constraint on band select clock
+ if (pfd_freq/BS > 100e3) continue;
+ goto done_loop;
+ }
+ } done_loop:
+
+ //Fractional-N calculation
+ MOD = 4095; //max fractional accuracy
+ FRAC = int((vco_freq/pfd_freq - N)*MOD);
+
+ //Reference divide-by-2 for 50% duty cycle
+ // if R even, move one divide by 2 to to regs.reference_divide_by_2
+ if(R % 2 == 0){
+ T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED;
+ R /= 2;
+ }
+
+ //actual frequency calculation
+ actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))/RFdiv);
+
+ if (sbx_debug) {
+ std::cerr << boost::format("SBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl;
+
+ std::cerr << boost::format("SBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d, LD=%d"
+ ) % R % BS % N % FRAC % MOD % T % D % RFdiv % get_locked(unit)<< std::endl
+ << boost::format("SBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f"
+ ) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl;
+ }
+
+ //load the register values
+ adf4350_regs_t regs;
+
+ if ((unit == dboard_iface::UNIT_TX) and (actual_freq == sbx_tx_lo_2dbm.clip(actual_freq)))
+ regs.output_power = adf4350_regs_t::OUTPUT_POWER_2DBM;
+ else
+ regs.output_power = adf4350_regs_t::OUTPUT_POWER_5DBM;
+
+ regs.frac_12_bit = FRAC;
+ regs.int_16_bit = N;
+ regs.mod_12_bit = MOD;
+ regs.prescaler = prescaler;
+ regs.r_counter_10_bit = R;
+ regs.reference_divide_by_2 = T;
+ regs.reference_doubler = D;
+ regs.band_select_clock_div = BS;
+ UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(RFdiv));
+ regs.rf_divider_select = rfdivsel_to_enum[RFdiv];
+
+ //write the registers
+ //correct power-up sequence to write registers (5, 4, 3, 2, 1, 0)
+ int addr;
+
+ for(addr=5; addr>=0; addr--){
+ if (sbx_debug) std::cerr << boost::format(
+ "SBX SPI Reg (0x%02x): 0x%08x"
+ ) % addr % regs.get_reg(addr) << std::endl;
+ this->get_iface()->write_spi(
+ unit, spi_config_t::EDGE_RISE,
+ regs.get_reg(addr), 32
+ );
+ }
+
+ //return the actual frequency
+ if (sbx_debug) std::cerr << boost::format(
+ "SBX tune: actual frequency %f Mhz"
+ ) % (actual_freq/1e6) << std::endl;
+ return actual_freq;
+}
+
+/***********************************************************************
+ * RX Get and Set
+ **********************************************************************/
+void sbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = get_rx_id().to_pp_string();
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ assert_has(_rx_gains.keys(), key.name, "sbx rx gain name");
+ val = _rx_gains[key.name];
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ assert_has(sbx_rx_gain_ranges.keys(), key.name, "sbx rx gain name");
+ val = sbx_rx_gain_ranges[key.name];
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(sbx_rx_gain_ranges.keys());
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _rx_lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = sbx_freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = _rx_ant;
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = sbx_rx_antennas;
+ return;
+
+ case SUBDEV_PROP_CONNECTION:
+ val = SUBDEV_CONN_COMPLEX_IQ;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_ENABLED:
+ val = true; //always enabled
+ return;
+
+ case SUBDEV_PROP_SENSOR:
+ UHD_ASSERT_THROW(key.name == "lo_locked");
+ val = sensor_value_t("LO", this->get_locked(dboard_iface::UNIT_RX), "locked", "unlocked");
+ return;
+
+ case SUBDEV_PROP_SENSOR_NAMES:
+ val = prop_names_t(1, "lo_locked");
+ return;
+
+ case SUBDEV_PROP_BANDWIDTH:
+ val = 2*20.0e6; //20MHz low-pass, we want complex double-sided
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void sbx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ this->set_rx_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ this->set_rx_gain(val.as<double>(), key.name);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ this->set_rx_ant(val.as<std::string>());
+ return;
+
+ case SUBDEV_PROP_ENABLED:
+ return; //always enabled
+
+ case SUBDEV_PROP_BANDWIDTH:
+ uhd::warning::post(
+ str(boost::format("SBX: No tunable bandwidth, fixed filtered to 40MHz"))
+ );
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
+
+/***********************************************************************
+ * TX Get and Set
+ **********************************************************************/
+void sbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = get_tx_id().to_pp_string();
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ assert_has(_tx_gains.keys(), key.name, "sbx tx gain name");
+ val = _tx_gains[key.name];
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ assert_has(sbx_tx_gain_ranges.keys(), key.name, "sbx tx gain name");
+ val = sbx_tx_gain_ranges[key.name];
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(sbx_tx_gain_ranges.keys());
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _tx_lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = sbx_freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("TX/RX");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = sbx_tx_antennas;
+ return;
+
+ case SUBDEV_PROP_CONNECTION:
+ val = SUBDEV_CONN_COMPLEX_QI;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_ENABLED:
+ val = true; //always enabled
+ return;
+
+ case SUBDEV_PROP_SENSOR:
+ UHD_ASSERT_THROW(key.name == "lo_locked");
+ val = sensor_value_t("LO", this->get_locked(dboard_iface::UNIT_TX), "locked", "unlocked");
+ return;
+
+ case SUBDEV_PROP_SENSOR_NAMES:
+ val = prop_names_t(1, "lo_locked");
+ return;
+
+ case SUBDEV_PROP_BANDWIDTH:
+ val = 2*20.0e6; //20MHz low-pass, we want complex double-sided
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void sbx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ this->set_tx_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ this->set_tx_gain(val.as<double>(), key.name);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ this->set_tx_ant(val.as<std::string>());
+ return;
+
+ case SUBDEV_PROP_ENABLED:
+ return; //always enabled
+
+ case SUBDEV_PROP_BANDWIDTH:
+ uhd::warning::post(
+ str(boost::format("SBX: No tunable bandwidth, fixed filtered to 40MHz"))
+ );
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx_common.cpp
index 2e9a1edc8..eb239c305 100644
--- a/host/lib/usrp/dboard/db_wbx.cpp
+++ b/host/lib/usrp/dboard/db_wbx_common.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// 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
@@ -16,7 +16,6 @@
//
// Common IO Pins
-#define ANTSW_IO ((1 << 5)|(1 << 15)) // on UNIT_TX, 0 = TX, 1 = RX, on UNIT_RX 0 = main ant, 1 = RX2
#define ADF4350_CE (1 << 3)
#define ADF4350_PDBRF (1 << 2)
#define ADF4350_MUXOUT (1 << 1) // INPUT!!!
@@ -43,38 +42,23 @@
#define RX_MIXER_ENB (RXBB_PDB|ADF4350_PDBRF)
#define RX_MIXER_DIS 0
-// Pin functions
-#define TX_POWER_IO (TX_PUP_5V|TX_PUP_3V) // high enables power supply
-#define TXIO_MASK (TX_POWER_IO|ANTSW_IO|ADF4350_CE|ADF4350_PDBRF|TXMOD_EN)
-
-#define RX_POWER_IO (RX_PUP_5V|RX_PUP_3V) // high enables power supply
-#define RXIO_MASK (RX_POWER_IO|ANTSW_IO|ADF4350_CE|ADF4350_PDBRF|RXBB_PDB|RX_ATTN_MASK)
-
// Power functions
-#define TX_POWER_UP (TX_POWER_IO|ADF4350_CE)
+#define TX_POWER_UP (TX_PUP_5V|TX_PUP_3V|ADF4350_CE) // high enables power supply
#define TX_POWER_DOWN 0
-#define RX_POWER_UP (RX_POWER_IO|ADF4350_CE)
+#define RX_POWER_UP (RX_PUP_5V|RX_PUP_3V|ADF4350_CE) // high enables power supply
#define RX_POWER_DOWN 0
-// Antenna constants
-#define ANT_TX 0 //the tx line is transmitting
-#define ANT_RX ANTSW_IO //the tx line is receiving
-#define ANT_TXRX 0 //the rx line is on txrx
-#define ANT_RX2 ANTSW_IO //the rx line in on rx2
-#define ANT_XX 0 //dont care how the antenna is set
-
+#include "db_wbx_common.hpp"
#include "adf4350_regs.hpp"
#include <uhd/types/dict.hpp>
#include <uhd/usrp/subdev_props.hpp>
#include <uhd/types/ranges.hpp>
#include <uhd/types/sensors.hpp>
#include <uhd/utils/assert_has.hpp>
-#include <uhd/utils/static.hpp>
#include <uhd/utils/algorithm.hpp>
#include <uhd/utils/warning.hpp>
#include <uhd/usrp/dboard_base.hpp>
-#include <uhd/usrp/dboard_manager.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/format.hpp>
#include <boost/math/special_functions/round.hpp>
@@ -84,16 +68,10 @@ using namespace uhd::usrp;
using namespace boost::assign;
/***********************************************************************
- * The WBX dboard constants
+ * The WBX Common dboard constants
**********************************************************************/
static const bool wbx_debug = false;
-static const freq_range_t wbx_freq_range(68.75e6, 2.2e9);
-
-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, 0.05))
;
@@ -103,105 +81,69 @@ static const uhd::dict<std::string, gain_range_t> wbx_rx_gain_ranges = map_list_
;
/***********************************************************************
- * The WBX dboard
- **********************************************************************/
-class wbx_xcvr : public xcvr_dboard_base{
-public:
- wbx_xcvr(ctor_args_t args);
- ~wbx_xcvr(void);
-
- void rx_get(const wax::obj &key, wax::obj &val);
- void rx_set(const wax::obj &key, const wax::obj &val);
-
- void tx_get(const wax::obj &key, wax::obj &val);
- void tx_set(const wax::obj &key, const wax::obj &val);
-
-private:
- uhd::dict<std::string, double> _tx_gains, _rx_gains;
- double _rx_lo_freq, _tx_lo_freq;
- std::string _tx_ant, _rx_ant;
-
- 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(double gain, const std::string &name);
- void set_tx_gain(double gain, const std::string &name);
-
- void update_atr(void);
-
- /*!
- * Set the LO frequency for the particular dboard unit.
- * \param unit which unit rx or tx
- * \param target_freq the desired frequency in Hz
- * \return the actual frequency in Hz
- */
- double set_lo_freq(dboard_iface::unit_t unit, double target_freq);
-
- /*!
- * Get the lock detect status of the LO.
- * \param unit which unit rx or tx
- * \return true for locked
- */
- bool get_locked(dboard_iface::unit_t unit){
- return (this->get_iface()->read_gpio(unit) & LOCKDET_MASK) != 0;
- }
-};
-
-/***********************************************************************
- * Register the WBX dboard (min freq, max freq, rx div2, tx div2)
- **********************************************************************/
-static dboard_base::sptr make_wbx(dboard_base::ctor_args_t args){
- return dboard_base::sptr(new wbx_xcvr(args));
-}
-
-UHD_STATIC_BLOCK(reg_wbx_dboards){
- dboard_manager::register_dboard(0x0053, 0x0052, &make_wbx, "WBX");
-}
-
-/***********************************************************************
- * Structors
+ * WBX Common Implementation
**********************************************************************/
-wbx_xcvr::wbx_xcvr(ctor_args_t args) : xcvr_dboard_base(args){
+wbx_base::wbx_base(ctor_args_t args) : xcvr_dboard_base(args){
//enable the clocks that we need
this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);
this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true);
- //set the gpio directions and atr controls (identically)
- this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, TXIO_MASK);
- this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, RXIO_MASK);
- this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TXIO_MASK);
- this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RXIO_MASK);
- if (wbx_debug) std::cerr << boost::format(
- "WBX GPIO Direction: RX: 0x%08x, TX: 0x%08x"
- ) % RXIO_MASK % TXIO_MASK << std::endl;
+ //set the gpio directions and atr controls
+ this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, TXMOD_EN|ADF4350_PDBRF);
+ this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, RXBB_PDB|ADF4350_PDBRF);
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TX_PUP_5V|TX_PUP_3V|ADF4350_CE|TXMOD_EN|ADF4350_PDBRF);
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RX_PUP_5V|RX_PUP_3V|ADF4350_CE|RXBB_PDB|ADF4350_PDBRF|RX_ATTN_MASK);
- //set some default values
- set_rx_lo_freq((wbx_freq_range.start() + wbx_freq_range.stop())/2.0);
- set_tx_lo_freq((wbx_freq_range.start() + wbx_freq_range.stop())/2.0);
- set_rx_ant("RX2");
+ //setup ATR for the mixer enables
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, TX_MIXER_DIS, TX_MIXER_DIS | TX_MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, TX_MIXER_DIS, TX_MIXER_DIS | TX_MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, TX_MIXER_ENB, TX_MIXER_DIS | TX_MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, TX_MIXER_ENB, TX_MIXER_DIS | TX_MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, RX_MIXER_DIS, RX_MIXER_DIS | RX_MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, RX_MIXER_DIS, RX_MIXER_DIS | RX_MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB);
+
+ //set some default values
BOOST_FOREACH(const std::string &name, wbx_tx_gain_ranges.keys()){
set_tx_gain(wbx_tx_gain_ranges[name].start(), name);
}
BOOST_FOREACH(const std::string &name, wbx_rx_gain_ranges.keys()){
set_rx_gain(wbx_rx_gain_ranges[name].start(), name);
}
+ set_rx_enabled(false);
+ set_tx_enabled(false);
}
-wbx_xcvr::~wbx_xcvr(void){
+wbx_base::~wbx_base(void){
/* NOP */
}
/***********************************************************************
+ * Enables
+ **********************************************************************/
+void wbx_base::set_rx_enabled(bool enb){
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX,
+ (enb)? RX_POWER_UP : RX_POWER_DOWN, RX_POWER_UP | RX_POWER_DOWN
+ );
+}
+
+void wbx_base::set_tx_enabled(bool enb){
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX,
+ (enb)? TX_POWER_UP : TX_POWER_DOWN, TX_POWER_UP | TX_POWER_DOWN
+ );
+}
+
+/***********************************************************************
* Gain Handling
**********************************************************************/
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
+ //convert to attenuation
double attn = wbx_rx_gain_ranges["PGA0"].stop() - gain;
//calculate the attenuation
@@ -239,7 +181,7 @@ static double tx_pga0_gain_to_dac_volts(double &gain){
return dac_volts;
}
-void wbx_xcvr::set_tx_gain(double gain, const std::string &name){
+void wbx_base::set_tx_gain(double gain, const std::string &name){
assert_has(wbx_tx_gain_ranges.keys(), name, "wbx tx gain name");
if(name == "PGA0"){
double dac_volts = tx_pga0_gain_to_dac_volts(gain);
@@ -251,75 +193,22 @@ void wbx_xcvr::set_tx_gain(double gain, const std::string &name){
else UHD_THROW_INVALID_CODE_PATH();
}
-void wbx_xcvr::set_rx_gain(double gain, const std::string &name){
+void wbx_base::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);
+ boost::uint16_t io_bits = rx_pga0_gain_to_iobits(gain);
_rx_gains[name] = gain;
- //write the new gain to atr regs
- update_atr();
+ //write the new gain to rx gpio outputs
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, io_bits, RX_ATTN_MASK);
}
else UHD_THROW_INVALID_CODE_PATH();
}
/***********************************************************************
- * Antenna Handling
- **********************************************************************/
-void wbx_xcvr::update_atr(void){
- //calculate atr pins
- int pga0_iobits = rx_pga0_gain_to_iobits(_rx_gains["PGA0"]);
-
- //setup the tx atr (this does not change with antenna)
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, TX_POWER_UP | ANT_XX | TX_MIXER_DIS);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, TX_POWER_UP | ANT_RX | TX_MIXER_DIS);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, TX_POWER_UP | ANT_TX | TX_MIXER_ENB);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, TX_POWER_UP | ANT_TX | TX_MIXER_ENB);
-
- //setup the rx atr (this does not change with antenna)
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE,
- pga0_iobits | RX_POWER_UP | ANT_XX | RX_MIXER_DIS);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,
- pga0_iobits | RX_POWER_UP | ANT_XX | RX_MIXER_DIS);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX,
- pga0_iobits | RX_POWER_UP | ANT_RX2| RX_MIXER_ENB);
-
- //set the rx atr regs that change with antenna setting
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,
- pga0_iobits | RX_POWER_UP | RX_MIXER_ENB | ((_rx_ant == "TX/RX")? ANT_TXRX : ANT_RX2));
- if (wbx_debug) std::cerr << boost::format(
- "WBX RXONLY ATR REG: 0x%08x"
- ) % (pga0_iobits | RX_POWER_UP | RX_MIXER_ENB | ((_rx_ant == "TX/RX")? ANT_TXRX : ANT_RX2)) << std::endl;
-}
-
-void wbx_xcvr::set_rx_ant(const std::string &ant){
- //validate input
- assert_has(wbx_rx_antennas, ant, "wbx rx antenna name");
-
- //shadow the setting
- _rx_ant = ant;
-
- //write the new antenna setting to atr regs
- update_atr();
-}
-
-void wbx_xcvr::set_tx_ant(const std::string &ant){
- assert_has(wbx_tx_antennas, ant, "wbx tx antenna name");
- //only one antenna option, do nothing
-}
-
-/***********************************************************************
* Tuning
**********************************************************************/
-void wbx_xcvr::set_rx_lo_freq(double freq){
- _rx_lo_freq = set_lo_freq(dboard_iface::UNIT_RX, freq);
-}
-
-void wbx_xcvr::set_tx_lo_freq(double freq){
- _tx_lo_freq = set_lo_freq(dboard_iface::UNIT_TX, freq);
-}
-
-double wbx_xcvr::set_lo_freq(
+double wbx_base::set_lo_freq(
dboard_iface::unit_t unit,
double target_freq
){
@@ -327,9 +216,6 @@ double wbx_xcvr::set_lo_freq(
"WBX tune: target frequency %f Mhz"
) % (target_freq/1e6) << std::endl;
- //clip the input
- target_freq = wbx_freq_range.clip(target_freq);
-
//map prescaler setting to mininmum integer divider (N) values (pg.18 prescaler)
static const uhd::dict<int, int> prescaler_to_min_int_div = map_list_of
(0,23) //adf4350_regs_t::PRESCALER_4_5
@@ -443,6 +329,35 @@ double wbx_xcvr::set_lo_freq(
UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(RFdiv));
regs.rf_divider_select = rfdivsel_to_enum[RFdiv];
+ if (unit == dboard_iface::UNIT_RX) {
+ freq_range_t rx_lo_5dbm = list_of
+ (range_t(0.05e9, 1.4e9))
+ ;
+
+ freq_range_t rx_lo_2dbm = list_of
+ (range_t(1.4e9, 2.2e9))
+ ;
+
+ if (actual_freq == rx_lo_5dbm.clip(actual_freq)) regs.output_power = adf4350_regs_t::OUTPUT_POWER_5DBM;
+
+ if (actual_freq == rx_lo_2dbm.clip(actual_freq)) regs.output_power = adf4350_regs_t::OUTPUT_POWER_2DBM;
+
+ } else if (unit == dboard_iface::UNIT_TX) {
+ freq_range_t tx_lo_5dbm = list_of
+ (range_t(0.05e9, 1.7e9))
+ (range_t(1.9e9, 2.2e9))
+ ;
+
+ freq_range_t tx_lo_m1dbm = list_of
+ (range_t(1.7e9, 1.9e9))
+ ;
+
+ if (actual_freq == tx_lo_5dbm.clip(actual_freq)) regs.output_power = adf4350_regs_t::OUTPUT_POWER_5DBM;
+
+ if (actual_freq == tx_lo_m1dbm.clip(actual_freq)) regs.output_power = adf4350_regs_t::OUTPUT_POWER_M1DBM;
+
+ }
+
//write the registers
//correct power-up sequence to write registers (5, 4, 3, 2, 1, 0)
int addr;
@@ -464,10 +379,14 @@ double wbx_xcvr::set_lo_freq(
return actual_freq;
}
+bool wbx_base::get_locked(dboard_iface::unit_t unit){
+ return (this->get_iface()->read_gpio(unit) & LOCKDET_MASK) != 0;
+}
+
/***********************************************************************
* RX Get and Set
**********************************************************************/
-void wbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
+void wbx_base::rx_get(const wax::obj &key_, wax::obj &val){
named_prop_t key = named_prop_t::extract(key_);
//handle the get request conditioned on the key
@@ -495,19 +414,19 @@ void wbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_FREQ:
- val = _rx_lo_freq;
+ val = 0.0;
return;
case SUBDEV_PROP_FREQ_RANGE:
- val = wbx_freq_range;
+ val = freq_range_t(0.0, 0.0, 0.0);;
return;
case SUBDEV_PROP_ANTENNA:
- val = _rx_ant;
+ val = std::string("");
return;
case SUBDEV_PROP_ANTENNA_NAMES:
- val = wbx_rx_antennas;
+ val = prop_names_t(1, "");
return;
case SUBDEV_PROP_CONNECTION:
@@ -515,7 +434,7 @@ void wbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_ENABLED:
- val = true; //always enabled
+ val = _rx_enabled;
return;
case SUBDEV_PROP_USE_LO_OFFSET:
@@ -539,26 +458,20 @@ void wbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
}
}
-void wbx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
+void wbx_base::rx_set(const wax::obj &key_, const wax::obj &val){
named_prop_t key = named_prop_t::extract(key_);
//handle the get request conditioned on the key
switch(key.as<subdev_prop_t>()){
- case SUBDEV_PROP_FREQ:
- this->set_rx_lo_freq(val.as<double>());
- return;
-
case SUBDEV_PROP_GAIN:
this->set_rx_gain(val.as<double>(), key.name);
return;
- case SUBDEV_PROP_ANTENNA:
- this->set_rx_ant(val.as<std::string>());
- return;
-
case SUBDEV_PROP_ENABLED:
- return; //always enabled
+ _rx_enabled = val.as<bool>();
+ this->set_rx_enabled(_rx_enabled);
+ return;
case SUBDEV_PROP_BANDWIDTH:
uhd::warning::post(
@@ -573,7 +486,7 @@ void wbx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
/***********************************************************************
* TX Get and Set
**********************************************************************/
-void wbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
+void wbx_base::tx_get(const wax::obj &key_, wax::obj &val){
named_prop_t key = named_prop_t::extract(key_);
//handle the get request conditioned on the key
@@ -601,19 +514,19 @@ void wbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_FREQ:
- val = _tx_lo_freq;
+ val = 0.0;
return;
case SUBDEV_PROP_FREQ_RANGE:
- val = wbx_freq_range;
+ val = freq_range_t(0.0, 0.0, 0.0);
return;
case SUBDEV_PROP_ANTENNA:
- val = std::string("TX/RX");
+ val = std::string("");
return;
case SUBDEV_PROP_ANTENNA_NAMES:
- val = wbx_tx_antennas;
+ val = prop_names_t(1, "");
return;
case SUBDEV_PROP_CONNECTION:
@@ -621,7 +534,7 @@ void wbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_ENABLED:
- val = true; //always enabled
+ val = _tx_enabled;
return;
case SUBDEV_PROP_USE_LO_OFFSET:
@@ -645,26 +558,20 @@ void wbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
}
}
-void wbx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){
+void wbx_base::tx_set(const wax::obj &key_, const wax::obj &val){
named_prop_t key = named_prop_t::extract(key_);
//handle the get request conditioned on the key
switch(key.as<subdev_prop_t>()){
- case SUBDEV_PROP_FREQ:
- this->set_tx_lo_freq(val.as<double>());
- return;
-
case SUBDEV_PROP_GAIN:
this->set_tx_gain(val.as<double>(), key.name);
return;
- case SUBDEV_PROP_ANTENNA:
- this->set_tx_ant(val.as<std::string>());
- return;
-
case SUBDEV_PROP_ENABLED:
- return; //always enabled
+ _tx_enabled = val.as<bool>();
+ this->set_tx_enabled(_tx_enabled);
+ return;
case SUBDEV_PROP_BANDWIDTH:
uhd::warning::post(
diff --git a/host/lib/usrp/dboard/db_wbx_common.hpp b/host/lib/usrp/dboard/db_wbx_common.hpp
new file mode 100644
index 000000000..07e84a565
--- /dev/null
+++ b/host/lib/usrp/dboard/db_wbx_common.hpp
@@ -0,0 +1,72 @@
+//
+// 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_DBOARD_DB_WBX_COMMON_HPP
+#define INCLUDED_LIBUHD_USRP_DBOARD_DB_WBX_COMMON_HPP
+
+#include "adf4350_regs.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/utils/props.hpp>
+#include <uhd/usrp/dboard_base.hpp>
+
+namespace uhd{ namespace usrp{
+
+/***********************************************************************
+ * The WBX dboard base class
+ **********************************************************************/
+class wbx_base : public xcvr_dboard_base{
+public:
+ wbx_base(ctor_args_t args);
+ virtual ~wbx_base(void);
+
+protected:
+ virtual void set_rx_gain(double gain, const std::string &name);
+ virtual void set_tx_gain(double gain, const std::string &name);
+
+ virtual void set_rx_enabled(bool enb);
+ virtual void set_tx_enabled(bool enb);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+
+ /*!
+ * Set the LO frequency for the particular dboard unit.
+ * \param unit which unit rx or tx
+ * \param target_freq the desired frequency in Hz
+ * \return the actual frequency in Hz
+ */
+ virtual double set_lo_freq(dboard_iface::unit_t unit, double target_freq);
+
+ /*!
+ * Get the lock detect status of the LO.
+ * \param unit which unit rx or tx
+ * \return true for locked
+ */
+ virtual bool get_locked(dboard_iface::unit_t unit);
+
+private:
+ uhd::dict<std::string, double> _tx_gains, _rx_gains;
+ bool _rx_enabled, _tx_enabled;
+};
+
+}} //namespace uhd::usrp
+
+#endif /* INCLUDED_LIBUHD_USRP_DBOARD_DB_WBX_COMMON_HPP */
diff --git a/host/lib/usrp/dboard/db_wbx_simple.cpp b/host/lib/usrp/dboard/db_wbx_simple.cpp
new file mode 100644
index 000000000..390b4474b
--- /dev/null
+++ b/host/lib/usrp/dboard/db_wbx_simple.cpp
@@ -0,0 +1,251 @@
+//
+// 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/>.
+//
+
+// Antenna constants
+#define ANTSW_IO ((1 << 5)|(1 << 15)) // on UNIT_TX, 0 = TX, 1 = RX, on UNIT_RX 0 = main ant, 1 = RX2
+#define ANT_TX 0 //the tx line is transmitting
+#define ANT_RX ANTSW_IO //the tx line is receiving
+#define ANT_TXRX 0 //the rx line is on txrx
+#define ANT_RX2 ANTSW_IO //the rx line in on rx2
+#define ANT_XX 0 //dont care how the antenna is set
+
+#include "db_wbx_common.hpp"
+#include <uhd/utils/static.hpp>
+#include <uhd/utils/assert_has.hpp>
+#include <uhd/usrp/dboard_manager.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <boost/assign/list_of.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
+
+/***********************************************************************
+ * The WBX Simple dboard constants
+ **********************************************************************/
+static const bool wbx_debug = false;
+
+static const freq_range_t wbx_freq_range(68.75e6, 2.2e9);
+
+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");
+
+/***********************************************************************
+ * The WBX simple implementation
+ **********************************************************************/
+class wbx_simple : public wbx_base{
+public:
+ wbx_simple(ctor_args_t args);
+ ~wbx_simple(void);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ void set_rx_lo_freq(double freq);
+ void set_tx_lo_freq(double freq);
+ double _rx_lo_freq, _tx_lo_freq;
+
+ void set_rx_ant(const std::string &ant);
+ void set_tx_ant(const std::string &ant);
+ std::string _rx_ant;
+};
+
+/***********************************************************************
+ * Register the WBX simple implementation
+ **********************************************************************/
+static dboard_base::sptr make_wbx_simple(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new wbx_simple(args));
+}
+
+UHD_STATIC_BLOCK(reg_wbx_simple_dboards){
+ dboard_manager::register_dboard(0x0053, 0x0052, &make_wbx_simple, "WBX");
+ dboard_manager::register_dboard(0x0053, 0x004f, &make_wbx_simple, "WBX + Simple GDB");
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+wbx_simple::wbx_simple(ctor_args_t args) : wbx_base(args){
+
+ //set the gpio directions and atr controls (antenna switches all under ATR)
+ this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, ANTSW_IO, ANTSW_IO);
+ this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, ANTSW_IO, ANTSW_IO);
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, ANTSW_IO, ANTSW_IO);
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, ANTSW_IO, ANTSW_IO);
+
+ //setup ATR for the antenna switches (constant)
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, ANT_XX, ANTSW_IO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, ANT_RX, ANTSW_IO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, ANT_TX, ANTSW_IO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, ANT_TX, ANTSW_IO);
+
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, ANT_XX, ANTSW_IO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, ANT_XX, ANTSW_IO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, ANT_RX2, ANTSW_IO);
+
+ //set some default values
+ set_rx_lo_freq((wbx_freq_range.start() + wbx_freq_range.stop())/2.0);
+ set_tx_lo_freq((wbx_freq_range.start() + wbx_freq_range.stop())/2.0);
+ set_rx_ant("RX2");
+}
+
+wbx_simple::~wbx_simple(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Antennas
+ **********************************************************************/
+void wbx_simple::set_rx_ant(const std::string &ant){
+ //validate input
+ assert_has(wbx_rx_antennas, ant, "wbx rx antenna name");
+
+ //shadow the setting
+ _rx_ant = ant;
+
+ //write the new antenna setting to atr regs
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, ((_rx_ant == "TX/RX")? ANT_TXRX : ANT_RX2), ANTSW_IO);
+}
+
+void wbx_simple::set_tx_ant(const std::string &ant){
+ assert_has(wbx_tx_antennas, ant, "wbx tx antenna name");
+ //only one antenna option, do nothing
+}
+
+/***********************************************************************
+ * Tuning
+ **********************************************************************/
+void wbx_simple::set_rx_lo_freq(double freq){
+ _rx_lo_freq = set_lo_freq(dboard_iface::UNIT_RX, wbx_freq_range.clip(freq));
+}
+
+void wbx_simple::set_tx_lo_freq(double freq){
+ _tx_lo_freq = set_lo_freq(dboard_iface::UNIT_TX, wbx_freq_range.clip(freq));
+}
+
+/***********************************************************************
+ * RX Get and Set
+ **********************************************************************/
+void wbx_simple::rx_get(const wax::obj &key_, wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = std::string("WBX RX + Simple GDB");
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _rx_lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = wbx_freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = _rx_ant;
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = wbx_rx_antennas;
+ return;
+
+ default:
+ //call into the base class for other properties
+ wbx_base::rx_get(key_, val);
+ }
+}
+
+void wbx_simple::rx_set(const wax::obj &key_, const wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ this->set_rx_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ this->set_rx_ant(val.as<std::string>());
+ return;
+
+ default:
+ //call into the base class for other properties
+ wbx_base::rx_set(key_, val);
+ }
+}
+
+/***********************************************************************
+ * TX Get and Set
+ **********************************************************************/
+void wbx_simple::tx_get(const wax::obj &key_, wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = std::string("WBX TX + Simple GDB");
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _tx_lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = wbx_freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("TX/RX");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = wbx_tx_antennas;
+ return;
+
+ default:
+ //call into the base class for other properties
+ wbx_base::tx_get(key_, val);
+ }
+}
+
+void wbx_simple::tx_set(const wax::obj &key_, const wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ this->set_tx_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ this->set_tx_ant(val.as<std::string>());
+ return;
+
+ default:
+ //call into the base class for other properties
+ wbx_base::tx_set(key_, val);
+ }
+}
diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp
index 70b0bbabd..45f600569 100644
--- a/host/lib/usrp/dboard/db_xcvr2450.cpp
+++ b/host/lib/usrp/dboard/db_xcvr2450.cpp
@@ -153,7 +153,7 @@ private:
*/
double get_rssi(void){
//*FIXME* RSSI depends on LNA Gain Setting (datasheet pg 16 top middle chart)
- double max_power;
+ double max_power = 0.0;
switch(_max2829_regs.rx_lna_gain){
case 0:
case 1: max_power = 0; break;
diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp
index 9055905b1..2e8b39311 100644
--- a/host/lib/usrp/dboard_manager.cpp
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -33,33 +33,87 @@ using namespace uhd;
using namespace uhd::usrp;
/***********************************************************************
+ * dboard key class to use for look-up
+ **********************************************************************/
+class dboard_key_t{
+public:
+ dboard_key_t(const dboard_id_t &id = dboard_id_t::none()):
+ _rx_id(id), _tx_id(id), _xcvr(false){}
+
+ dboard_key_t(const dboard_id_t &rx_id, const dboard_id_t &tx_id):
+ _rx_id(rx_id), _tx_id(tx_id), _xcvr(true){}
+
+ dboard_id_t xx_id(void) const{
+ UHD_ASSERT_THROW(not this->is_xcvr());
+ return this->_rx_id;
+ }
+
+ dboard_id_t rx_id(void) const{
+ UHD_ASSERT_THROW(this->is_xcvr());
+ return this->_rx_id;
+ }
+
+ dboard_id_t tx_id(void) const{
+ UHD_ASSERT_THROW(this->is_xcvr());
+ return this->_tx_id;
+ }
+
+ bool is_xcvr(void) const{
+ return this->_xcvr;
+ }
+
+private:
+ dboard_id_t _rx_id, _tx_id;
+ bool _xcvr;
+};
+
+bool operator==(const dboard_key_t &lhs, const dboard_key_t &rhs){
+ if (lhs.is_xcvr() and rhs.is_xcvr())
+ return lhs.rx_id() == rhs.rx_id() and lhs.tx_id() == rhs.tx_id();
+ if (not lhs.is_xcvr() and not rhs.is_xcvr())
+ return lhs.xx_id() == rhs.xx_id();
+ return false;
+}
+
+/***********************************************************************
* storage and registering for dboards
**********************************************************************/
//dboard registry tuple: dboard constructor, canonical name, subdev names
typedef boost::tuple<dboard_manager::dboard_ctor_t, std::string, prop_names_t> args_t;
//map a dboard id to a dboard constructor
-typedef uhd::dict<dboard_id_t, args_t> id_to_args_map_t;
+typedef uhd::dict<dboard_key_t, args_t> id_to_args_map_t;
UHD_SINGLETON_FCN(id_to_args_map_t, get_id_to_args_map)
-void dboard_manager::register_dboard(
- const dboard_id_t &dboard_id,
- dboard_ctor_t dboard_ctor,
+static void register_dboard_key(
+ const dboard_key_t &dboard_key,
+ dboard_manager::dboard_ctor_t dboard_ctor,
const std::string &name,
const prop_names_t &subdev_names
){
//std::cout << "registering: " << name << std::endl;
- if (get_id_to_args_map().has_key(dboard_id)){
- throw uhd::key_error(str(boost::format(
+ if (get_id_to_args_map().has_key(dboard_key)){
+
+ if (dboard_key.is_xcvr()) throw uhd::key_error(str(boost::format(
+ "The dboard id pair [%s, %s] is already registered to %s."
+ ) % dboard_key.rx_id().to_string() % dboard_key.tx_id().to_string() % get_id_to_args_map()[dboard_key].get<1>()));
+
+ else throw uhd::key_error(str(boost::format(
"The dboard id %s is already registered to %s."
- ) % dboard_id.to_string() % dboard_id.to_pp_string()));
+ ) % dboard_key.xx_id().to_string() % get_id_to_args_map()[dboard_key].get<1>()));
+
}
- get_id_to_args_map()[dboard_id] = args_t(dboard_ctor, name, subdev_names);
+ get_id_to_args_map()[dboard_key] = args_t(dboard_ctor, name, subdev_names);
}
-//map an xcvr dboard id to its partner dboard id
-typedef uhd::dict<dboard_id_t, dboard_id_t> xcvr_id_to_id_map_t;
-UHD_SINGLETON_FCN(xcvr_id_to_id_map_t, get_xcvr_id_to_id_map)
+void dboard_manager::register_dboard(
+ const dboard_id_t &dboard_id,
+ dboard_ctor_t dboard_ctor,
+ const std::string &name,
+ const prop_names_t &subdev_names
+){
+ register_dboard_key(dboard_key_t(dboard_id), dboard_ctor, name, subdev_names);
+}
void dboard_manager::register_dboard(
const dboard_id_t &rx_dboard_id,
@@ -68,18 +122,21 @@ void dboard_manager::register_dboard(
const std::string &name,
const prop_names_t &subdev_names
){
- //regular registration for ids
- register_dboard(rx_dboard_id, dboard_ctor, name, subdev_names);
- register_dboard(tx_dboard_id, dboard_ctor, name, subdev_names);
-
- //register xcvr mapping for ids
- get_xcvr_id_to_id_map()[rx_dboard_id] = tx_dboard_id;
- get_xcvr_id_to_id_map()[tx_dboard_id] = rx_dboard_id;
+ register_dboard_key(dboard_key_t(rx_dboard_id, tx_dboard_id), dboard_ctor, name, subdev_names);
}
std::string dboard_id_t::to_cname(void) const{
- if (not get_id_to_args_map().has_key(*this)) return "Unknown";
- return get_id_to_args_map()[*this].get<1>();
+ std::string cname;
+ BOOST_FOREACH(const dboard_key_t &key, get_id_to_args_map().keys()){
+ if (
+ (not key.is_xcvr() and *this == key.xx_id()) or
+ (key.is_xcvr() and (*this == key.rx_id() or *this == key.tx_id()))
+ ){
+ if (not cname.empty()) cname += ", ";
+ cname += get_id_to_args_map()[key].get<1>();
+ }
+ }
+ return (cname.empty())? "Unknown" : cname;
}
std::string dboard_id_t::to_pp_string(void) const{
@@ -172,34 +229,6 @@ dboard_manager::sptr dboard_manager::make(
/***********************************************************************
* implementation class methods
**********************************************************************/
-static args_t get_dboard_args(
- dboard_iface::unit_t unit,
- dboard_id_t dboard_id,
- bool force_to_unknown = false
-){
- //special case, the none id was provided, use the following ids
- if (dboard_id == dboard_id_t::none() or force_to_unknown){
- UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff1));
- UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff0));
- switch(unit){
- case dboard_iface::UNIT_RX: return get_dboard_args(unit, 0xfff1);
- case dboard_iface::UNIT_TX: return get_dboard_args(unit, 0xfff0);
- default: UHD_THROW_INVALID_CODE_PATH();
- }
- }
-
- //verify that there is a registered constructor for this id
- if (not get_id_to_args_map().has_key(dboard_id)){
- uhd::warning::post(str(boost::format(
- "Unknown dboard ID: %s.\n"
- ) % dboard_id.to_pp_string()));
- return get_dboard_args(unit, dboard_id, true);
- }
-
- //return the dboard args for this id
- return get_id_to_args_map()[dboard_id];
-}
-
dboard_manager_impl::dboard_manager_impl(
dboard_id_t rx_dboard_id,
dboard_id_t tx_dboard_id,
@@ -219,35 +248,30 @@ dboard_manager_impl::dboard_manager_impl(
void dboard_manager_impl::init(
dboard_id_t rx_dboard_id, dboard_id_t tx_dboard_id
){
- //determine xcvr status
- bool rx_dboard_is_xcvr = get_xcvr_id_to_id_map().has_key(rx_dboard_id);
- bool tx_dboard_is_xcvr = get_xcvr_id_to_id_map().has_key(tx_dboard_id);
- bool this_dboard_is_xcvr = (
- rx_dboard_is_xcvr and tx_dboard_is_xcvr and
- (get_xcvr_id_to_id_map()[rx_dboard_id] == tx_dboard_id) and
- (get_xcvr_id_to_id_map()[tx_dboard_id] == rx_dboard_id)
- );
+ //find the dboard key matches for the dboard ids
+ dboard_key_t rx_dboard_key, tx_dboard_key, xcvr_dboard_key;
+ BOOST_FOREACH(const dboard_key_t &key, get_id_to_args_map().keys()){
+ if (key.is_xcvr()){
+ if (rx_dboard_id == key.rx_id() and tx_dboard_id == key.tx_id()) xcvr_dboard_key = key;
+ if (rx_dboard_id == key.rx_id()) rx_dboard_key = key; //kept to handle warning
+ if (tx_dboard_id == key.tx_id()) tx_dboard_key = key; //kept to handle warning
+ }
+ else{
+ if (rx_dboard_id == key.xx_id()) rx_dboard_key = key;
+ if (tx_dboard_id == key.xx_id()) tx_dboard_key = key;
+ }
+ }
//warn for invalid dboard id xcvr combinations
- if (rx_dboard_is_xcvr != this_dboard_is_xcvr or tx_dboard_is_xcvr != this_dboard_is_xcvr){
+ if (not xcvr_dboard_key.is_xcvr() and (rx_dboard_key.is_xcvr() or tx_dboard_key.is_xcvr())){
uhd::warning::post(str(boost::format(
- "Unknown transceiver board ID combination...\n"
+ "Unknown transceiver board ID combination.\n"
+ "Is your daughter-board mounted properly?\n"
"RX dboard ID: %s\n"
"TX dboard ID: %s\n"
) % rx_dboard_id.to_pp_string() % tx_dboard_id.to_pp_string()));
}
- //extract dboard constructor and settings (force to unknown for messed up xcvr status)
- dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs;
- boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(
- dboard_iface::UNIT_RX, rx_dboard_id, rx_dboard_is_xcvr != this_dboard_is_xcvr
- );
-
- dboard_ctor_t tx_dboard_ctor; std::string tx_name; prop_names_t tx_subdevs;
- boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(
- dboard_iface::UNIT_TX, tx_dboard_id, tx_dboard_is_xcvr != this_dboard_is_xcvr
- );
-
//initialize the gpio pins before creating subdevs
set_nice_dboard_if();
@@ -255,15 +279,19 @@ void dboard_manager_impl::init(
dboard_ctor_args_t db_ctor_args;
db_ctor_args.db_iface = _iface;
- //make xcvr subdevs (make one subdev for both rx and tx dboards)
- if (this_dboard_is_xcvr){
- UHD_ASSERT_THROW(rx_dboard_ctor == tx_dboard_ctor);
- UHD_ASSERT_THROW(rx_subdevs == tx_subdevs);
- BOOST_FOREACH(const std::string &subdev, rx_subdevs){
+ //make xcvr subdevs
+ if (xcvr_dboard_key.is_xcvr()){
+
+ //extract data for the xcvr dboard key
+ dboard_ctor_t dboard_ctor; std::string name; prop_names_t subdevs;
+ boost::tie(dboard_ctor, name, subdevs) = get_id_to_args_map()[xcvr_dboard_key];
+
+ //create the xcvr object for each subdevice
+ BOOST_FOREACH(const std::string &subdev, subdevs){
db_ctor_args.sd_name = subdev;
db_ctor_args.rx_id = rx_dboard_id;
db_ctor_args.tx_id = tx_dboard_id;
- dboard_base::sptr xcvr_dboard = rx_dboard_ctor(&db_ctor_args);
+ dboard_base::sptr xcvr_dboard = dboard_ctor(&db_ctor_args);
//create a rx proxy for this xcvr board
_rx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(xcvr_dboard, subdev_proxy::RX_TYPE)
@@ -277,6 +305,16 @@ void dboard_manager_impl::init(
//make tx and rx subdevs (separate subdevs for rx and tx dboards)
else{
+
+ //force the rx key to the unknown board for bad combinations
+ if (rx_dboard_key.is_xcvr() or rx_dboard_key.xx_id() == dboard_id_t::none()){
+ rx_dboard_key = dboard_key_t(0xfff1);
+ }
+
+ //extract data for the rx dboard key
+ dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs;
+ boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_id_to_args_map()[rx_dboard_key];
+
//make the rx subdevs
BOOST_FOREACH(const std::string &subdev, rx_subdevs){
db_ctor_args.sd_name = subdev;
@@ -288,6 +326,16 @@ void dboard_manager_impl::init(
new subdev_proxy(rx_dboard, subdev_proxy::RX_TYPE)
);
}
+
+ //force the tx key to the unknown board for bad combinations
+ if (tx_dboard_key.is_xcvr() or tx_dboard_key.xx_id() == dboard_id_t::none()){
+ tx_dboard_key = dboard_key_t(0xfff0);
+ }
+
+ //extract data for the tx dboard key
+ dboard_ctor_t tx_dboard_ctor; std::string tx_name; prop_names_t tx_subdevs;
+ boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_id_to_args_map()[tx_dboard_key];
+
//make the tx subdevs
BOOST_FOREACH(const std::string &subdev, tx_subdevs){
db_ctor_args.sd_name = subdev;
diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp
index ff8e9cee6..de97710f2 100644
--- a/host/lib/usrp/gps_ctrl.cpp
+++ b/host/lib/usrp/gps_ctrl.cpp
@@ -125,7 +125,6 @@ public:
}
-//TODO: this isn't generalizeable to non-USRP2 USRPs.
std::string safe_gps_read() {
return _recv();
}
@@ -147,18 +146,19 @@ public:
found_gprmc = true;
break;
}
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
}
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
+ UHD_ASSERT_THROW(toked.size() == 12); //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)))
+ greg_year(boost::lexical_cast<int>(toked[9].substr(4, 2)) + 2000), //just trust me on this one
+ greg_month(boost::lexical_cast<int>(toked[9].substr(2, 2))),
+ greg_day(boost::lexical_cast<int>(toked[9].substr(0, 2)))
),
hours( boost::lexical_cast<int>(toked[1].substr(0, 2)))
+ minutes(boost::lexical_cast<int>(toked[1].substr(2, 2)))
@@ -172,6 +172,10 @@ public:
}
return now;
}
+
+ time_t get_epoch_time(void) {
+ return (get_time() - boost::posix_time::from_time_t(0)).total_seconds();
+ }
bool gps_detected(void) {
return (gps_type != GPS_TYPE_NONE);
diff --git a/host/lib/usrp/mboard_eeprom.cpp b/host/lib/usrp/mboard_eeprom.cpp
index c90f4a2db..869a38478 100644
--- a/host/lib/usrp/mboard_eeprom.cpp
+++ b/host/lib/usrp/mboard_eeprom.cpp
@@ -74,10 +74,17 @@ static const uhd::dict<std::string, boost::uint8_t> USRP_N100_OFFSETS = boost::a
("mac-addr", 0x02)
("ip-addr", 0x0C)
//leave space here for other addresses (perhaps)
+ ("gpsdo", 0x17)
("serial", 0x18)
("name", 0x18 + SERIAL_LEN)
;
+enum n200_gpsdo_type{
+ N200_GPSDO_NONE = 0,
+ N200_GPSDO_INTERNAL = 1,
+ N200_GPSDO_ONBOARD = 2
+};
+
static void load_n100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
//extract the revision number
byte_vector_t rev_lsb_msb = iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["rev-lsb-msb"], 2);
@@ -93,6 +100,14 @@ static void load_n100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
byte_copy(iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["ip-addr"], 4), ip_addr_bytes);
mb_eeprom["ip-addr"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string();
+ //gpsdo capabilities
+ boost::uint8_t gpsdo_byte = iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["gpsdo"], 1).at(0);
+ switch(n200_gpsdo_type(gpsdo_byte)){
+ case N200_GPSDO_INTERNAL: mb_eeprom["gpsdo"] = "internal"; break;
+ case N200_GPSDO_ONBOARD: mb_eeprom["gpsdo"] = "onboard"; break;
+ default: mb_eeprom["gpsdo"] = "none";
+ }
+
//extract the serial
mb_eeprom["serial"] = bytes_to_string(iface.read_eeprom(
N100_EEPROM_ADDR, USRP_N100_OFFSETS["serial"], SERIAL_LEN
@@ -136,6 +151,14 @@ static void store_n100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
iface.write_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["ip-addr"], ip_addr_bytes);
}
+ //gpsdo capabilities
+ if (mb_eeprom.has_key("gpsdo")){
+ boost::uint8_t gpsdo_byte = N200_GPSDO_NONE;
+ if (mb_eeprom["gpsdo"] == "internal") gpsdo_byte = N200_GPSDO_INTERNAL;
+ if (mb_eeprom["gpsdo"] == "onboard") gpsdo_byte = N200_GPSDO_ONBOARD;
+ iface.write_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["gpsdo"], byte_vector_t(1, gpsdo_byte));
+ }
+
//store the serial
if (mb_eeprom.has_key("serial")) iface.write_eeprom(
N100_EEPROM_ADDR, USRP_N100_OFFSETS["serial"],
diff --git a/host/lib/usrp/usrp1/dboard_impl.cpp b/host/lib/usrp/usrp1/dboard_impl.cpp
index 02906fc45..df0bb6261 100644
--- a/host/lib/usrp/usrp1/dboard_impl.cpp
+++ b/host/lib/usrp/usrp1/dboard_impl.cpp
@@ -59,6 +59,7 @@ void usrp1_impl::dboard_init(void)
//read the tx and rx dboard eeproms
_rx_db_eeproms[dboard_slot].load(*_iface, get_rx_ee_addr(dboard_slot));
_tx_db_eeproms[dboard_slot].load(*_iface, get_tx_ee_addr(dboard_slot));
+ _gdb_eeproms[dboard_slot].load(*_iface, get_tx_ee_addr(dboard_slot) ^ 5);
//create a new dboard interface and manager
_dboard_ifaces[dboard_slot] = make_dboard_iface(
@@ -68,7 +69,7 @@ void usrp1_impl::dboard_init(void)
_dboard_managers[dboard_slot] = dboard_manager::make(
_rx_db_eeproms[dboard_slot].id,
- _tx_db_eeproms[dboard_slot].id,
+ ((_gdb_eeproms[dboard_slot].id == dboard_id_t::none())? _tx_db_eeproms[dboard_slot] : _gdb_eeproms[dboard_slot]).id,
_dboard_ifaces[dboard_slot]
);
@@ -171,6 +172,10 @@ void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val, dboard_slot_
val = _tx_db_eeproms[dboard_slot];
return;
+ case DBOARD_PROP_GBOARD_EEPROM:
+ val = _gdb_eeproms[dboard_slot];
+ return;
+
case DBOARD_PROP_DBOARD_IFACE:
val = _dboard_ifaces[dboard_slot];
return;
@@ -203,6 +208,11 @@ void usrp1_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val, dboard_
_tx_db_eeproms[dboard_slot].store(*_iface, get_tx_ee_addr(dboard_slot));
return;
+ case DBOARD_PROP_GBOARD_EEPROM:
+ _gdb_eeproms[dboard_slot] = val.as<dboard_eeprom_t>();
+ _gdb_eeproms[dboard_slot].store(*_iface, get_tx_ee_addr(dboard_slot) ^ 5);
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp
index b3268298e..8fb639c4a 100644
--- a/host/lib/usrp/usrp1/io_impl.cpp
+++ b/host/lib/usrp/usrp1/io_impl.cpp
@@ -180,6 +180,9 @@ void usrp1_impl::io_impl::commit_send_buff(
//commit the current buffer
curr.buff->commit(num_bytes_to_commit);
+
+ //store the next buffer for the next call
+ curr_buff = next;
}
/*!
@@ -216,9 +219,6 @@ bool usrp1_impl::io_impl::get_send_buffs(
//make a new managed buffer with the offset buffs
buffs[0] = omsb.get_new(curr_buff, next_buff);
- //store the next buffer for the next call
- curr_buff = next_buff;
-
return true;
}
diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp
index 4e2fad6e5..870956568 100644
--- a/host/lib/usrp/usrp1/mboard_impl.cpp
+++ b/host/lib/usrp/usrp1/mboard_impl.cpp
@@ -80,7 +80,7 @@ static boost::uint32_t calc_rx_mux(
//calculate the channel flags
int channel_flags = 0;
size_t num_reals = 0, num_quads = 0;
- BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){
+ BOOST_FOREACH(const subdev_spec_pair_t &pair, uhd::reversed(subdev_spec)){
wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_RX_DBOARD, pair.db_name)];
wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)];
subdev_conn_t conn = subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>();
diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp
index 9755c466d..f53894b29 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.hpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.hpp
@@ -175,7 +175,7 @@ private:
uhd::dict<dboard_slot_t, wax_obj_proxy::sptr> _rx_dboard_proxies;
//tx dboard functions and settings
- uhd::dict<dboard_slot_t, uhd::usrp::dboard_eeprom_t> _tx_db_eeproms;
+ uhd::dict<dboard_slot_t, uhd::usrp::dboard_eeprom_t> _tx_db_eeproms, _gdb_eeproms;
void tx_dboard_get(const wax::obj &, wax::obj &, dboard_slot_t);
void tx_dboard_set(const wax::obj &, const wax::obj &, dboard_slot_t);
uhd::dict<dboard_slot_t, wax_obj_proxy::sptr> _tx_dboard_proxies;
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
index 3f41cddcf..8c6379d66 100644
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ b/host/lib/usrp/usrp2/dboard_impl.cpp
@@ -38,11 +38,14 @@ void usrp2_mboard_impl::dboard_init(void){
//read the dboard eeprom to extract the dboard ids
_rx_db_eeprom.load(*_iface, USRP2_I2C_ADDR_RX_DB);
_tx_db_eeprom.load(*_iface, USRP2_I2C_ADDR_TX_DB);
+ _gdb_eeprom.load(*_iface, USRP2_I2C_ADDR_TX_DB ^ 5);
//create a new dboard interface and manager
_dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl);
_dboard_manager = dboard_manager::make(
- _rx_db_eeprom.id, _tx_db_eeprom.id, _dboard_iface
+ _rx_db_eeprom.id,
+ ((_gdb_eeprom.id == dboard_id_t::none())? _tx_db_eeprom : _gdb_eeprom).id,
+ _dboard_iface
);
//load dboards
@@ -137,6 +140,10 @@ void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _tx_db_eeprom;
return;
+ case DBOARD_PROP_GBOARD_EEPROM:
+ val = _gdb_eeprom;
+ return;
+
case DBOARD_PROP_DBOARD_IFACE:
val = _dboard_iface;
return;
@@ -166,6 +173,11 @@ void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){
_tx_db_eeprom.store(*_iface, USRP2_I2C_ADDR_TX_DB);
return;
+ case DBOARD_PROP_GBOARD_EEPROM:
+ _gdb_eeprom = val.as<dboard_eeprom_t>();
+ _gdb_eeprom.store(*_iface, USRP2_I2C_ADDR_TX_DB ^ 5);
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 07cbd2432..005be7ce4 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -228,9 +228,9 @@ void usrp2_impl::io_impl::recv_pirate_loop(
zero_copy_if::sptr err_xport,
size_t index
){
+ recv_pirate_crew_raiding = true;
spawn_barrier.wait();
set_thread_priority_safe();
- recv_pirate_crew_raiding = true;
//store a reference to the flow control monitor (offset by max dsps)
flow_control_monitor &fc_mon = *(this->fc_mons[index*usrp2_mboard_impl::MAX_NUM_DSPS]);
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 29e0535f8..ae098dba6 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -26,6 +26,8 @@
#include <uhd/usrp/mboard_props.hpp>
#include <uhd/utils/byteswap.hpp>
#include <uhd/utils/algorithm.hpp>
+#include <uhd/types/sensors.hpp>
+#include <boost/assign/list_of.hpp>
#include <boost/bind.hpp>
#include <iostream>
@@ -100,11 +102,11 @@ usrp2_mboard_impl::usrp2_mboard_impl(
//contruct the interfaces to mboard perifs
_clock_ctrl = usrp2_clock_ctrl::make(_iface);
_codec_ctrl = usrp2_codec_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;
+ if (_iface->mb_eeprom["gpsdo"] == "internal"){
+ _gps_ctrl = gps_ctrl::make(
+ _iface->get_gps_write_fn(),
+ _iface->get_gps_read_fn());
+ }
//init the dsp stuff (before setting update packets)
dsp_init();
@@ -363,10 +365,42 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){
val = this->get_master_clock_freq();
return;
+ case SUBDEV_PROP_SENSOR_NAMES:{
+ prop_names_t names = boost::assign::list_of("mimo_locked")("ref_locked");
+ if (_gps_ctrl.get()) names.push_back("gps_time");
+ val = names;
+ }
+ return;
+
+ case MBOARD_PROP_SENSOR:
+ if(key.name == "mimo_locked") {
+ val = sensor_value_t("MIMO", this->get_mimo_locked(), "locked", "unlocked");
+ return;
+ }
+ else if(key.name == "ref_locked") {
+ val = sensor_value_t("Ref", this->get_ref_locked(), "locked", "unlocked");
+ return;
+ }
+ else if(key.name == "gps_time" and _gps_ctrl.get()) {
+ val = sensor_value_t("GPS time", int(_gps_ctrl->get_epoch_time()), "seconds");
+ }
+ else {
+ UHD_THROW_PROP_GET_ERROR();
+ }
+ break;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
+bool usrp2_mboard_impl::get_mimo_locked(void) {
+ return bool((_iface->peek32(_iface->regs.irq_rb) & (1<<10)) > 0);
+}
+
+bool usrp2_mboard_impl::get_ref_locked(void) {
+ return bool((_iface->peek32(_iface->regs.irq_rb) & (1<<11)) > 0);
+}
+
/***********************************************************************
* MBoard Set Properties
**********************************************************************/
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index cb92b1921..48443bba4 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -105,33 +105,37 @@ static device_addrs_t usrp2_find(const device_addr_t &hint_){
size_t len = udp_transport->recv(asio::buffer(usrp2_ctrl_data_in_mem));
//std::cout << len << "\n";
if (len > offsetof(usrp2_ctrl_data_t, data) and ntohl(ctrl_data_in->id) == USRP2_CTRL_ID_WAZZUP_DUDE){
+
//make a boost asio ipv4 with the raw addr in host byte order
boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in->data.ip_addr));
device_addr_t new_addr;
new_addr["type"] = "usrp2";
new_addr["addr"] = ip_addr.to_string();
+
//Attempt to read the name from the EEPROM and perform filtering.
//This operation can throw due to compatibility mismatch.
- //In this case, the discovered device will be ignored.
try{
mboard_eeprom_t mb_eeprom = usrp2_iface::make(udp_simple::make_connected(
new_addr["addr"], boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT)
))->mb_eeprom;
new_addr["name"] = mb_eeprom["name"];
new_addr["serial"] = mb_eeprom["serial"];
- if (
- (not hint.has_key("name") or hint["name"] == new_addr["name"]) and
- (not hint.has_key("serial") or hint["serial"] == new_addr["serial"])
- ){
- usrp2_addrs.push_back(new_addr);
- }
}
- catch(const std::exception &e){
- uhd::warning::post(
- std::string("Ignoring discovered device\n")
- + e.what()
- );
+ catch(const std::exception &){
+ //set these values as empty string so the device may still be found
+ //and the filter's below can still operate on the discovered device
+ new_addr["name"] = "";
+ new_addr["serial"] = "";
}
+
+ //filter the discovered device below by matching optional keys
+ if (
+ (not hint.has_key("name") or hint["name"] == new_addr["name"]) and
+ (not hint.has_key("serial") or hint["serial"] == new_addr["serial"])
+ ){
+ usrp2_addrs.push_back(new_addr);
+ }
+
//dont break here, it will exit the while loop
//just continue on to the next loop iteration
}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index 0676cecf2..ccaf0c9a8 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -147,7 +147,7 @@ private:
void tx_dboard_get(const wax::obj &, wax::obj &);
void tx_dboard_set(const wax::obj &, const wax::obj &);
wax_obj_proxy::sptr _tx_dboard_proxy;
- uhd::usrp::dboard_eeprom_t _tx_db_eeprom;
+ uhd::usrp::dboard_eeprom_t _tx_db_eeprom, _gdb_eeprom;
//methods and shadows for the dsps
UHD_PIMPL_DECL(dsp_impl) _dsp_impl;
@@ -163,7 +163,10 @@ private:
void duc_get(const wax::obj &, wax::obj &, size_t);
void duc_set(const wax::obj &, const wax::obj &, size_t);
uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dsp_proxies;
-
+
+ //sensors methods for mboard
+ bool get_mimo_locked(void);
+ bool get_ref_locked(void);
};
/*!
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index e7803d9ee..b50f8b506 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -40,6 +40,7 @@ typedef struct {
int time64_secs_rb_pps;
int time64_ticks_rb_pps;
int compat_num_rb;
+ int irq_rb;
int dsp_tx_freq;
int dsp_tx_scale_iq;
int dsp_tx_interp_rate;
diff --git a/host/lib/usrp/usrp_e100/dboard_impl.cpp b/host/lib/usrp/usrp_e100/dboard_impl.cpp
index 0b89fed9f..f6bbbd5e8 100644
--- a/host/lib/usrp/usrp_e100/dboard_impl.cpp
+++ b/host/lib/usrp/usrp_e100/dboard_impl.cpp
@@ -31,15 +31,19 @@ using namespace uhd::usrp;
* Dboard Initialization
**********************************************************************/
void usrp_e100_impl::dboard_init(void){
+ //read the dboard eeprom to extract the dboard ids
_rx_db_eeprom.load(*_iface, I2C_ADDR_RX_DB);
_tx_db_eeprom.load(*_iface, I2C_ADDR_TX_DB);
+ _gdb_eeprom.load(*_iface, I2C_ADDR_TX_DB ^ 5);
//create a new dboard interface and manager
_dboard_iface = make_usrp_e100_dboard_iface(
_iface, _clock_ctrl, _codec_ctrl
);
_dboard_manager = dboard_manager::make(
- _rx_db_eeprom.id, _tx_db_eeprom.id, _dboard_iface
+ _rx_db_eeprom.id,
+ ((_gdb_eeprom.id == dboard_id_t::none())? _tx_db_eeprom : _gdb_eeprom).id,
+ _dboard_iface
);
//setup the dboard proxies
@@ -136,6 +140,10 @@ void usrp_e100_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _tx_db_eeprom;
return;
+ case DBOARD_PROP_GBOARD_EEPROM:
+ val = _gdb_eeprom;
+ return;
+
case DBOARD_PROP_DBOARD_IFACE:
val = _dboard_iface;
return;
@@ -167,6 +175,11 @@ void usrp_e100_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){
_tx_db_eeprom.store(*_iface, I2C_ADDR_TX_DB);
return;
+ case DBOARD_PROP_GBOARD_EEPROM:
+ _gdb_eeprom = val.as<dboard_eeprom_t>();
+ _gdb_eeprom.store(*_iface, I2C_ADDR_TX_DB ^ 5);
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/usrp_e100/io_impl.cpp b/host/lib/usrp/usrp_e100/io_impl.cpp
index cbab5a761..40b8a2393 100644
--- a/host/lib/usrp/usrp_e100/io_impl.cpp
+++ b/host/lib/usrp/usrp_e100/io_impl.cpp
@@ -31,8 +31,6 @@ using namespace uhd;
using namespace uhd::usrp;
using namespace uhd::transport;
-zero_copy_if::sptr usrp_e100_make_mmap_zero_copy(usrp_e100_iface::sptr iface);
-
/***********************************************************************
* Constants
**********************************************************************/
@@ -49,8 +47,8 @@ static const bool recv_debug = false;
* - vrt packet handler states
**********************************************************************/
struct usrp_e100_impl::io_impl{
- io_impl(usrp_e100_iface::sptr iface):
- data_xport(usrp_e100_make_mmap_zero_copy(iface)),
+ io_impl(zero_copy_if::sptr &xport):
+ data_xport(xport),
get_recv_buffs_fcn(boost::bind(&usrp_e100_impl::io_impl::get_recv_buffs, this, _1)),
get_send_buffs_fcn(boost::bind(&usrp_e100_impl::io_impl::get_send_buffs, this, _1)),
recv_pirate_booty(data_xport->get_num_recv_frames()),
@@ -79,7 +77,8 @@ struct usrp_e100_impl::io_impl{
//The data transport is listed first so that it is deconstructed last,
//which is after the states and booty which may hold managed buffers.
- zero_copy_if::sptr data_xport;
+ //This comment is invalid because its now a reference and not stored here.
+ zero_copy_if::sptr &data_xport;
//bound callbacks for get buffs (bound once here, not in fast-path)
vrt_packet_handler::get_recv_buffs_t get_recv_buffs_fcn;
@@ -109,9 +108,9 @@ struct usrp_e100_impl::io_impl{
void usrp_e100_impl::io_impl::recv_pirate_loop(
boost::barrier &spawn_barrier, usrp_e100_clock_ctrl::sptr clock_ctrl
){
+ recv_pirate_crew_raiding = true;
spawn_barrier.wait();
set_thread_priority_safe();
- recv_pirate_crew_raiding = true;
while(recv_pirate_crew_raiding){
managed_recv_buffer::sptr buff = this->data_xport->get_recv_buff();
@@ -181,7 +180,7 @@ void usrp_e100_impl::io_init(void){
_recv_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
//setup before the registers (transport called to calculate max spp)
- _io_impl = UHD_PIMPL_MAKE(io_impl, (_iface));
+ _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_xport));
//clear state machines
_iface->poke32(UE_REG_CTRL_RX_CLEAR, 0);
@@ -234,7 +233,7 @@ size_t usrp_e100_impl::get_max_send_samps_per_packet(void) const{
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
;
- size_t bpp = _io_impl->data_xport->get_send_frame_size() - hdr_size;
+ size_t bpp = _send_frame_size - hdr_size;
return bpp/_send_otw_type.get_sample_size();
}
@@ -265,7 +264,7 @@ size_t usrp_e100_impl::get_max_recv_samps_per_packet(void) const{
+ sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
;
- size_t bpp = _io_impl->data_xport->get_recv_frame_size() - hdr_size;
+ size_t bpp = _recv_frame_size - hdr_size;
return bpp/_recv_otw_type.get_sample_size();
}
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp
index a8fbe5d69..fe839c409 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp
+++ b/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp
@@ -138,7 +138,7 @@ static device::sptr usrp_e100_make(const device_addr_t &device_addr){
) % USRP_E_FPGA_COMPAT_NUM % fpga_compat_num));
}
- return device::sptr(new usrp_e100_impl(iface));
+ return device::sptr(new usrp_e100_impl(iface, device_addr));
}
UHD_STATIC_BLOCK(register_usrp_e100_device){
@@ -148,7 +148,15 @@ UHD_STATIC_BLOCK(register_usrp_e100_device){
/***********************************************************************
* Structors
**********************************************************************/
-usrp_e100_impl::usrp_e100_impl(usrp_e100_iface::sptr iface): _iface(iface){
+usrp_e100_impl::usrp_e100_impl(
+ usrp_e100_iface::sptr iface,
+ const device_addr_t &device_addr
+):
+ _iface(iface),
+ _data_xport(usrp_e100_make_mmap_zero_copy(_iface)),
+ _recv_frame_size(std::min(_data_xport->get_recv_frame_size(), size_t(device_addr.cast<double>("recv_frame_size", 1e9)))),
+ _send_frame_size(std::min(_data_xport->get_send_frame_size(), size_t(device_addr.cast<double>("send_frame_size", 1e9))))
+{
//setup interfaces into hardware
_clock_ctrl = usrp_e100_clock_ctrl::make(_iface);
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
index 98117cf26..ab3379dd5 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
+++ b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
@@ -26,10 +26,13 @@
#include <uhd/types/clock_config.hpp>
#include <uhd/types/stream_cmd.hpp>
#include <uhd/usrp/dboard_manager.hpp>
+#include <uhd/transport/zero_copy.hpp>
#ifndef INCLUDED_USRP_E100_IMPL_HPP
#define INCLUDED_USRP_E100_IMPL_HPP
+uhd::transport::zero_copy_if::sptr usrp_e100_make_mmap_zero_copy(usrp_e100_iface::sptr iface);
+
static const boost::uint16_t USRP_E_FPGA_COMPAT_NUM = 0x03;
//! load an fpga image from a bin file into the usrp-e fpga
@@ -79,7 +82,7 @@ private:
class usrp_e100_impl : public uhd::device{
public:
//structors
- usrp_e100_impl(usrp_e100_iface::sptr);
+ usrp_e100_impl(usrp_e100_iface::sptr, const uhd::device_addr_t &);
~usrp_e100_impl(void);
//the io interface
@@ -94,7 +97,9 @@ private:
usrp_e100_iface::sptr _iface;
//handle io stuff
+ uhd::transport::zero_copy_if::sptr _data_xport;
UHD_PIMPL_DECL(io_impl) _io_impl;
+ size_t _recv_frame_size, _send_frame_size;
uhd::otw_type_t _send_otw_type, _recv_otw_type;
void io_init(void);
void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd);
@@ -132,7 +137,7 @@ private:
wax_obj_proxy::sptr _rx_dboard_proxy;
//tx dboard functions and settings
- uhd::usrp::dboard_eeprom_t _tx_db_eeprom;
+ uhd::usrp::dboard_eeprom_t _tx_db_eeprom, _gdb_eeprom;
void tx_dboard_get(const wax::obj &, wax::obj &);
void tx_dboard_set(const wax::obj &, const wax::obj &);
wax_obj_proxy::sptr _tx_dboard_proxy;
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt
index 98b5d41fb..b2dd697fc 100644
--- a/host/utils/CMakeLists.txt
+++ b/host/utils/CMakeLists.txt
@@ -54,6 +54,17 @@ FOREACH(util_source ${util_share_sources})
ENDFOREACH(util_source)
IF(ENABLE_USRP2)
+ IF(WIN32 AND UHD_RELEASE_MODE) #include dd.exe
+ FILE(DOWNLOAD
+ "http://www.ettus.com/downloads/dd.exe"
+ ${CMAKE_CURRENT_BINARY_DIR}/dd.exe
+ )
+ INSTALL(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/dd.exe
+ DESTINATION ${PKG_DATA_DIR}/utils
+ COMPONENT utilities
+ )
+ ENDIF(WIN32 AND UHD_RELEASE_MODE)
INSTALL(PROGRAMS
usrp2_recovery.py
usrp2_card_burner.py
diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp
index b32131b2a..3ea63c4bb 100644
--- a/host/utils/uhd_usrp_probe.cpp
+++ b/host/utils/uhd_usrp_probe.cpp
@@ -27,6 +27,7 @@
#include <uhd/usrp/subdev_props.hpp>
#include <uhd/usrp/dboard_id.hpp>
#include <uhd/usrp/mboard_eeprom.hpp>
+#include <uhd/usrp/dboard_eeprom.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
@@ -46,12 +47,12 @@ static std::string make_border(const std::string &text){
ss << boost::format(" _____________________________________________________") << std::endl;
ss << boost::format(" /") << std::endl;
std::vector<std::string> lines; boost::split(lines, text, boost::is_any_of("\n"));
- while (lines.back() == "") lines.pop_back(); //strip trailing newlines
+ while (lines.back().empty()) lines.pop_back(); //strip trailing newlines
if (lines.size()) lines[0] = " " + lines[0]; //indent the title line
BOOST_FOREACH(const std::string &line, lines){
ss << boost::format("| %s") % line << std::endl;
}
- //ss << boost::format(" \\____________________________________________________") << std::endl;
+ //ss << boost::format(" \\_____________________________________________________") << std::endl;
return ss.str();
}
@@ -114,6 +115,14 @@ static std::string get_dboard_pp_string(const std::string &type, wax::obj dboard
std::stringstream ss;
ss << boost::format("%s Dboard: %s") % type % dboard[usrp::DBOARD_PROP_NAME].as<std::string>() << std::endl;
//ss << std::endl;
+ usrp::dboard_eeprom_t db_eeprom = dboard[usrp::DBOARD_PROP_DBOARD_EEPROM].as<usrp::dboard_eeprom_t>();
+ if (db_eeprom.id != usrp::dboard_id_t::none()) ss << boost::format("ID: %s") % db_eeprom.id.to_pp_string() << std::endl;
+ if (not db_eeprom.serial.empty()) ss << boost::format("Serial: %s") % db_eeprom.serial << std::endl;
+ if (type == "TX"){
+ usrp::dboard_eeprom_t gdb_eeprom = dboard[usrp::DBOARD_PROP_GBOARD_EEPROM].as<usrp::dboard_eeprom_t>();
+ if (gdb_eeprom.id != usrp::dboard_id_t::none()) ss << boost::format("GDB ID: %s") % gdb_eeprom.id.to_pp_string() << std::endl;
+ if (not gdb_eeprom.serial.empty()) ss << boost::format("GDB Serial: %s") % gdb_eeprom.serial << std::endl;
+ }
BOOST_FOREACH(const std::string &subdev_name, dboard[usrp::DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>()){
ss << make_border(get_subdev_pp_string(type, dboard[named_prop_t(usrp::DBOARD_PROP_SUBDEV, subdev_name)]));
}
@@ -132,14 +141,14 @@ static std::string get_mboard_pp_string(wax::obj mboard){
BOOST_FOREACH(const std::string &dsp_name, mboard[usrp::MBOARD_PROP_RX_DSP_NAMES].as<prop_names_t>()){
ss << make_border(get_dsp_pp_string("RX", mboard[named_prop_t(usrp::MBOARD_PROP_RX_DSP, dsp_name)]));
}
+ BOOST_FOREACH(const std::string &db_name, mboard[usrp::MBOARD_PROP_RX_DBOARD_NAMES].as<prop_names_t>()){
+ ss << make_border(get_dboard_pp_string("RX", mboard[named_prop_t(usrp::MBOARD_PROP_RX_DBOARD, db_name)]));
+ }
BOOST_FOREACH(const std::string &dsp_name, mboard[usrp::MBOARD_PROP_TX_DSP_NAMES].as<prop_names_t>()){
ss << make_border(get_dsp_pp_string("TX", mboard[named_prop_t(usrp::MBOARD_PROP_TX_DSP, dsp_name)]));
}
- BOOST_FOREACH(const std::string &dsp_name, mboard[usrp::MBOARD_PROP_RX_DBOARD_NAMES].as<prop_names_t>()){
- ss << make_border(get_dboard_pp_string("RX", mboard[named_prop_t(usrp::MBOARD_PROP_RX_DBOARD, dsp_name)]));
- }
- BOOST_FOREACH(const std::string &dsp_name, mboard[usrp::MBOARD_PROP_TX_DBOARD_NAMES].as<prop_names_t>()){
- ss << make_border(get_dboard_pp_string("TX", mboard[named_prop_t(usrp::MBOARD_PROP_TX_DBOARD, dsp_name)]));
+ BOOST_FOREACH(const std::string &db_name, mboard[usrp::MBOARD_PROP_TX_DBOARD_NAMES].as<prop_names_t>()){
+ ss << make_border(get_dboard_pp_string("TX", mboard[named_prop_t(usrp::MBOARD_PROP_TX_DBOARD, db_name)]));
}
return ss.str();
}
diff --git a/host/utils/usrp1_init_eeprom.cpp b/host/utils/usrp1_init_eeprom.cpp
index b05e400b1..39f091af4 100644
--- a/host/utils/usrp1_init_eeprom.cpp
+++ b/host/utils/usrp1_init_eeprom.cpp
@@ -21,6 +21,7 @@
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <iostream>
+#include <cstdlib>
namespace po = boost::program_options;
@@ -41,6 +42,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
return ~0;
}
+ //cant find a uninitialized usrp with this mystery module in the way...
+ if (std::system("/sbin/rmmod usbtest") != 0){
+ std::cerr << "Did not rmmod usbtest, this may be ok..." << std::endl;
+ }
+
//load the options into the address
uhd::device_addr_t device_addr;
device_addr["type"] = "usrp1";
diff --git a/host/utils/usrp2_card_burner.py b/host/utils/usrp2_card_burner.py
index 741c7e3e1..26adb91c7 100755
--- a/host/utils/usrp2_card_burner.py
+++ b/host/utils/usrp2_card_burner.py
@@ -56,6 +56,8 @@ def command(*args):
def get_dd_path():
if platform.system() == 'Windows':
+ dd_path = os.path.join(os.path.dirname(__file__), 'dd.exe')
+ if os.path.exists(dd_path): return dd_path
dd_path = os.path.join(tempfile.gettempdir(), 'dd.exe')
if not os.path.exists(dd_path):
print('Downloading dd.exe to %s'%dd_path)
@@ -232,13 +234,9 @@ def get_options():
parser.add_option("--fw", type="string", help="firmware image path (optional)", default='')
parser.add_option("--fpga", type="string", help="fpga image path (optional)", default='')
parser.add_option("--list", action="store_true", help="list possible raw devices", default=False)
+ parser.add_option("--force", action="store_true", help="override safety check", default=False)
(options, args) = parser.parse_args()
- if options.list:
- print('Possible raw devices:')
- print(' ' + '\n '.join(get_raw_device_hints()))
- exit()
-
return options
########################################################################
@@ -246,5 +244,19 @@ def get_options():
########################################################################
if __name__=='__main__':
options = get_options()
+ device_hints = get_raw_device_hints()
+ show_listing = options.list
+
+ if not show_listing and not options.force and options.dev and options.dev not in device_hints:
+ print('The device "%s" was not in the list of possible raw devices.'%options.dev)
+ print('The card burner application will now exit without burning your card.')
+ print('To override this safety check, specify the --force option.\n')
+ show_listing = True
+
+ if show_listing:
+ print('Possible raw devices:')
+ print(' ' + '\n '.join(device_hints))
+ exit()
+
if not options.dev: raise Exception('no raw device path specified')
print(burn_sd_card(dev=options.dev, fw=options.fw, fpga=options.fpga))
diff --git a/host/utils/usrp_burn_db_eeprom.cpp b/host/utils/usrp_burn_db_eeprom.cpp
index 617417e09..58417bd68 100644
--- a/host/utils/usrp_burn_db_eeprom.cpp
+++ b/host/utils/usrp_burn_db_eeprom.cpp
@@ -37,10 +37,13 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//command line variables
std::string args, slot, unit;
static const uhd::dict<std::string, mboard_prop_t> unit_to_db_prop = boost::assign::map_list_of
- ("RX", MBOARD_PROP_RX_DBOARD) ("TX", MBOARD_PROP_TX_DBOARD)
+ ("RX", MBOARD_PROP_RX_DBOARD) ("TX", MBOARD_PROP_TX_DBOARD) ("GDB", MBOARD_PROP_TX_DBOARD)
;
static const uhd::dict<std::string, mboard_prop_t> unit_to_db_names_prop = boost::assign::map_list_of
- ("RX", MBOARD_PROP_RX_DBOARD_NAMES) ("TX", MBOARD_PROP_TX_DBOARD_NAMES)
+ ("RX", MBOARD_PROP_RX_DBOARD_NAMES) ("TX", MBOARD_PROP_TX_DBOARD_NAMES) ("GDB", MBOARD_PROP_TX_DBOARD_NAMES)
+ ;
+ static const uhd::dict<std::string, dboard_prop_t> unit_to_db_eeprom_prop = boost::assign::map_list_of
+ ("RX", DBOARD_PROP_DBOARD_EEPROM) ("TX", DBOARD_PROP_DBOARD_EEPROM) ("GDB", DBOARD_PROP_GBOARD_EEPROM)
;
po::options_description desc("Allowed options");
@@ -48,7 +51,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("help", "help message")
("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
("slot", po::value<std::string>(&slot)->default_value(""), "dboard slot name [default is blank for automatic]")
- ("unit", po::value<std::string>(&unit)->default_value(""), "which unit [RX or TX]")
+ ("unit", po::value<std::string>(&unit)->default_value(""), "which unit [RX, TX, or GDB]")
("id", po::value<std::string>(), "dboard id to burn, omit for readback")
("ser", po::value<std::string>(), "serial to burn, omit for readback")
;
@@ -82,19 +85,19 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::string prefix = unit + ":" + slot;
std::cout << boost::format("Reading EEPROM on %s dboard...") % prefix << std::endl;
- dboard_eeprom_t db_eeprom = dboard[DBOARD_PROP_DBOARD_EEPROM].as<dboard_eeprom_t>();
+ dboard_eeprom_t db_eeprom = dboard[unit_to_db_eeprom_prop[unit]].as<dboard_eeprom_t>();
//------------- handle the dboard ID -----------------------------//
if (vm.count("id")){
db_eeprom.id = dboard_id_t::from_string(vm["id"].as<std::string>());
- dboard[DBOARD_PROP_DBOARD_EEPROM] = db_eeprom;
+ dboard[unit_to_db_eeprom_prop[unit]] = db_eeprom;
}
std::cout << boost::format(" Current ID: %s") % db_eeprom.id.to_pp_string() << std::endl;
//------------- handle the dboard serial--------------------------//
if (vm.count("ser")){
db_eeprom.serial = vm["ser"].as<std::string>();
- dboard[DBOARD_PROP_DBOARD_EEPROM] = db_eeprom;
+ dboard[unit_to_db_eeprom_prop[unit]] = db_eeprom;
}
std::cout << boost::format(" Current serial: \"%s\"") % db_eeprom.serial << std::endl;