aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-rw-r--r--host/CMakeLists.txt1
-rw-r--r--host/README1
-rw-r--r--host/apps/omap_debug/usrp-e-led.c16
-rw-r--r--host/docs/build.rst31
-rw-r--r--host/docs/dboards.rst11
-rw-r--r--host/docs/usrp2.rst27
-rw-r--r--host/examples/CMakeLists.txt4
-rw-r--r--host/examples/rx_timed_samples.cpp17
-rw-r--r--host/examples/tx_timed_samples.cpp92
-rw-r--r--host/include/uhd/config.hpp9
-rw-r--r--host/include/uhd/device.hpp57
-rw-r--r--host/include/uhd/transport/zero_copy.hpp17
-rw-r--r--host/include/uhd/types/dict.hpp2
-rw-r--r--host/include/uhd/types/mac_addr.hpp16
-rw-r--r--host/include/uhd/types/otw_type.hpp6
-rw-r--r--host/include/uhd/usrp/dboard_iface.hpp22
-rw-r--r--host/include/uhd/usrp/dboard_props.hpp3
-rw-r--r--host/include/uhd/usrp/device_props.hpp4
-rw-r--r--host/include/uhd/usrp/simple_usrp.hpp2
-rw-r--r--host/include/uhd/utils/algorithm.hpp5
-rw-r--r--host/lib/ic_reg_maps/common.py41
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad9777_regs.py2
-rw-r--r--host/lib/transport/CMakeLists.txt1
-rw-r--r--host/lib/transport/convert_types.cpp23
-rwxr-xr-xhost/lib/transport/gen_vrt.py2
-rw-r--r--host/lib/transport/udp_zero_copy_asio.cpp144
-rw-r--r--host/lib/transport/vrt_packet_handler.hpp370
-rw-r--r--host/lib/types.cpp140
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp124
-rw-r--r--host/lib/usrp/dboard/db_wbx.cpp6
-rw-r--r--host/lib/usrp/dboard/db_xcvr2450.cpp4
-rw-r--r--host/lib/usrp/dboard_manager.cpp3
-rw-r--r--host/lib/usrp/simple_usrp.cpp8
-rw-r--r--host/lib/usrp/usrp2/CMakeLists.txt10
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.cpp (renamed from host/lib/usrp/usrp2/clock_control.cpp)22
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.hpp (renamed from host/lib/usrp/usrp2/clock_control.hpp)12
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.cpp91
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.hpp38
-rw-r--r--host/lib/usrp/usrp2/dboard_iface.cpp52
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp12
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp3
-rw-r--r--host/lib/usrp/usrp2/fw_common.h24
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp182
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp152
-rw-r--r--host/lib/usrp/usrp2/serdes_ctrl.cpp46
-rw-r--r--host/lib/usrp/usrp2/serdes_ctrl.hpp40
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp7
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp15
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp61
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp41
-rw-r--r--host/lib/usrp/usrp_e/dboard_iface.cpp50
-rw-r--r--host/lib/usrp/usrp_e/usrp_e_impl.cpp14
-rw-r--r--host/lib/usrp/usrp_e/usrp_e_impl.hpp6
-rw-r--r--host/lib/usrp/usrp_e/usrp_e_regs.hpp12
-rw-r--r--host/utils/CMakeLists.txt13
-rw-r--r--host/utils/usrp2_addr_burner.cpp (renamed from host/utils/usrp2_burner.cpp)2
-rwxr-xr-xhost/utils/usrp2_card_burner.py226
-rwxr-xr-xhost/utils/usrp2_card_burner_gui.py169
58 files changed, 1887 insertions, 624 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index f2725e4b3..0b2d3f012 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -62,6 +62,7 @@ IF(UNIX)
UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-ansi HAVE_ANSI)
#only export symbols that are declared to be part of the uhd api:
UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
+ UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-O3 HAVE_O3) #have some optimizations
ENDIF(UNIX)
IF(WIN32)
diff --git a/host/README b/host/README
index e67bb25f8..6eaf6bb42 100644
--- a/host/README
+++ b/host/README
@@ -17,6 +17,7 @@ LF RX
LF TX
RFX Series
XCVR 2450
+WBX Series
########################################################################
# Documentation
diff --git a/host/apps/omap_debug/usrp-e-led.c b/host/apps/omap_debug/usrp-e-led.c
index d1b6c8996..30fbb66e0 100644
--- a/host/apps/omap_debug/usrp-e-led.c
+++ b/host/apps/omap_debug/usrp-e-led.c
@@ -20,16 +20,16 @@ int main(int argc, char *argv[])
fp = open("/dev/usrp_e0", O_RDWR);
printf("fp = %d\n", fp);
- d.offset = UE_REG_MISC_BASE;
+ d.offset = UE_REG_MISC_BASE+14;
d.count = 1;
- while (1) {
- for (i=0; i<8; i++) {
- d.buf[0] = i;
- ret = ioctl(fp, USRP_E_WRITE_CTL16, &d);
- sleep(1);
- }
- }
+ d.buf[0] = 0x4020;
+ ret = ioctl(fp, USRP_E_WRITE_CTL16, &d);
+
+ sleep(10);
+
+ d.buf[0] = 0x0;
+ ret = ioctl(fp, USRP_E_WRITE_CTL16, &d);
return 0;
}
diff --git a/host/docs/build.rst b/host/docs/build.rst
index d28682764..f5a8dac8d 100644
--- a/host/docs/build.rst
+++ b/host/docs/build.rst
@@ -8,9 +8,14 @@ UHD - Build Guide
Build Dependencies
------------------------------------------------------------------------
-**Unix Notes:**
+**Linux Notes:**
The dependencies can be acquired through the package manager.
+**Mac OS X Notes:**
+Install the "Xcode Developer Tools" to get the build tools (gcc and make).
+Use MacPorts to get the Boost and Cheetah dependencies.
+Other dependencies can be downloaded as dmg installers from the web.
+
**Windows Notes:**
The dependencies can be acquired through installable exe files.
Usually, the windows installer can be found on the project's website.
@@ -27,12 +32,13 @@ or install msysgit from http://code.google.com/p/msysgit/downloads/list
^^^^^^^^^^^^^^^^
C++
^^^^^^^^^^^^^^^^
-On unix, this is GCC 4.0 and above. On windows, this is MSVC 2008.
+On Unix, this is GCC 4.0 and above. On Windows, this is MSVC 2008.
Other compilers have not been tested yet or confirmed working.
^^^^^^^^^^^^^^^^
CMake
^^^^^^^^^^^^^^^^
+* **Purpose:** generates project build files
* **Version:** at least 2.8
* **Required for:** build time
* **Download URL:** http://www.cmake.org/cmake/resources/software.html
@@ -40,6 +46,7 @@ CMake
^^^^^^^^^^^^^^^^
Boost
^^^^^^^^^^^^^^^^
+* **Purpose:** C++ library
* **Version:** at least 3.6 unix, at least 4.0 windows
* **Required for:** build time + run time
* **Download URL:** http://www.boost.org/users/download/
@@ -48,13 +55,15 @@ Boost
^^^^^^^^^^^^^^^^
Python
^^^^^^^^^^^^^^^^
+* **Purpose:** used by Cheetah and utility scripts
* **Version:** at least 2.6
-* **Required for:** build time
+* **Required for:** build time + run time utility scripts
* **Download URL:** http://www.python.org/download/
^^^^^^^^^^^^^^^^
Cheetah
^^^^^^^^^^^^^^^^
+* **Purpose:** source code generation
* **Version:** at least 2.0
* **Required for:** build time
* **Download URL:** http://www.cheetahtemplate.org/download.html
@@ -63,9 +72,17 @@ Cheetah
^^^^^^^^^^^^^^^^
Doxygen
^^^^^^^^^^^^^^^^
+* **Purpose:** generates html api documentation
* **Required for:** build time (optional)
* **Download URL:** http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc
+^^^^^^^^^^^^^^^^
+Docutils
+^^^^^^^^^^^^^^^^
+* **Purpose:** generates html user manual
+* **Required for:** build time (optional)
+* **Download URL:** http://docutils.sourceforge.net/
+
------------------------------------------------------------------------
Build Instructions (Unix)
------------------------------------------------------------------------
@@ -80,7 +97,7 @@ Generate Makefiles with cmake
cd build
cmake ../
-For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX=<myprefix> ../
+For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX=<prefix> ../
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Build and install
@@ -92,11 +109,15 @@ Build and install
sudo make install
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Setup the library path
+Setup the library path (Linux)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Make sure that libuhd.so is in your LD_LIBRARY_PATH
or add it to /etc/ld.so.conf and make sure to run sudo ldconfig
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Setup the library path (Mac OS X)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Make sure that libuhd.dylib is in your DYLD_LIBRARY_PATH
------------------------------------------------------------------------
Build Instructions (Windows)
diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst
index d08b752a6..a320f86cb 100644
--- a/host/docs/dboards.rst
+++ b/host/docs/dboards.rst
@@ -62,3 +62,14 @@ not doing so will yeild undefined results.
The XCVR2450 uses a common LO for both receive and transmit.
Even though the API allows the RX and TX LOs to be individually set,
a change of one LO setting will be reflected in the other LO setting.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+WBX Series
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Transmit Antennas: **TX/RX**
+
+Receive Antennas: **TX/RX** or **RX2**
+
+The user may set the receive antenna to be TX/RX or RX2.
+However, when using an RFX board in full-duplex mode,
+the receive antenna will always be set to RX2, regardless of the settings.
diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst
index dfde06b27..1bd95cefa 100644
--- a/host/docs/usrp2.rst
+++ b/host/docs/usrp2.rst
@@ -45,22 +45,33 @@ Run the following commands:
Load the images onto the SD card
------------------------------------------------------------------------
**Warning!**
-Use the u2_flash_tool with caution. If you specify the wrong device node,
+Use the usrp2_card_burner.py with caution. If you specify the wrong device node,
you could overwrite your hard drive. Make sure that --dev= specifies the SD card.
-Load the FPGA image:
+Use the *--list* option to get a list of possible raw devices.
+The list result will filter out disk partitions and devices too large to be the sd card.
+The list option has been implemented on Linux, Mac OS X, and Windows.
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Use the card burner tool (unix)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
- cd <uhd-repo-path>/firmware/microblaze
- sudo ./u2_flash_tool --dev=/dev/sd<XXX> -t fpga -w <path_to_fpga_image>
+ sudo <prefix>/share/uhd/utils/usrp2_card_burner_gui.py
+
+ -- OR --
-Load the firmware image:
+ cd <prefix>/share/uhd/utils
+ sudo ./usrp2_card_burner.py --dev=/dev/sd<XXX> --fpga=<path_to_fpga_image>
+ sudo ./usrp2_card_burner.py --dev=/dev/sd<XXX> --fw=<path_to_firmware_image>
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Use the card burner tool (windows)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
- cd <uhd-repo-path>/firmware/microblaze directory
- sudo ./u2_flash_tool --dev=/dev/sd<XXX> -t s/w -w <path_to_firmware_image>
+ <path_to_python.exe> <prefix>/share/uhd/utils/usrp2_card_burner_gui.py
+
------------------------------------------------------------------------
Setup networking
@@ -103,7 +114,7 @@ Run the following commands:
::
cd <prefix>/share/uhd/utils
- ./usrp_burner --addr=192.168.10.2 --new-ip=192.168.10.3
+ ./usrp_addr_burner --addr=192.168.10.2 --new-ip=192.168.10.3
**Method 2 (Linux Only):**
This method assumes that you do not know the IP address of your USRP2.
diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt
index 242857625..a537c0901 100644
--- a/host/examples/CMakeLists.txt
+++ b/host/examples/CMakeLists.txt
@@ -18,3 +18,7 @@
ADD_EXECUTABLE(rx_timed_samples rx_timed_samples.cpp)
TARGET_LINK_LIBRARIES(rx_timed_samples uhd)
INSTALL(TARGETS rx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples)
+
+ADD_EXECUTABLE(tx_timed_samples tx_timed_samples.cpp)
+TARGET_LINK_LIBRARIES(tx_timed_samples uhd)
+INSTALL(TARGETS tx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples)
diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp
index 4b8774036..64da260d5 100644
--- a/host/examples/rx_timed_samples.cpp
+++ b/host/examples/rx_timed_samples.cpp
@@ -29,7 +29,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::string args;
int seconds_in_future;
size_t total_num_samps;
- double rx_rate;
+ double rx_rate, freq;
//setup the program options
po::options_description desc("Allowed options");
@@ -39,10 +39,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("secs", po::value<int>(&seconds_in_future)->default_value(3), "number of seconds in the future to receive")
("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to receive")
("rxrate", po::value<double>(&rx_rate)->default_value(100e6/16), "rate of incoming samples")
+ ("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
- po::notify(vm);
+ po::notify(vm);
//print the help message
if (vm.count("help")){
@@ -62,6 +63,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
sdev->set_rx_rate(rx_rate);
std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl;
std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
+ sdev->set_rx_freq(freq);
sdev->set_time_now(uhd::time_spec_t(0));
//setup streaming
@@ -78,11 +80,16 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
size_t num_acc_samps = 0; //number of accumulated samples
while(num_acc_samps < total_num_samps){
uhd::rx_metadata_t md;
- std::complex<float> buff[1000];
+ std::vector<std::complex<float> > buff(dev->get_max_recv_samps_per_packet());
size_t num_rx_samps = dev->recv(
- boost::asio::buffer(buff, sizeof(buff)),
- md, uhd::io_type_t::COMPLEX_FLOAT32
+ boost::asio::buffer(buff),
+ md, uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::RECV_MODE_ONE_PACKET
);
+ if (num_rx_samps == 0 and num_acc_samps > 0){
+ std::cout << "Got timeout before all samples received, possible packet loss, exiting loop..." << std::endl;
+ break;
+ }
if (num_rx_samps == 0) continue; //wait for packets with contents
std::cout << boost::format("Got packet: %u samples, %u secs, %u nsecs")
diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp
new file mode 100644
index 000000000..e9e0c785e
--- /dev/null
+++ b/host/examples/tx_timed_samples.cpp
@@ -0,0 +1,92 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/safe_main.hpp>
+#include <uhd/usrp/simple_usrp.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+#include <complex>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ //variables to be set by po
+ std::string args;
+ int seconds_in_future;
+ size_t total_num_samps;
+ double tx_rate, freq;
+ float ampl;
+
+ //setup the program options
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args")
+ ("secs", po::value<int>(&seconds_in_future)->default_value(3), "number of seconds in the future to transmit")
+ ("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to transmit")
+ ("txrate", po::value<double>(&tx_rate)->default_value(100e6/16), "rate of outgoing samples")
+ ("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
+ ("ampl", po::value<float>(&ampl)->default_value(float(0.3)), "amplitude of each sample")
+ ;
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ //print the help message
+ if (vm.count("help")){
+ std::cout << boost::format("UHD TX Timed Samples %s") % desc << std::endl;
+ return ~0;
+ }
+
+ //create a usrp device
+ std::cout << std::endl;
+ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
+ uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args);
+ uhd::device::sptr dev = sdev->get_device();
+ std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl;
+
+ //set properties on the device
+ std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl;
+ sdev->set_tx_rate(tx_rate);
+ std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl;
+ std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
+ sdev->set_tx_freq(freq);
+ sdev->set_time_now(uhd::time_spec_t(0));
+
+ //data to send
+ std::vector<std::complex<float> > buff(total_num_samps, std::complex<float>(ampl, ampl));
+ uhd::tx_metadata_t md;
+ md.start_of_burst = true;
+ md.end_of_burst = true;
+ md.has_time_spec = true;
+ md.time_spec = uhd::time_spec_t(seconds_in_future);
+
+ //send the entire buffer, let the driver handle fragmentation
+ size_t num_tx_samps = dev->send(
+ boost::asio::buffer(buff),
+ md, uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::SEND_MODE_FULL_BUFF
+ );
+ std::cout << std::endl << boost::format("Sent %d samples") % num_tx_samps << std::endl;
+
+
+ //finished
+ std::cout << std::endl << "Done!" << std::endl << std::endl;
+
+ return 0;
+}
diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp
index 32eafc89b..fea95145c 100644
--- a/host/include/uhd/config.hpp
+++ b/host/include/uhd/config.hpp
@@ -76,4 +76,13 @@
#define UHD_LOCAL
#endif // UHD_DLL
+// Define force inline macro
+#ifdef BOOST_MSVC
+ #define UHD_INLINE __forceinline
+#elif defined(__GNUG__) && __GNUG__ >= 4
+ #define UHD_INLINE inline __attribute__((always_inline))
+#else
+ #define UHD_INLINE inline
+#endif
+
#endif /* INCLUDED_UHD_CONFIG_HPP */
diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp
index ae75e6dc8..d3e9015c4 100644
--- a/host/include/uhd/device.hpp
+++ b/host/include/uhd/device.hpp
@@ -77,15 +77,35 @@ public:
static sptr make(const device_addr_t &hint, size_t which = 0);
/*!
+ * Send modes for the device send routine.
+ */
+ enum send_mode_t{
+ //! Tells the send routine to send the entire buffer
+ SEND_MODE_FULL_BUFF = 0,
+ //! Tells the send routine to return after one packet
+ SEND_MODE_ONE_PACKET = 1
+ };
+
+ /*!
+ * Recv modes for the device recv routine.
+ */
+ enum recv_mode_t{
+ //! Tells the recv routine to recv the entire buffer
+ RECV_MODE_FULL_BUFF = 0,
+ //! Tells the recv routine to return after one packet
+ RECV_MODE_ONE_PACKET = 1
+ };
+
+ /*!
* Send a buffer containing IF data with its metadata.
*
* Send handles fragmentation as follows:
- * If the buffer has more samples than the maximum supported,
- * the send method will send the maximum number of samples
- * as supported by the transport and return the number sent.
- * In this case, the end of burst flag will be forced to false.
- * It is up to the caller to call send again on the un-sent
- * portions of the buffer, until the buffer is exhausted.
+ * If the buffer has more samples than the maximum per packet,
+ * the send method will fragment the samples across several packets.
+ * Send will respect the burst flags when fragmenting to ensure
+ * that start of burst can only be set on the first fragment and
+ * that end of burst can only be set on the final fragment.
+ * Fragmentation only applies in the full buffer send mode.
*
* This is a blocking call and will not return until the number
* of samples returned have been read out of the buffer.
@@ -93,12 +113,14 @@ public:
* \param buff a buffer pointing to some read-only memory
* \param metadata data describing the buffer's contents
* \param io_type the type of data loaded in the buffer
+ * \param send_mode tells send how to unload the buffer
* \return the number of samples sent
*/
virtual size_t send(
const boost::asio::const_buffer &buff,
const tx_metadata_t &metadata,
- const io_type_t &io_type
+ const io_type_t &io_type,
+ send_mode_t send_mode
) = 0;
/*!
@@ -123,16 +145,35 @@ public:
* immediately when no packets are available to the transport layer,
* and that the timeout duration is reasonably tuned for performance.
*
+ * When using the full buffer recv mode, the metadata only applies
+ * to the first packet received and written into the recv buffer.
+ * Use the one packet recv mode to get per packet metadata.
+ *
* \param buff the buffer to fill with IF data
* \param metadata data to fill describing the buffer
* \param io_type the type of data to fill into the buffer
+ * \param recv_mode tells recv how to load the buffer
* \return the number of samples received
*/
virtual size_t recv(
const boost::asio::mutable_buffer &buff,
rx_metadata_t &metadata,
- const io_type_t &io_type
+ const io_type_t &io_type,
+ recv_mode_t recv_mode
) = 0;
+
+ /*!
+ * Get the maximum number of samples per packet on send.
+ * \return the number of samples
+ */
+ virtual size_t get_max_send_samps_per_packet(void) const = 0;
+
+ /*!
+ * Get the maximum number of samples per packet on recv.
+ * \return the number of samples
+ */
+ virtual size_t get_max_recv_samps_per_packet(void) const = 0;
+
};
} //namespace uhd
diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp
index 4fc1df9de..52c6d4143 100644
--- a/host/include/uhd/transport/zero_copy.hpp
+++ b/host/include/uhd/transport/zero_copy.hpp
@@ -35,17 +35,18 @@ public:
typedef boost::shared_ptr<managed_recv_buffer> sptr;
/*!
+ * Managed recv buffer destructor:
* Signal to the transport that we are done with the buffer.
* This should be called to release the buffer to the transport.
* After calling, the referenced memory should be considered invalid.
*/
- virtual void done(void) = 0;
+ virtual ~managed_recv_buffer(void){};
/*!
* Get the size of the underlying buffer.
* \return the number of bytes
*/
- size_t size(void){
+ size_t size(void) const{
return boost::asio::buffer_size(this->get());
}
@@ -53,7 +54,7 @@ public:
* Get a pointer to the underlying buffer.
* \return a pointer into memory
*/
- template <class T> T cast(void){
+ template <class T> T cast(void) const{
return boost::asio::buffer_cast<T>(this->get());
}
@@ -63,7 +64,7 @@ private:
* The buffer has a reference to memory and a size.
* \return a boost asio const buffer
*/
- virtual const boost::asio::const_buffer &get(void) = 0;
+ virtual const boost::asio::const_buffer &get(void) const = 0;
};
/*!
@@ -81,13 +82,13 @@ public:
* After calling, the referenced memory should be considered invalid.
* \param num_bytes the number of bytes written into the buffer
*/
- virtual void done(size_t num_bytes) = 0;
+ virtual void commit(size_t num_bytes) = 0;
/*!
* Get the size of the underlying buffer.
* \return the number of bytes
*/
- size_t size(void){
+ size_t size(void) const{
return boost::asio::buffer_size(this->get());
}
@@ -95,7 +96,7 @@ public:
* Get a pointer to the underlying buffer.
* \return a pointer into memory
*/
- template <class T> T cast(void){
+ template <class T> T cast(void) const{
return boost::asio::buffer_cast<T>(this->get());
}
@@ -105,7 +106,7 @@ private:
* The buffer has a reference to memory and a size.
* \return a boost asio mutable buffer
*/
- virtual const boost::asio::mutable_buffer &get(void) = 0;
+ virtual const boost::asio::mutable_buffer &get(void) const = 0;
};
/*!
diff --git a/host/include/uhd/types/dict.hpp b/host/include/uhd/types/dict.hpp
index b5fb11120..50a2b5c3b 100644
--- a/host/include/uhd/types/dict.hpp
+++ b/host/include/uhd/types/dict.hpp
@@ -46,7 +46,7 @@ namespace uhd{
* \param first the begin iterator
* \param last the end iterator
*/
- template <class InputIterator>
+ template <typename InputIterator>
dict(InputIterator first, InputIterator last){
for(InputIterator it = first; it != last; it++){
_map.push_back(*it);
diff --git a/host/include/uhd/types/mac_addr.hpp b/host/include/uhd/types/mac_addr.hpp
index 3cd1fe86b..0ced2e734 100644
--- a/host/include/uhd/types/mac_addr.hpp
+++ b/host/include/uhd/types/mac_addr.hpp
@@ -19,7 +19,7 @@
#define INCLUDED_UHD_TYPES_MAC_ADDR_HPP
#include <uhd/config.hpp>
-#include <boost/cstdint.hpp>
+#include <uhd/types/serial.hpp>
#include <string>
namespace uhd{
@@ -30,14 +30,12 @@ namespace uhd{
*/
class UHD_API mac_addr_t{
public:
- static const size_t hlen = 6;
-
/*!
* Create a mac address a byte array.
- * \param bytes a pointer for the byte array
+ * \param bytes a vector of bytes
* \return a new mac address
*/
- static mac_addr_t from_bytes(const boost::uint8_t *bytes);
+ static mac_addr_t from_bytes(const byte_vector_t &bytes);
/*!
* Create a mac address from a string.
@@ -48,9 +46,9 @@ namespace uhd{
/*!
* Get the byte representation of the mac address.
- * \return a pointer to the internal byte array
+ * \return a vector of bytes
*/
- const boost::uint8_t *to_bytes(void) const;
+ byte_vector_t to_bytes(void) const;
/*!
* Get the string representation of this mac address.
@@ -59,8 +57,8 @@ namespace uhd{
std::string to_string(void) const;
private:
- mac_addr_t(const boost::uint8_t *bytes); //private constructor
- boost::uint8_t _bytes[hlen]; //internal representation
+ mac_addr_t(const byte_vector_t &bytes); //private constructor
+ const byte_vector_t _bytes; //internal representation
};
} //namespace uhd
diff --git a/host/include/uhd/types/otw_type.hpp b/host/include/uhd/types/otw_type.hpp
index f10664584..8e3e65d78 100644
--- a/host/include/uhd/types/otw_type.hpp
+++ b/host/include/uhd/types/otw_type.hpp
@@ -55,6 +55,12 @@ namespace uhd{
BO_NOT_APPLICABLE = '|'
} byteorder;
+ /*!
+ * Get the sample size of this otw type.
+ * \return the size of a sample in bytes
+ */
+ size_t get_sample_size(void) const;
+
otw_type_t(void);
};
diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp
index 1214a1a2f..7ecfcd3c0 100644
--- a/host/include/uhd/usrp/dboard_iface.hpp
+++ b/host/include/uhd/usrp/dboard_iface.hpp
@@ -68,19 +68,29 @@ public:
virtual float read_aux_adc(unit_t unit, int which_adc) = 0;
/*!
+ * Set a daughterboard output pin control source.
+ * By default, the outputs are all GPIO controlled.
+ *
+ * \param unit which unit rx or tx
+ * \param value 16-bits, 0=GPIO controlled, 1=ATR controlled
+ */
+ virtual void set_pin_ctrl(unit_t unit, boost::uint16_t value) = 0;
+
+ /*!
* Set a daughterboard ATR register.
*
* \param unit which unit rx or tx
* \param reg which ATR register to set
- * \param value 16-bits, 0=FPGA output low, 1=FPGA output high
+ * \param value 16-bits, 0=ATR output low, 1=ATR output high
*/
virtual void set_atr_reg(unit_t unit, atr_reg_t reg, boost::uint16_t value) = 0;
/*!
* Set daughterboard GPIO data direction register.
+ * By default, the GPIO pins are all inputs.
*
* \param unit which unit rx or tx
- * \param value 16-bits, 0=FPGA input, 1=FPGA output
+ * \param value 16-bits, 0=GPIO input, 1=GPIO output
*/
virtual void set_gpio_ddr(unit_t unit, boost::uint16_t value) = 0;
@@ -88,6 +98,14 @@ public:
* Read daughterboard GPIO pin values.
*
* \param unit which unit rx or tx
+ * \param value 16-bits, 0=GPIO output low, 1=GPIO output high
+ */
+ virtual void write_gpio(unit_t unit, boost::uint16_t value) = 0;
+
+ /*!
+ * Read daughterboard GPIO pin values.
+ *
+ * \param unit which unit rx or tx
* \return the value of the gpio unit
*/
virtual boost::uint16_t read_gpio(unit_t unit) = 0;
diff --git a/host/include/uhd/usrp/dboard_props.hpp b/host/include/uhd/usrp/dboard_props.hpp
index 0208a6c2c..4d5c5efbd 100644
--- a/host/include/uhd/usrp/dboard_props.hpp
+++ b/host/include/uhd/usrp/dboard_props.hpp
@@ -30,7 +30,8 @@ namespace uhd{ namespace usrp{
DBOARD_PROP_SUBDEV = 's', //ro, wax::obj
DBOARD_PROP_SUBDEV_NAMES = 'S', //ro, prop_names_t
DBOARD_PROP_USED_SUBDEVS = 'u', //ro, prop_names_t
- DBOARD_PROP_DBOARD_ID = 'i' //rw, dboard_id_t
+ DBOARD_PROP_DBOARD_ID = 'i', //rw, dboard_id_t
+ DBOARD_PROP_DBOARD_IFACE = 'f' //ro, dboard_iface::sptr
//DBOARD_PROP_CODEC //ro, wax::obj //----> not sure, dont have to deal with yet
};
diff --git a/host/include/uhd/usrp/device_props.hpp b/host/include/uhd/usrp/device_props.hpp
index b8f6f5cd4..983bcb672 100644
--- a/host/include/uhd/usrp/device_props.hpp
+++ b/host/include/uhd/usrp/device_props.hpp
@@ -31,9 +31,7 @@ namespace uhd{ namespace usrp{
enum device_prop_t{
DEVICE_PROP_NAME = 'n', //ro, std::string
DEVICE_PROP_MBOARD = 'm', //ro, wax::obj
- DEVICE_PROP_MBOARD_NAMES = 'M', //ro, prop_names_t
- DEVICE_PROP_MAX_RX_SAMPLES = 'r', //ro, size_t
- DEVICE_PROP_MAX_TX_SAMPLES = 't' //ro, size_t
+ DEVICE_PROP_MBOARD_NAMES = 'M' //ro, prop_names_t
};
////////////////////////////////////////////////////////////////////////
diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp
index c4142b4e6..6ba1b90dd 100644
--- a/host/include/uhd/usrp/simple_usrp.hpp
+++ b/host/include/uhd/usrp/simple_usrp.hpp
@@ -112,6 +112,7 @@ public:
virtual double get_rx_rate(void) = 0;
virtual tune_result_t set_rx_freq(double freq) = 0;
+ virtual tune_result_t set_rx_freq(double freq, double lo_off) = 0;
virtual freq_range_t get_rx_freq_range(void) = 0;
virtual void set_rx_gain(float gain) = 0;
@@ -131,6 +132,7 @@ public:
virtual double get_tx_rate(void) = 0;
virtual tune_result_t set_tx_freq(double freq) = 0;
+ virtual tune_result_t set_tx_freq(double freq, double lo_off) = 0;
virtual freq_range_t get_tx_freq_range(void) = 0;
virtual void set_tx_gain(float gain) = 0;
diff --git a/host/include/uhd/utils/algorithm.hpp b/host/include/uhd/utils/algorithm.hpp
index 72b655745..146b56c63 100644
--- a/host/include/uhd/utils/algorithm.hpp
+++ b/host/include/uhd/utils/algorithm.hpp
@@ -26,6 +26,11 @@
*/
namespace std{
+ template<typename RangeSrc, typename RangeDst> inline
+ void copy(const RangeSrc &src, RangeDst &dst){
+ std::copy(boost::begin(src), boost::end(src), boost::begin(dst));
+ }
+
template<typename Range, typename T> inline
bool has(const Range &range, const T &value){
return boost::end(range) != std::find(boost::begin(range), boost::end(range), value);
diff --git a/host/lib/ic_reg_maps/common.py b/host/lib/ic_reg_maps/common.py
index 4aa1ef35e..e27c2816d 100644
--- a/host/lib/ic_reg_maps/common.py
+++ b/host/lib/ic_reg_maps/common.py
@@ -29,30 +29,59 @@ COMMON_TMPL = """\
\#ifndef INCLUDED_$(name.upper())_HPP
\#define INCLUDED_$(name.upper())_HPP
+\#include <uhd/config.hpp>
\#include <boost/cstdint.hpp>
+\#include <stdexcept>
+\#include <set>
-struct $(name)_t{
-
+class $(name)_t{
+public:
#for $reg in $regs
- #if $reg.get_enums()
+ #if $reg.get_enums()
enum $reg.get_type(){
#for $i, $enum in enumerate($reg.get_enums())
#set $end_comma = ',' if $i < len($reg.get_enums())-1 else ''
$(reg.get_name().upper())_$(enum[0].upper()) = $enum[1]$end_comma
#end for
};
- #end if
+ #end if
$reg.get_type() $reg.get_name();
#end for
$(name)_t(void){
- #for $reg in $regs
+ _state = NULL;
+ #for $reg in $regs
$reg.get_name() = $reg.get_default();
- #end for
+ #end for
+ }
+
+ ~$(name)_t(void){
+ delete _state;
}
$body
+ void save_state(void){
+ if (_state == NULL) _state = new $(name)_t();
+ #for $reg in $regs
+ _state->$reg.get_name() = this->$reg.get_name();
+ #end for
+ }
+
+ template<typename T> std::set<T> get_changed_addrs(void){
+ if (_state == NULL) throw std::runtime_error("no saved state");
+ //check each register for changes
+ std::set<T> addrs;
+ #for $reg in $regs
+ if(_state->$reg.get_name() != this->$reg.get_name()){
+ addrs.insert($reg.get_addr());
+ }
+ #end for
+ return addrs;
+ }
+
+private:
+ $(name)_t *_state;
};
\#endif /* INCLUDED_$(name.upper())_HPP */
diff --git a/host/lib/ic_reg_maps/gen_ad9777_regs.py b/host/lib/ic_reg_maps/gen_ad9777_regs.py
index abb839f0f..690b15e24 100755
--- a/host/lib/ic_reg_maps/gen_ad9777_regs.py
+++ b/host/lib/ic_reg_maps/gen_ad9777_regs.py
@@ -59,7 +59,7 @@ pll_divide_ratio 3[0:1] 0 div1, div2, div4, div8
## address 4
########################################################################
pll_state 4[7] 0 off, on
-auto_cp_control 4[6] 0 dis, enb
+auto_cp_control 4[6] 0 auto, manual
pll_cp_control 4[0:2] 0 50ua=0, 100ua=1, 200ua=2, 400ua=3, 800ua=7
########################################################################
## address 5 and 9
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt
index a36f0fc03..ed8c35225 100644
--- a/host/lib/transport/CMakeLists.txt
+++ b/host/lib/transport/CMakeLists.txt
@@ -49,4 +49,5 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_SOURCE_DIR}/lib/transport/if_addrs.cpp
${CMAKE_SOURCE_DIR}/lib/transport/udp_simple.cpp
${CMAKE_SOURCE_DIR}/lib/transport/udp_zero_copy_asio.cpp
+ ${CMAKE_SOURCE_DIR}/lib/transport/vrt_packet_handler.hpp
)
diff --git a/host/lib/transport/convert_types.cpp b/host/lib/transport/convert_types.cpp
index 8c3d6b17a..43503025a 100644
--- a/host/lib/transport/convert_types.cpp
+++ b/host/lib/transport/convert_types.cpp
@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include <uhd/config.hpp>
#include <uhd/transport/convert_types.hpp>
#include <uhd/utils/assert.hpp>
#include <boost/asio.hpp> //endianness conversion
@@ -49,7 +50,7 @@ static const bool is_big_endian = true;
static const bool is_big_endian = false;
#endif
-static inline void host_floats_to_usrp2_items(
+static UHD_INLINE void host_floats_to_usrp2_items(
boost::uint32_t *usrp2_items,
const fc32_t *host_floats,
size_t num_samps
@@ -62,7 +63,7 @@ static inline void host_floats_to_usrp2_items(
unrolled_loop(host_floats_to_usrp2_items_i, num_samps);
}
-static inline void usrp2_items_to_host_floats(
+static UHD_INLINE void usrp2_items_to_host_floats(
fc32_t *host_floats,
const boost::uint32_t *usrp2_items,
size_t num_samps
@@ -76,7 +77,7 @@ static inline void usrp2_items_to_host_floats(
unrolled_loop(usrp2_items_to_host_floats_i, num_samps);
}
-static inline void host_items_to_usrp2_items(
+static UHD_INLINE void host_items_to_usrp2_items(
boost::uint32_t *usrp2_items,
const boost::uint32_t *host_items,
size_t num_samps
@@ -90,7 +91,7 @@ static inline void host_items_to_usrp2_items(
}
}
-static inline void usrp2_items_to_host_items(
+static UHD_INLINE void usrp2_items_to_host_items(
boost::uint32_t *host_items,
const boost::uint32_t *usrp2_items,
size_t num_samps
@@ -115,10 +116,13 @@ void transport::convert_io_type_to_otw_type(
switch(io_type.tid){
case io_type_t::COMPLEX_FLOAT32:
host_floats_to_usrp2_items((boost::uint32_t *)otw_buff, (const fc32_t*)io_buff, num_samps);
- break;
+ return;
case io_type_t::COMPLEX_INT16:
host_items_to_usrp2_items((boost::uint32_t *)otw_buff, (const boost::uint32_t*)io_buff, num_samps);
- break;
+ return;
+ case io_type_t::CUSTOM_TYPE:
+ std::memcpy(otw_buff, io_buff, num_samps*io_type.size);
+ return;
default:
throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid));
}
@@ -135,10 +139,13 @@ void transport::convert_otw_type_to_io_type(
switch(io_type.tid){
case io_type_t::COMPLEX_FLOAT32:
usrp2_items_to_host_floats((fc32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps);
- break;
+ return;
case io_type_t::COMPLEX_INT16:
usrp2_items_to_host_items((boost::uint32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps);
- break;
+ return;
+ case io_type_t::CUSTOM_TYPE:
+ std::memcpy(io_buff, otw_buff, num_samps*io_type.size);
+ return;
default:
throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid));
}
diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py
index 9a57c83c3..c34ffb198 100755
--- a/host/lib/transport/gen_vrt.py
+++ b/host/lib/transport/gen_vrt.py
@@ -57,7 +57,7 @@ void vrt::pack(
size_t packet_count, //input
double tick_rate //input
){
- boost::uint32_t vrt_hdr_flags;
+ boost::uint32_t vrt_hdr_flags = 0;
boost::uint8_t pred = 0;
if (metadata.has_stream_id) pred |= $hex($sid_p);
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp
index ee44803f4..f8a222475 100644
--- a/host/lib/transport/udp_zero_copy_asio.cpp
+++ b/host/lib/transport/udp_zero_copy_asio.cpp
@@ -16,75 +16,69 @@
//
#include <uhd/transport/udp_zero_copy.hpp>
+#include <uhd/utils/assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/asio.hpp>
-#include <boost/thread.hpp>
#include <boost/format.hpp>
#include <iostream>
using namespace uhd::transport;
/***********************************************************************
+ * Constants
+ **********************************************************************/
+static const size_t MIN_SOCK_BUFF_SIZE = size_t(100e3);
+static const size_t MAX_DGRAM_SIZE = 2048; //assume max size on send and recv
+static const double RECV_TIMEOUT = 0.1; // 100 ms
+
+/***********************************************************************
* Managed receive buffer implementation for udp zero-copy asio:
- * Frees the memory held by the const buffer on done.
**********************************************************************/
class managed_recv_buffer_impl : public managed_recv_buffer{
public:
managed_recv_buffer_impl(const boost::asio::const_buffer &buff) : _buff(buff){
- _done = false;
+ /* NOP */
}
~managed_recv_buffer_impl(void){
- if (not _done) this->done();
- }
-
- void done(void){
- _done = true;
- delete [] boost::asio::buffer_cast<const boost::uint32_t *>(_buff);
+ delete [] this->cast<const boost::uint8_t *>();
}
private:
- const boost::asio::const_buffer &get(void){
+ const boost::asio::const_buffer &get(void) const{
return _buff;
}
const boost::asio::const_buffer _buff;
- bool _done;
};
/***********************************************************************
* Managed send buffer implementation for udp zero-copy asio:
- * Sends and frees the memory held by the mutable buffer on done.
**********************************************************************/
class managed_send_buffer_impl : public managed_send_buffer{
public:
managed_send_buffer_impl(
const boost::asio::mutable_buffer &buff,
boost::asio::ip::udp::socket *socket
- ) : _buff(buff){
- _done = false;
- _socket = socket;
+ ) : _buff(buff), _socket(socket){
+ /* NOP */
}
~managed_send_buffer_impl(void){
- if (not _done) this->done(0);
+ /* NOP */
}
- void done(size_t num_bytes){
- _done = true;
- boost::uint32_t *mem = boost::asio::buffer_cast<boost::uint32_t *>(_buff);
- _socket->send(boost::asio::buffer(mem, num_bytes));
- delete [] mem;
+ void commit(size_t num_bytes){
+ _socket->send(boost::asio::buffer(_buff, num_bytes));
}
private:
- const boost::asio::mutable_buffer &get(void){
+ const boost::asio::mutable_buffer &get(void) const{
return _buff;
}
const boost::asio::mutable_buffer _buff;
boost::asio::ip::udp::socket *_socket;
- bool _done;
};
/***********************************************************************
@@ -96,6 +90,8 @@ private:
**********************************************************************/
class udp_zero_copy_impl : public udp_zero_copy{
public:
+ typedef boost::shared_ptr<udp_zero_copy_impl> sptr;
+
//structors
udp_zero_copy_impl(const std::string &addr, const std::string &port);
~udp_zero_copy_impl(void);
@@ -104,23 +100,27 @@ public:
managed_recv_buffer::sptr get_recv_buff(void);
managed_send_buffer::sptr get_send_buff(void);
- //resize
- size_t resize_recv_buff(size_t num_bytes){
- boost::asio::socket_base::receive_buffer_size option(num_bytes);
- _socket->set_option(option);
+ //manage buffer
+ template <typename Opt> size_t get_buff_size(void){
+ Opt option;
_socket->get_option(option);
return option.value();
}
- size_t resize_send_buff(size_t num_bytes){
- boost::asio::socket_base::send_buffer_size option(num_bytes);
+
+ template <typename Opt> size_t resize_buff(size_t num_bytes){
+ Opt option(num_bytes);
_socket->set_option(option);
- _socket->get_option(option);
- return option.value();
+ return get_buff_size<Opt>();
}
private:
boost::asio::ip::udp::socket *_socket;
boost::asio::io_service _io_service;
+
+ //send and recv buffer memory (allocated once)
+ boost::uint8_t _send_mem[MIN_SOCK_BUFF_SIZE];
+
+ managed_send_buffer::sptr _send_buff;
};
udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){
@@ -131,10 +131,25 @@ udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::strin
boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port);
boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
- // Create, open, and connect the socket
+ // create, open, and connect the socket
_socket = new boost::asio::ip::udp::socket(_io_service);
_socket->open(boost::asio::ip::udp::v4());
_socket->connect(receiver_endpoint);
+
+ // create the managed send buff (just once)
+ _send_buff = managed_send_buffer::sptr(new managed_send_buffer_impl(
+ boost::asio::buffer(_send_mem, MIN_SOCK_BUFF_SIZE), _socket
+ ));
+
+ // set recv timeout
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = size_t(RECV_TIMEOUT*1e6);
+ UHD_ASSERT_THROW(setsockopt(
+ _socket->native(),
+ SOL_SOCKET, SO_RCVTIMEO,
+ (const char *)&tv, sizeof(timeval)
+ ) == 0);
}
udp_zero_copy_impl::~udp_zero_copy_impl(void){
@@ -142,61 +157,56 @@ udp_zero_copy_impl::~udp_zero_copy_impl(void){
}
managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){
- //implement timeout through polling and sleeping
- size_t available = 0;
- boost::asio::deadline_timer timer(_socket->get_io_service());
- timer.expires_from_now(boost::posix_time::milliseconds(100));
- while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){
- boost::this_thread::sleep(boost::posix_time::milliseconds(1));
- }
+ //allocate memory
+ boost::uint8_t *recv_mem = new boost::uint8_t[MAX_DGRAM_SIZE];
- //receive only if data is available
- boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)];
- if (available){
- available = _socket->receive(boost::asio::buffer(buff_mem, available));
- }
+ //call recv() with timeout option
+ size_t num_bytes = _socket->receive(boost::asio::buffer(recv_mem, MIN_SOCK_BUFF_SIZE));
//create a new managed buffer to house the data
return managed_recv_buffer::sptr(
- new managed_recv_buffer_impl(boost::asio::buffer(buff_mem, available))
+ new managed_recv_buffer_impl(boost::asio::buffer(recv_mem, num_bytes))
);
}
managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){
- boost::uint32_t *buff_mem = new boost::uint32_t[2000/sizeof(boost::uint32_t)];
- return managed_send_buffer::sptr(
- new managed_send_buffer_impl(boost::asio::buffer(buff_mem, 2000), _socket)
- );
+ return _send_buff; //FIXME there is only ever one send buff, we assume that the caller doesnt hang onto these
}
/***********************************************************************
* UDP zero copy make function
**********************************************************************/
+template<typename Opt> static inline void resize_buff_helper(
+ udp_zero_copy_impl::sptr udp_trans,
+ size_t target_size,
+ const std::string &name
+){
+ //resize the buffer if size was provided
+ if (target_size > 0){
+ size_t actual_size = udp_trans->resize_buff<Opt>(target_size);
+ if (target_size != actual_size) std::cout << boost::format(
+ "Target %s buffer size: %d\n"
+ "Actual %s byffer size: %d"
+ ) % name % target_size % name % actual_size << std::endl;
+ }
+
+ //otherwise, ensure that the buffer is at least the minimum size
+ else if (udp_trans->get_buff_size<Opt>() < MIN_SOCK_BUFF_SIZE){
+ resize_buff_helper<Opt>(udp_trans, MIN_SOCK_BUFF_SIZE, name);
+ }
+}
+
udp_zero_copy::sptr udp_zero_copy::make(
const std::string &addr,
const std::string &port,
size_t recv_buff_size,
size_t send_buff_size
){
- boost::shared_ptr<udp_zero_copy_impl> udp_trans(new udp_zero_copy_impl(addr, port));
-
- //resize the recv buffer if size was provided
- if (recv_buff_size > 0){
- size_t actual_bytes = udp_trans->resize_recv_buff(recv_buff_size);
- if (recv_buff_size != actual_bytes) std::cout << boost::format(
- "Target recv buffer size: %d\n"
- "Actual recv byffer size: %d"
- ) % recv_buff_size % actual_bytes << std::endl;
- }
+ udp_zero_copy_impl::sptr udp_trans(new udp_zero_copy_impl(addr, port));
- //resize the send buffer if size was provided
- if (send_buff_size > 0){
- size_t actual_bytes = udp_trans->resize_send_buff(send_buff_size);
- if (send_buff_size != actual_bytes) std::cout << boost::format(
- "Target send buffer size: %d\n"
- "Actual send byffer size: %d"
- ) % send_buff_size % actual_bytes << std::endl;
- }
+ //call the helper to resize send and recv buffers
+ resize_buff_helper<boost::asio::socket_base::receive_buffer_size>(udp_trans, recv_buff_size, "recv");
+ resize_buff_helper<boost::asio::socket_base::send_buffer_size> (udp_trans, send_buff_size, "send");
return udp_trans;
}
diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp
new file mode 100644
index 000000000..e64e3383d
--- /dev/null
+++ b/host/lib/transport/vrt_packet_handler.hpp
@@ -0,0 +1,370 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP
+#define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/device.hpp>
+#include <uhd/types/io_type.hpp>
+#include <uhd/types/otw_type.hpp>
+#include <uhd/types/metadata.hpp>
+#include <uhd/transport/vrt.hpp>
+#include <uhd/transport/convert_types.hpp>
+#include <uhd/transport/zero_copy.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/function.hpp>
+#include <stdexcept>
+#include <iostream>
+
+namespace vrt_packet_handler{
+
+/***********************************************************************
+ * vrt packet handler for recv
+ **********************************************************************/
+ struct recv_state{
+ //init the expected seq number
+ size_t next_packet_seq;
+
+ //state variables to handle fragments
+ uhd::transport::managed_recv_buffer::sptr managed_buff;
+ boost::asio::const_buffer copy_buff;
+ size_t fragment_offset_in_samps;
+
+ recv_state(void){
+ //first expected seq is zero
+ next_packet_seq = 0;
+
+ //initially empty copy buffer
+ copy_buff = boost::asio::buffer("", 0);
+ }
+ };
+
+ typedef boost::function<void(uhd::transport::managed_recv_buffer::sptr)> recv_cb_t;
+
+ static UHD_INLINE void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){
+ /* NOP */
+ }
+
+ /*******************************************************************
+ * Unpack a received vrt header and set the copy buffer.
+ * - helper function for vrt_packet_handler::_recv1
+ ******************************************************************/
+ static UHD_INLINE void _recv1_helper(
+ recv_state &state,
+ uhd::rx_metadata_t &metadata,
+ double tick_rate,
+ size_t vrt_header_offset_words32
+ ){
+ size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t);
+ if (num_packet_words32 <= vrt_header_offset_words32){
+ state.copy_buff = boost::asio::buffer("", 0);
+ return; //must exit here after setting the buffer
+ }
+ const boost::uint32_t *vrt_hdr = state.managed_buff->cast<const boost::uint32_t *>() + vrt_header_offset_words32;
+ size_t num_header_words32_out, num_payload_words32_out, packet_count_out;
+ uhd::transport::vrt::unpack(
+ metadata, //output
+ vrt_hdr, //input
+ num_header_words32_out, //output
+ num_payload_words32_out, //output
+ num_packet_words32, //input
+ packet_count_out, //output
+ tick_rate
+ );
+
+ //handle the packet count / sequence number
+ if (packet_count_out != state.next_packet_seq){
+ std::cerr << "S" << (packet_count_out - state.next_packet_seq)%16;
+ }
+ state.next_packet_seq = (packet_count_out+1)%16;
+
+ //setup the buffer to point to the data
+ state.copy_buff = boost::asio::buffer(
+ vrt_hdr + num_header_words32_out,
+ num_payload_words32_out*sizeof(boost::uint32_t)
+ );
+ }
+
+ /*******************************************************************
+ * Recv data, unpack a vrt header, and copy-convert the data.
+ * - helper function for vrt_packet_handler::recv
+ ******************************************************************/
+ static UHD_INLINE size_t _recv1(
+ recv_state &state,
+ void *recv_mem,
+ size_t total_samps,
+ uhd::rx_metadata_t &metadata,
+ const uhd::io_type_t &io_type,
+ const uhd::otw_type_t &otw_type,
+ double tick_rate,
+ uhd::transport::zero_copy_if::sptr zc_iface,
+ //use these two params to handle a layer above vrt
+ size_t vrt_header_offset_words32,
+ const recv_cb_t& recv_cb
+ ){
+ //perform a receive if no rx data is waiting to be copied
+ if (boost::asio::buffer_size(state.copy_buff) == 0){
+ state.fragment_offset_in_samps = 0;
+ state.managed_buff = zc_iface->get_recv_buff();
+ recv_cb(state.managed_buff); //callback before vrt unpack
+ try{
+ _recv1_helper(
+ state, metadata, tick_rate, vrt_header_offset_words32
+ );
+ }catch(const std::exception &e){
+ std::cerr << "Error (recv): " << e.what() << std::endl;
+ return 0;
+ }
+ }
+
+ //extract the number of samples available to copy
+ size_t bytes_per_item = otw_type.get_sample_size();
+ size_t bytes_available = boost::asio::buffer_size(state.copy_buff);
+ size_t num_samps = std::min(total_samps, bytes_available/bytes_per_item);
+
+ //setup the fragment flags and offset
+ metadata.more_fragments = total_samps < num_samps;
+ metadata.fragment_offset = state.fragment_offset_in_samps;
+ state.fragment_offset_in_samps += num_samps; //set for next call
+
+ //copy-convert the samples from the recv buffer
+ uhd::transport::convert_otw_type_to_io_type(
+ boost::asio::buffer_cast<const void*>(state.copy_buff), otw_type,
+ recv_mem, io_type, num_samps
+ );
+
+ //update the rx copy buffer to reflect the bytes copied
+ size_t bytes_copied = num_samps*bytes_per_item;
+ state.copy_buff = boost::asio::buffer(
+ boost::asio::buffer_cast<const boost::uint8_t*>(state.copy_buff) + bytes_copied,
+ bytes_available - bytes_copied
+ );
+
+ return num_samps;
+ }
+
+ /*******************************************************************
+ * Recv vrt packets and copy convert the samples into the buffer.
+ ******************************************************************/
+ static UHD_INLINE size_t recv(
+ recv_state &state,
+ const boost::asio::mutable_buffer &buff,
+ uhd::rx_metadata_t &metadata,
+ uhd::device::recv_mode_t recv_mode,
+ const uhd::io_type_t &io_type,
+ const uhd::otw_type_t &otw_type,
+ double tick_rate,
+ uhd::transport::zero_copy_if::sptr zc_iface,
+ //use these two params to handle a layer above vrt
+ size_t vrt_header_offset_words32 = 0,
+ const recv_cb_t& recv_cb = &recv_cb_nop
+ ){
+ metadata = uhd::rx_metadata_t(); //init the metadata
+ const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size;
+
+ switch(recv_mode){
+
+ ////////////////////////////////////////////////////////////////
+ case uhd::device::RECV_MODE_ONE_PACKET:{
+ ////////////////////////////////////////////////////////////////
+ return _recv1(
+ state,
+ boost::asio::buffer_cast<void *>(buff),
+ total_num_samps,
+ metadata,
+ io_type, otw_type,
+ tick_rate,
+ zc_iface,
+ vrt_header_offset_words32,
+ recv_cb
+ );
+ }
+
+ ////////////////////////////////////////////////////////////////
+ case uhd::device::RECV_MODE_FULL_BUFF:{
+ ////////////////////////////////////////////////////////////////
+ size_t accum_num_samps = 0;
+ uhd::rx_metadata_t tmp_md;
+ while(accum_num_samps < total_num_samps){
+ size_t num_samps = _recv1(
+ state,
+ boost::asio::buffer_cast<boost::uint8_t *>(buff) + (accum_num_samps*io_type.size),
+ total_num_samps - accum_num_samps,
+ (accum_num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept
+ io_type, otw_type,
+ tick_rate,
+ zc_iface,
+ vrt_header_offset_words32,
+ recv_cb
+ );
+ if (num_samps == 0) break; //had a recv timeout or error, break loop
+ accum_num_samps += num_samps;
+ }
+ return accum_num_samps;
+ }
+
+ default: throw std::runtime_error("unknown recv mode");
+ }//switch(recv_mode)
+ }
+
+/***********************************************************************
+ * vrt packet handler for send
+ **********************************************************************/
+ struct send_state{
+ //init the expected seq number
+ size_t next_packet_seq;
+
+ send_state(void){
+ next_packet_seq = 0;
+ }
+ };
+
+ typedef boost::function<void(uhd::transport::managed_send_buffer::sptr)> send_cb_t;
+
+ static UHD_INLINE void send_cb_nop(uhd::transport::managed_send_buffer::sptr){
+ /* NOP */
+ }
+
+ /*******************************************************************
+ * Pack a vrt header, copy-convert the data, and send it.
+ * - helper function for vrt_packet_handler::send
+ ******************************************************************/
+ static UHD_INLINE void _send1(
+ send_state &state,
+ const void *send_mem,
+ size_t num_samps,
+ const uhd::tx_metadata_t &metadata,
+ const uhd::io_type_t &io_type,
+ const uhd::otw_type_t &otw_type,
+ double tick_rate,
+ uhd::transport::zero_copy_if::sptr zc_iface,
+ size_t vrt_header_offset_words32,
+ const send_cb_t& send_cb
+ ){
+ //get a new managed send buffer
+ uhd::transport::managed_send_buffer::sptr send_buff = zc_iface->get_send_buff();
+ boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>() + vrt_header_offset_words32;
+
+ size_t num_header_words32, num_packet_words32;
+ size_t packet_count = state.next_packet_seq++;
+
+ //pack metadata into a vrt header
+ uhd::transport::vrt::pack(
+ metadata, //input
+ tx_mem, //output
+ num_header_words32, //output
+ num_samps, //input
+ num_packet_words32, //output
+ packet_count, //input
+ tick_rate
+ );
+
+ //copy-convert the samples into the send buffer
+ uhd::transport::convert_io_type_to_otw_type(
+ send_mem, io_type,
+ tx_mem + num_header_words32, otw_type,
+ num_samps
+ );
+
+ send_cb(send_buff); //callback after memory filled
+
+ //commit the samples to the zero-copy interface
+ send_buff->commit(num_packet_words32*sizeof(boost::uint32_t));
+ }
+
+ /*******************************************************************
+ * Send vrt packets and copy convert the samples into the buffer.
+ ******************************************************************/
+ static UHD_INLINE size_t send(
+ send_state &state,
+ const boost::asio::const_buffer &buff,
+ const uhd::tx_metadata_t &metadata,
+ uhd::device::send_mode_t send_mode,
+ const uhd::io_type_t &io_type,
+ const uhd::otw_type_t &otw_type,
+ double tick_rate,
+ uhd::transport::zero_copy_if::sptr zc_iface,
+ size_t max_samples_per_packet,
+ //use these two params to handle a layer above vrt
+ size_t vrt_header_offset_words32 = 0,
+ const send_cb_t& send_cb = &send_cb_nop
+ ){
+ const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size;
+ if (total_num_samps <= max_samples_per_packet) send_mode = uhd::device::SEND_MODE_ONE_PACKET;
+ switch(send_mode){
+
+ ////////////////////////////////////////////////////////////////
+ case uhd::device::SEND_MODE_ONE_PACKET:{
+ ////////////////////////////////////////////////////////////////
+ size_t num_samps = std::min(total_num_samps, max_samples_per_packet);
+ _send1(
+ state,
+ boost::asio::buffer_cast<const void *>(buff),
+ num_samps,
+ metadata,
+ io_type, otw_type,
+ tick_rate,
+ zc_iface,
+ vrt_header_offset_words32,
+ send_cb
+ );
+ return num_samps;
+ }
+
+ ////////////////////////////////////////////////////////////////
+ case uhd::device::SEND_MODE_FULL_BUFF:{
+ ////////////////////////////////////////////////////////////////
+ //calculate constants for fragmentation
+ const size_t num_fragments = (total_num_samps+max_samples_per_packet-1)/max_samples_per_packet;
+ static const size_t first_fragment_index = 0;
+ const size_t final_fragment_index = num_fragments-1;
+
+ //make a rw copy of the metadata to re-flag below
+ uhd::tx_metadata_t md(metadata);
+
+ //loop through the following fragment indexes
+ for (size_t n = first_fragment_index; n <= final_fragment_index; n++){
+
+ //calculate new flags for the fragments
+ md.has_time_spec = metadata.has_time_spec and (n == first_fragment_index);
+ md.start_of_burst = metadata.start_of_burst and (n == first_fragment_index);
+ md.end_of_burst = metadata.end_of_burst and (n == final_fragment_index);
+
+ //send the fragment with the helper function
+ _send1(
+ state,
+ boost::asio::buffer_cast<const boost::uint8_t *>(buff) + (n*max_samples_per_packet*io_type.size),
+ (n == final_fragment_index)?(total_num_samps%max_samples_per_packet):max_samples_per_packet,
+ md,
+ io_type, otw_type,
+ tick_rate,
+ zc_iface,
+ vrt_header_offset_words32,
+ send_cb
+ );
+ }
+ return total_num_samps;
+ }
+
+ default: throw std::runtime_error("unknown send mode");
+ }//switch(send_mode)
+ }
+
+} //namespace vrt_packet_handler
+
+#endif /* INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP */
diff --git a/host/lib/types.cpp b/host/lib/types.cpp
index ec9c8ac01..daf3be7f7 100644
--- a/host/lib/types.cpp
+++ b/host/lib/types.cpp
@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include <uhd/utils/assert.hpp>
#include <uhd/types/ranges.hpp>
#include <uhd/types/tune_result.hpp>
#include <uhd/types/clock_config.hpp>
@@ -41,73 +42,89 @@ using namespace uhd;
/***********************************************************************
* ranges
**********************************************************************/
-gain_range_t::gain_range_t(float min_, float max_, float step_){
- min = min_;
- max = max_;
- step = step_;
+gain_range_t::gain_range_t(float min, float max, float step):
+ min(min),
+ max(max),
+ step(step)
+{
+ /* NOP */
}
-freq_range_t::freq_range_t(double min_, double max_){
- min = min_;
- max = max_;
+freq_range_t::freq_range_t(double min, double max):
+ min(min),
+ max(max)
+{
+ /* NOP */
}
/***********************************************************************
* tune result
**********************************************************************/
-tune_result_t::tune_result_t(void){
- target_inter_freq = 0.0;
- actual_inter_freq = 0.0;
- target_dsp_freq = 0.0;
- actual_dsp_freq = 0.0;
- spectrum_inverted = false;
+tune_result_t::tune_result_t(void):
+ target_inter_freq(0.0),
+ actual_inter_freq(0.0),
+ target_dsp_freq(0.0),
+ actual_dsp_freq(0.0),
+ spectrum_inverted(false)
+{
+ /* NOP */
}
/***********************************************************************
* clock config
**********************************************************************/
-clock_config_t::clock_config_t(void){
- ref_source = REF_INT,
- pps_source = PPS_INT,
- pps_polarity = PPS_NEG;
+clock_config_t::clock_config_t(void):
+ ref_source(REF_INT),
+ pps_source(PPS_INT),
+ pps_polarity(PPS_NEG)
+{
+ /* NOP */
}
/***********************************************************************
* stream command
**********************************************************************/
-stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode_){
- stream_mode = stream_mode_;
- stream_now = true;
- num_samps = 0;
+stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode):
+ stream_mode(stream_mode),
+ num_samps(0),
+ stream_now(true)
+{
+ /* NOP */
}
/***********************************************************************
* metadata
**********************************************************************/
-rx_metadata_t::rx_metadata_t(void){
- stream_id = 0;
- has_stream_id = false;
- time_spec = time_spec_t();
- has_time_spec = false;
- more_fragments = false;
- fragment_offset = 0;
+rx_metadata_t::rx_metadata_t(void):
+ has_stream_id(false),
+ stream_id(0),
+ has_time_spec(false),
+ time_spec(time_spec_t()),
+ more_fragments(false),
+ fragment_offset(0)
+{
+ /* NOP */
}
-tx_metadata_t::tx_metadata_t(void){
- stream_id = 0;
- has_stream_id = false;
- time_spec = time_spec_t();
- has_time_spec = false;
- start_of_burst = false;
- end_of_burst = false;
+tx_metadata_t::tx_metadata_t(void):
+ has_stream_id(false),
+ stream_id(0),
+ has_time_spec(false),
+ time_spec(time_spec_t()),
+ start_of_burst(false),
+ end_of_burst(false)
+{
+ /* NOP */
}
/***********************************************************************
* time spec
**********************************************************************/
-time_spec_t::time_spec_t(boost::uint32_t secs_, double nsecs_){
- secs = secs_;
- nsecs = nsecs_;
+time_spec_t::time_spec_t(boost::uint32_t secs, double nsecs):
+ secs(secs),
+ nsecs(nsecs)
+{
+ /* NOP */
}
boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{
@@ -164,17 +181,18 @@ std::string device_addr_t::to_string(void) const{
/***********************************************************************
* mac addr
**********************************************************************/
-mac_addr_t::mac_addr_t(const boost::uint8_t *bytes){
- std::copy(bytes, bytes+hlen, _bytes);
+mac_addr_t::mac_addr_t(const byte_vector_t &bytes) : _bytes(bytes){
+ UHD_ASSERT_THROW(_bytes.size() == 6);
}
-mac_addr_t mac_addr_t::from_bytes(const boost::uint8_t *bytes){
+mac_addr_t mac_addr_t::from_bytes(const byte_vector_t &bytes){
return mac_addr_t(bytes);
}
mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){
- boost::uint8_t p[hlen] = {0x00, 0x50, 0xC2, 0x85, 0x30, 0x00}; // Matt's IAB
+ byte_vector_t bytes = boost::assign::list_of
+ (0x00)(0x50)(0xC2)(0x85)(0x30)(0x00); // Matt's IAB
try{
//only allow patterns of xx:xx or xx:xx:xx:xx:xx:xx
@@ -189,7 +207,7 @@ mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){
int hex_num;
std::istringstream iss(hex_strs[i]);
iss >> std::hex >> hex_num;
- p[i] = boost::uint8_t(hex_num);
+ bytes[i] = boost::uint8_t(hex_num);
}
}
@@ -199,28 +217,34 @@ mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){
));
}
- return from_bytes(p);
+ return mac_addr_t::from_bytes(bytes);
}
-const boost::uint8_t *mac_addr_t::to_bytes(void) const{
+byte_vector_t mac_addr_t::to_bytes(void) const{
return _bytes;
}
std::string mac_addr_t::to_string(void) const{
- return str(
- boost::format("%02x:%02x:%02x:%02x:%02x:%02x")
- % int(to_bytes()[0]) % int(to_bytes()[1]) % int(to_bytes()[2])
- % int(to_bytes()[3]) % int(to_bytes()[4]) % int(to_bytes()[5])
- );
+ std::string addr = "";
+ BOOST_FOREACH(boost::uint8_t byte, this->to_bytes()){
+ addr += str(boost::format("%s%02x") % ((addr == "")?"":":") % int(byte));
+ }
+ return addr;
}
/***********************************************************************
* otw type
**********************************************************************/
-otw_type_t::otw_type_t(void){
- width = 0;
- shift = 0;
- byteorder = BO_NATIVE;
+size_t otw_type_t::get_sample_size(void) const{
+ return (this->width * 2) / 8;
+}
+
+otw_type_t::otw_type_t(void):
+ width(0),
+ shift(0),
+ byteorder(BO_NATIVE)
+{
+ /* NOP */
}
/***********************************************************************
@@ -248,9 +272,11 @@ io_type_t::io_type_t(size_t size)
/***********************************************************************
* serial
**********************************************************************/
-spi_config_t::spi_config_t(edge_t edge){
- mosi_edge = edge;
- miso_edge = edge;
+spi_config_t::spi_config_t(edge_t edge):
+ mosi_edge(edge),
+ miso_edge(edge)
+{
+ /* NOP */
}
void i2c_iface::write_eeprom(
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index bbc9716b1..89e707718 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -15,8 +15,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-static const bool rfx_debug = false;
-
// IO Pin functions
#define POWER_IO (1 << 7) // Low enables power supply
#define ANTSW_IO (1 << 6) // On TX DB, 0 = TX, 1 = RX, on RX DB 0 = main ant, 1 = RX2
@@ -56,10 +54,23 @@ using namespace uhd::usrp;
using namespace boost::assign;
/***********************************************************************
- * The RFX series of dboards
+ * The RFX Series constants
**********************************************************************/
-static const float _max_rx_pga0_gain = 45;
+static const bool rfx_debug = false;
+
+static const prop_names_t rfx_tx_antennas = list_of("TX/RX");
+
+static const prop_names_t rfx_rx_antennas = list_of("TX/RX")("RX2");
+static const uhd::dict<std::string, gain_range_t> rfx_tx_gain_ranges; //empty
+
+static const uhd::dict<std::string, gain_range_t> rfx_rx_gain_ranges = map_list_of
+ ("PGA0", gain_range_t(0, 45, float(0.022)))
+;
+
+/***********************************************************************
+ * The RFX series of dboards
+ **********************************************************************/
class rfx_xcvr : public xcvr_dboard_base{
public:
rfx_xcvr(
@@ -85,6 +96,10 @@ private:
void set_rx_lo_freq(double freq);
void set_tx_lo_freq(double freq);
void set_rx_ant(const std::string &ant);
+ void set_tx_ant(const std::string &ant);
+ void set_rx_gain(float gain, const std::string &name);
+ void set_tx_gain(float gain, const std::string &name);
+
void set_rx_pga0_gain(float gain);
/*!
@@ -161,8 +176,10 @@ rfx_xcvr::rfx_xcvr(
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
+ //set the gpio directions and atr controls (identically)
boost::uint16_t output_enables = POWER_IO | ANTSW_IO | MIXER_IO;
+ this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, output_enables);
+ this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, output_enables);
this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, output_enables);
this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, output_enables);
@@ -189,19 +206,11 @@ rfx_xcvr::~rfx_xcvr(void){
}
/***********************************************************************
- * Helper Methods
+ * Antenna Handling
**********************************************************************/
-void rfx_xcvr::set_rx_lo_freq(double freq){
- _rx_lo_freq = set_lo_freq(dboard_iface::UNIT_RX, freq);
-}
-
-void rfx_xcvr::set_tx_lo_freq(double freq){
- _tx_lo_freq = set_lo_freq(dboard_iface::UNIT_TX, freq);
-}
-
void rfx_xcvr::set_rx_ant(const std::string &ant){
//validate input
- UHD_ASSERT_THROW(ant == "TX/RX" or ant == "RX2");
+ assert_has(rfx_rx_antennas, ant, "rfx rx antenna name");
//set the rx atr regs that change with antenna setting
this->get_iface()->set_atr_reg(
@@ -213,22 +222,51 @@ void rfx_xcvr::set_rx_ant(const std::string &ant){
_rx_ant = ant;
}
-void rfx_xcvr::set_rx_pga0_gain(float gain){
- //clip the input
- gain = std::clip<float>(gain, 0, _max_rx_pga0_gain);
+void rfx_xcvr::set_tx_ant(const std::string &ant){
+ assert_has(rfx_tx_antennas, ant, "rfx tx antenna name");
+ //only one antenna option, do nothing
+}
+
+/***********************************************************************
+ * Gain Handling
+ **********************************************************************/
+void rfx_xcvr::set_tx_gain(float, const std::string &name){
+ assert_has(rfx_tx_gain_ranges.keys(), name, "rfx tx gain name");
+ UHD_ASSERT_THROW(false); //no gains to set
+}
+
+void rfx_xcvr::set_rx_gain(float gain, const std::string &name){
+ assert_has(rfx_rx_gain_ranges.keys(), name, "rfx rx gain name");
+ if(name == "PGA0"){
+ this->set_rx_pga0_gain(gain);
+ }
+ else UHD_ASSERT_THROW(false);
+}
- //voltage level constants
+void rfx_xcvr::set_rx_pga0_gain(float gain){
+ //voltage level constants (negative slope)
static const float max_volts = float(.2), min_volts = float(1.2);
- static const float slope = (max_volts-min_volts)/_max_rx_pga0_gain;
+ static const float slope = (max_volts-min_volts)/45;
//calculate the voltage for the aux dac
- float dac_volts = gain*slope + min_volts;
+ float dac_volts = std::clip<float>(gain*slope + min_volts, max_volts, min_volts);
//write the new voltage to the aux dac
this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, 1, dac_volts);
- //shadow the setting (does not account for precision loss)
- _rx_pga0_gain = gain;
+ //shadow the actual gain setting
+ _rx_pga0_gain = (dac_volts - min_volts)/slope;
+}
+
+/***********************************************************************
+ * Tuning
+ **********************************************************************/
+void rfx_xcvr::set_rx_lo_freq(double freq){
+ _rx_lo_freq = set_lo_freq(dboard_iface::UNIT_RX, freq);
+}
+
+void rfx_xcvr::set_tx_lo_freq(double freq){
+ _tx_lo_freq = set_lo_freq(dboard_iface::UNIT_TX, freq);
}
double rfx_xcvr::set_lo_freq(
@@ -258,8 +296,8 @@ double rfx_xcvr::set_lo_freq(
(8, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_8)
;
- double actual_freq, ref_freq = this->get_iface()->get_clock_rate(unit);
- int R, BS, P, B, A;
+ double actual_freq=0, ref_freq = this->get_iface()->get_clock_rate(unit);
+ int R=0, BS=0, P=0, B=0, A=0;
/*
* The goal here to to loop though possible R dividers,
@@ -364,12 +402,12 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_GAIN_RANGE:
- UHD_ASSERT_THROW(name == "PGA0");
- val = gain_range_t(0, _max_rx_pga0_gain, float(0.022));
+ assert_has(rfx_rx_gain_ranges.keys(), name, "rfx rx gain name");
+ val = rfx_rx_gain_ranges[name];
return;
case SUBDEV_PROP_GAIN_NAMES:
- val = prop_names_t(1, "PGA0");
+ val = prop_names_t(rfx_rx_gain_ranges.keys());
return;
case SUBDEV_PROP_FREQ:
@@ -384,10 +422,8 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
val = _rx_ant;
return;
- case SUBDEV_PROP_ANTENNA_NAMES:{
- prop_names_t ants = list_of("TX/RX")("RX2");
- val = ants;
- }
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = rfx_rx_antennas;
return;
case SUBDEV_PROP_QUADRATURE:
@@ -422,16 +458,15 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_FREQ:
- set_rx_lo_freq(val.as<double>());
+ this->set_rx_lo_freq(val.as<double>());
return;
case SUBDEV_PROP_GAIN:
- UHD_ASSERT_THROW(name == "PGA0");
- set_rx_pga0_gain(val.as<float>());
+ this->set_rx_gain(val.as<float>(), name);
return;
case SUBDEV_PROP_ANTENNA:
- set_rx_ant(val.as<std::string>());
+ this->set_rx_ant(val.as<std::string>());
return;
default: UHD_THROW_PROP_SET_ERROR();
@@ -456,15 +491,13 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- val = float(0);
- return;
-
case SUBDEV_PROP_GAIN_RANGE:
- val = gain_range_t(0, 0, 0);
+ assert_has(rfx_tx_gain_ranges.keys(), name, "rfx tx gain name");
+ //no controllable tx gains, will not get here
return;
case SUBDEV_PROP_GAIN_NAMES:
- val = prop_names_t(); //empty
+ val = prop_names_t(rfx_tx_gain_ranges.keys());
return;
case SUBDEV_PROP_FREQ:
@@ -480,7 +513,7 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_ANTENNA_NAMES:
- val = prop_names_t(1, "TX/RX");
+ val = rfx_tx_antennas;
return;
case SUBDEV_PROP_QUADRATURE:
@@ -515,16 +548,15 @@ void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_FREQ:
- set_tx_lo_freq(val.as<double>());
+ this->set_tx_lo_freq(val.as<double>());
return;
case SUBDEV_PROP_GAIN:
- //no gains to set!
+ this->set_tx_gain(val.as<float>(), name);
return;
case SUBDEV_PROP_ANTENNA:
- //its always set to tx/rx, so we only allow this value
- UHD_ASSERT_THROW(val.as<std::string>() == "TX/RX");
+ this->set_tx_ant(val.as<std::string>());
return;
default: UHD_THROW_PROP_SET_ERROR();
diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp
index 2a8a3a9f2..23654860f 100644
--- a/host/lib/usrp/dboard/db_wbx.cpp
+++ b/host/lib/usrp/dboard/db_wbx.cpp
@@ -164,7 +164,9 @@ wbx_xcvr::wbx_xcvr(
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
+ //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(
@@ -303,7 +305,7 @@ double wbx_xcvr::set_lo_freq(
double actual_freq, pfd_freq;
double ref_freq = this->get_iface()->get_clock_rate(unit);
- int R, BS, N, FRAC, MOD;
+ 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;
diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp
index 3472229f4..d4d5f184e 100644
--- a/host/lib/usrp/dboard/db_xcvr2450.cpp
+++ b/host/lib/usrp/dboard/db_xcvr2450.cpp
@@ -169,7 +169,9 @@ xcvr2450::xcvr2450(ctor_args_t args) : xcvr_dboard_base(args){
//enable only the clocks we need
this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);
- //set the gpio directions
+ //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);
diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp
index 8161727e5..01352039e 100644
--- a/host/lib/usrp/dboard_manager.cpp
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -298,7 +298,8 @@ void dboard_manager_impl::set_nice_dboard_if(void){
//set nice settings on each unit
BOOST_FOREACH(dboard_iface::unit_t unit, units){
_iface->set_gpio_ddr(unit, 0x0000); //all inputs
- _iface->set_atr_reg(unit, dboard_iface::ATR_REG_IDLE, 0x0000); //all low
+ _iface->write_gpio(unit, 0x0000); //all low
+ _iface->set_pin_ctrl(unit, 0x0000); //all gpio
_iface->set_clock_enabled(unit, false); //clock off
}
}
diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp
index a8c104485..f4aa82669 100644
--- a/host/lib/usrp/simple_usrp.cpp
+++ b/host/lib/usrp/simple_usrp.cpp
@@ -121,6 +121,10 @@ public:
return tune_rx_subdev_and_ddc(_rx_subdev, _rx_dsp, target_freq);
}
+ tune_result_t set_rx_freq(double target_freq, double lo_off){
+ return tune_rx_subdev_and_ddc(_rx_subdev, _rx_dsp, target_freq, lo_off);
+ }
+
freq_range_t get_rx_freq_range(void){
return _rx_subdev[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>();
}
@@ -168,6 +172,10 @@ public:
return tune_tx_subdev_and_duc(_tx_subdev, _tx_dsp, target_freq);
}
+ tune_result_t set_tx_freq(double target_freq, double lo_off){
+ return tune_tx_subdev_and_duc(_tx_subdev, _tx_dsp, target_freq, lo_off);
+ }
+
freq_range_t get_tx_freq_range(void){
return _tx_subdev[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>();
}
diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt
index f9907e21e..99d0b8bdd 100644
--- a/host/lib/usrp/usrp2/CMakeLists.txt
+++ b/host/lib/usrp/usrp2/CMakeLists.txt
@@ -18,12 +18,20 @@
#This file will be included by cmake, use absolute paths!
LIBUHD_APPEND_SOURCES(
- ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_control.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.hpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.hpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/io_impl.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/mboard_impl.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.hpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.hpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.hpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_regs.hpp
)
diff --git a/host/lib/usrp/usrp2/clock_control.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp
index 72f1f1c7a..4c5207203 100644
--- a/host/lib/usrp/usrp2/clock_control.cpp
+++ b/host/lib/usrp/usrp2/clock_ctrl.cpp
@@ -15,21 +15,19 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include "usrp2_impl.hpp"
-#include "clock_control.hpp"
+#include "clock_ctrl.hpp"
#include "ad9510_regs.hpp"
#include "usrp2_regs.hpp" //spi slave constants
#include <boost/cstdint.hpp>
using namespace uhd;
-using namespace uhd::usrp;
/*!
* A usrp2 clock control specific to the ad9510 ic.
*/
-class clock_control_ad9510 : public clock_control{
+class clock_ctrl_impl : public clock_ctrl{
public:
- clock_control_ad9510(usrp2_iface::sptr iface){
+ clock_ctrl_impl(usrp2_iface::sptr iface){
_iface = iface;
_ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA;
@@ -70,7 +68,7 @@ public:
}
- ~clock_control_ad9510(void){
+ ~clock_ctrl_impl(void){
/* private clock enables, must be set here */
this->enable_dac_clock(false);
this->enable_adc_clock(false);
@@ -81,7 +79,9 @@ public:
_ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1;
_ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS;
_ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA;
+ _ad9510_regs.bypass_divider_out7 = 1;
this->write_reg(0x43);
+ this->write_reg(0x57);
this->update_regs();
}
@@ -90,7 +90,9 @@ public:
_ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;
_ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS;
_ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA;
+ _ad9510_regs.bypass_divider_out6 = 1;
this->write_reg(0x42);
+ this->write_reg(0x55);
this->update_regs();
}
@@ -132,7 +134,9 @@ private:
ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL :
ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD;
_ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV;
+ _ad9510_regs.bypass_divider_out3 = 1;
this->write_reg(0x3F);
+ this->write_reg(0x4F);
this->update_regs();
}
@@ -141,7 +145,9 @@ private:
_ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1;
_ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS;
_ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA;
+ _ad9510_regs.bypass_divider_out4 = 1;
this->write_reg(0x40);
+ this->write_reg(0x51);
this->update_regs();
}
@@ -152,6 +158,6 @@ private:
/***********************************************************************
* Public make function for the ad9510 clock control
**********************************************************************/
-clock_control::sptr clock_control::make_ad9510(usrp2_iface::sptr iface){
- return clock_control::sptr(new clock_control_ad9510(iface));
+clock_ctrl::sptr clock_ctrl::make(usrp2_iface::sptr iface){
+ return sptr(new clock_ctrl_impl(iface));
}
diff --git a/host/lib/usrp/usrp2/clock_control.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp
index b64a53196..706bf4246 100644
--- a/host/lib/usrp/usrp2/clock_control.hpp
+++ b/host/lib/usrp/usrp2/clock_ctrl.hpp
@@ -15,23 +15,23 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#ifndef INCLUDED_CLOCK_CONTROL_HPP
-#define INCLUDED_CLOCK_CONTROL_HPP
+#ifndef INCLUDED_CLOCK_CTRL_HPP
+#define INCLUDED_CLOCK_CTRL_HPP
#include "usrp2_iface.hpp"
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
-class clock_control : boost::noncopyable{
+class clock_ctrl : boost::noncopyable{
public:
- typedef boost::shared_ptr<clock_control> sptr;
+ typedef boost::shared_ptr<clock_ctrl> sptr;
/*!
* Make a clock config for the ad9510 ic.
* \param _iface a pointer to the usrp2 interface object
* \return a new clock control object
*/
- static sptr make_ad9510(usrp2_iface::sptr iface);
+ static sptr make(usrp2_iface::sptr iface);
/*!
* Enable/disable the rx dboard clock.
@@ -57,4 +57,4 @@ public:
};
-#endif /* INCLUDED_CLOCK_CONTROL_HPP */
+#endif /* INCLUDED_CLOCK_CTRL_HPP */
diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp
new file mode 100644
index 000000000..d698216ba
--- /dev/null
+++ b/host/lib/usrp/usrp2/codec_ctrl.cpp
@@ -0,0 +1,91 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "codec_ctrl.hpp"
+#include "ad9777_regs.hpp"
+#include "usrp2_regs.hpp"
+#include <boost/cstdint.hpp>
+#include <boost/foreach.hpp>
+#include <iostream>
+
+static const bool codec_ctrl_debug = false;
+
+using namespace uhd;
+
+/*!
+ * A usrp2 codec control specific to the ad9777 ic.
+ */
+class codec_ctrl_impl : public codec_ctrl{
+public:
+ codec_ctrl_impl(usrp2_iface::sptr iface){
+ _iface = iface;
+
+ //setup the ad9777 dac
+ _ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R;
+ _ad9777_regs.filter_interp_rate = ad9777_regs_t::FILTER_INTERP_RATE_4X;
+ _ad9777_regs.mix_mode = ad9777_regs_t::MIX_MODE_REAL;
+ _ad9777_regs.pll_divide_ratio = ad9777_regs_t::PLL_DIVIDE_RATIO_DIV1;
+ _ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_ON;
+ _ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_AUTO;
+ //I dac values
+ _ad9777_regs.idac_fine_gain_adjust = 0;
+ _ad9777_regs.idac_coarse_gain_adjust = 0xf;
+ _ad9777_regs.idac_offset_adjust_lsb = 0;
+ _ad9777_regs.idac_offset_adjust_msb = 0;
+ //Q dac values
+ _ad9777_regs.qdac_fine_gain_adjust = 0;
+ _ad9777_regs.qdac_coarse_gain_adjust = 0xf;
+ _ad9777_regs.qdac_offset_adjust_lsb = 0;
+ _ad9777_regs.qdac_offset_adjust_msb = 0;
+ //write all regs
+ for(boost::uint8_t addr = 0; addr <= 0xC; addr++){
+ this->send_ad9777_reg(addr);
+ }
+
+ //power-up adc
+ _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_ON);
+ }
+
+ ~codec_ctrl_impl(void){
+ //power-down dac
+ _ad9777_regs.power_down_mode = 1;
+ this->send_ad9777_reg(0);
+
+ //power-down adc
+ _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_OFF);
+ }
+
+private:
+ ad9777_regs_t _ad9777_regs;
+ usrp2_iface::sptr _iface;
+
+ void send_ad9777_reg(boost::uint8_t addr){
+ boost::uint16_t reg = _ad9777_regs.get_write_reg(addr);
+ if (codec_ctrl_debug) std::cout << "send_ad9777_reg: " << std::hex << reg << std::endl;
+ _iface->transact_spi(
+ SPI_SS_AD9777, spi_config_t::EDGE_RISE,
+ reg, 16, false /*no rb*/
+ );
+ }
+};
+
+/***********************************************************************
+ * Public make function for the usrp2 codec control
+ **********************************************************************/
+codec_ctrl::sptr codec_ctrl::make(usrp2_iface::sptr iface){
+ return sptr(new codec_ctrl_impl(iface));
+}
diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp
new file mode 100644
index 000000000..0ee52f476
--- /dev/null
+++ b/host/lib/usrp/usrp2/codec_ctrl.hpp
@@ -0,0 +1,38 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_CODEC_CTRL_HPP
+#define INCLUDED_CODEC_CTRL_HPP
+
+#include "usrp2_iface.hpp"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+class codec_ctrl : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<codec_ctrl> sptr;
+
+ /*!
+ * Make a codec control for the DAC and ADC.
+ * \param _iface a pointer to the usrp2 interface object
+ * \return a new codec control object
+ */
+ static sptr make(usrp2_iface::sptr iface);
+
+};
+
+#endif /* INCLUDED_CODEC_CTRL_HPP */
diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp
index 372a5af07..0a2e4b550 100644
--- a/host/lib/usrp/usrp2/dboard_iface.cpp
+++ b/host/lib/usrp/usrp2/dboard_iface.cpp
@@ -16,7 +16,7 @@
//
#include "usrp2_iface.hpp"
-#include "clock_control.hpp"
+#include "clock_ctrl.hpp"
#include "usrp2_regs.hpp" //wishbone address constants
#include <uhd/usrp/dboard_iface.hpp>
#include <uhd/types/dict.hpp>
@@ -33,14 +33,16 @@ using namespace boost::assign;
class usrp2_dboard_iface : public dboard_iface{
public:
- usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::sptr clk_ctrl);
+ usrp2_dboard_iface(usrp2_iface::sptr iface, clock_ctrl::sptr clock_ctrl);
~usrp2_dboard_iface(void);
void write_aux_dac(unit_t, int, float);
float read_aux_adc(unit_t, int);
+ void set_pin_ctrl(unit_t, boost::uint16_t);
void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t);
void set_gpio_ddr(unit_t, boost::uint16_t);
+ void write_gpio(unit_t, boost::uint16_t);
boost::uint16_t read_gpio(unit_t);
void write_i2c(boost::uint8_t, const byte_vector_t &);
@@ -66,8 +68,9 @@ public:
private:
usrp2_iface::sptr _iface;
- clock_control::sptr _clk_ctrl;
+ clock_ctrl::sptr _clock_ctrl;
boost::uint32_t _ddr_shadow;
+ boost::uint32_t _gpio_shadow;
uhd::dict<unit_t, ad5624_regs_t> _dac_regs;
void _write_aux_dac(unit_t);
@@ -78,26 +81,19 @@ private:
**********************************************************************/
dboard_iface::sptr make_usrp2_dboard_iface(
usrp2_iface::sptr iface,
- clock_control::sptr clk_ctrl
+ clock_ctrl::sptr clock_ctrl
){
- return dboard_iface::sptr(new usrp2_dboard_iface(iface, clk_ctrl));
+ return dboard_iface::sptr(new usrp2_dboard_iface(iface, clock_ctrl));
}
/***********************************************************************
* Structors
**********************************************************************/
-usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::sptr clk_ctrl){
+usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_ctrl::sptr clock_ctrl){
_iface = iface;
- _clk_ctrl = clk_ctrl;
+ _clock_ctrl = clock_ctrl;
_ddr_shadow = 0;
-
- //set the selection mux to use atr
- boost::uint32_t new_sels = 0x0;
- for(size_t i = 0; i < 16; i++){
- new_sels |= FRF_GPIO_SEL_ATR << (i*2);
- }
- _iface->poke32(FR_GPIO_TX_SEL, new_sels);
- _iface->poke32(FR_GPIO_RX_SEL, new_sels);
+ _gpio_shadow = 0;
//reset the aux dacs
_dac_regs[UNIT_RX] = ad5624_regs_t();
@@ -123,8 +119,8 @@ double usrp2_dboard_iface::get_clock_rate(unit_t){
void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){
switch(unit){
- case UNIT_RX: _clk_ctrl->enable_rx_dboard_clock(enb); return;
- case UNIT_TX: _clk_ctrl->enable_tx_dboard_clock(enb); return;
+ case UNIT_RX: _clock_ctrl->enable_rx_dboard_clock(enb); return;
+ case UNIT_TX: _clock_ctrl->enable_tx_dboard_clock(enb); return;
}
}
@@ -136,6 +132,21 @@ static const uhd::dict<dboard_iface::unit_t, int> unit_to_shift = map_list_of
(dboard_iface::UNIT_TX, 16)
;
+void usrp2_dboard_iface::set_pin_ctrl(unit_t unit, boost::uint16_t value){
+ //calculate the new selection mux setting
+ boost::uint32_t new_sels = 0x0;
+ for(size_t i = 0; i < 16; i++){
+ bool is_bit_set = bool(value & (0x1 << i));
+ new_sels |= ((is_bit_set)? FRF_GPIO_SEL_ATR : FRF_GPIO_SEL_GPIO) << (i*2);
+ }
+
+ //write the selection mux value to register
+ switch(unit){
+ case UNIT_RX: _iface->poke32(FR_GPIO_RX_SEL, new_sels); return;
+ case UNIT_TX: _iface->poke32(FR_GPIO_TX_SEL, new_sels); return;
+ }
+}
+
void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){
_ddr_shadow = \
(_ddr_shadow & ~(0xffff << unit_to_shift[unit])) |
@@ -143,6 +154,13 @@ void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){
_iface->poke32(FR_GPIO_DDR, _ddr_shadow);
}
+void usrp2_dboard_iface::write_gpio(unit_t unit, boost::uint16_t value){
+ _gpio_shadow = \
+ (_gpio_shadow & ~(0xffff << unit_to_shift[unit])) |
+ (boost::uint32_t(value) << unit_to_shift[unit]);
+ _iface->poke32(FR_GPIO_IO, _gpio_shadow);
+}
+
boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){
return boost::uint16_t(_iface->peek32(FR_GPIO_IO) >> unit_to_shift[unit]);
}
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
index 403faf5cf..0ac39d2a3 100644
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ b/host/lib/usrp/usrp2/dboard_impl.cpp
@@ -38,9 +38,7 @@ void usrp2_impl::dboard_init(void){
_tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes()));
//create a new dboard interface and manager
- dboard_iface::sptr _dboard_iface(
- make_usrp2_dboard_iface(_iface, _clk_ctrl)
- );
+ _dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl);
_dboard_manager = dboard_manager::make(
_rx_db_eeprom.id, _tx_db_eeprom.id, _dboard_iface
);
@@ -123,6 +121,10 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _rx_db_eeprom.id;
return;
+ case DBOARD_PROP_DBOARD_IFACE:
+ val = _dboard_iface;
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -172,6 +174,10 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _tx_db_eeprom.id;
return;
+ case DBOARD_PROP_DBOARD_IFACE:
+ val = _dboard_iface;
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp
index fc4c5479e..195a9bc53 100644
--- a/host/lib/usrp/usrp2/dsp_impl.cpp
+++ b/host/lib/usrp/usrp2/dsp_impl.cpp
@@ -94,9 +94,6 @@ void usrp2_impl::init_ddc_config(void){
_ddc_decim = default_decim;
_ddc_freq = 0;
update_ddc_config();
-
- //initial command that kills streaming (in case if was left on)
- issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
}
void usrp2_impl::update_ddc_config(void){
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index e80001ff2..75f5b1779 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -34,7 +34,7 @@ extern "C" {
//defines the protocol version in this shared header
//increment this value when the protocol is changed
-#define USRP2_PROTO_VERSION 2
+#define USRP2_PROTO_VERSION 3
//used to differentiate control packets over data port
#define USRP2_INVALID_VRT_HEADER 0
@@ -53,13 +53,8 @@ typedef enum{
//USRP2_CTRL_ID_FOR_SURE, //TODO error condition enums
//USRP2_CTRL_ID_SUX_MAN,
- USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO = 'a',
- USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE = 'A',
- USRP2_CTRL_ID_HERE_IS_A_NEW_IP_ADDR_BRO = 'b',
-
- USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO = 'm',
- USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE = 'M',
- USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO = 'n',
+ USRP2_CTRL_ID_WAZZUP_BRO = 'a',
+ USRP2_CTRL_ID_WAZZUP_DUDE = 'A',
USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO = 's',
USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE = 'S',
@@ -70,9 +65,6 @@ typedef enum{
USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO = 'h',
USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE = 'H',
- USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO = '{',
- USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE = '}',
-
USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO = 'p',
USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE = 'P',
@@ -99,7 +91,6 @@ typedef struct{
_SINS_ uint32_t seq;
union{
_SINS_ uint32_t ip_addr;
- _SINS_ uint8_t mac_addr[6];
struct {
_SINS_ uint8_t dev;
_SINS_ uint8_t miso_edge;
@@ -114,15 +105,6 @@ typedef struct{
_SINS_ uint8_t data[sizeof(_SINS_ uint32_t)];
} i2c_args;
struct {
- _SINS_ uint8_t now; //stream now?
- _SINS_ uint8_t continuous; //auto-reload commmands?
- _SINS_ uint8_t chain;
- _SINS_ uint8_t _pad[1];
- _SINS_ uint32_t secs;
- _SINS_ uint32_t ticks;
- _SINS_ uint32_t num_samps;
- } stream_cmd;
- struct {
_SINS_ uint32_t addr;
_SINS_ uint32_t data;
_SINS_ uint8_t num_bytes; //1, 2, 4
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 2634e84aa..79b18fb63 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -16,6 +16,7 @@
//
#include "usrp2_impl.hpp"
+#include "usrp2_regs.hpp"
#include <uhd/transport/convert_types.hpp>
#include <boost/format.hpp>
#include <boost/asio.hpp> //htonl and ntohl
@@ -30,71 +31,35 @@ namespace asio = boost::asio;
* Helper Functions
**********************************************************************/
void usrp2_impl::io_init(void){
- //setup otw type
- _otw_type.width = 16;
- _otw_type.shift = 0;
- _otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN;
+ //setup rx otw type
+ _rx_otw_type.width = 16;
+ _rx_otw_type.shift = 0;
+ _rx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN;
- //initially empty copy buffer
- _rx_copy_buff = asio::buffer("", 0);
-
- //init the expected rx seq number
- _rx_stream_id_to_packet_seq[0] = 0;
+ //setup tx otw type
+ _tx_otw_type.width = 16;
+ _tx_otw_type.shift = 0;
+ _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN;
//send a small data packet so the usrp2 knows the udp source port
- //and the maximum number of lines (32 bit words) per packet
managed_send_buffer::sptr send_buff = _data_transport->get_send_buff();
- boost::uint32_t data[2] = {
- htonl(USRP2_INVALID_VRT_HEADER),
- htonl(_max_rx_samples_per_packet)
- };
- memcpy(send_buff->cast<void*>(), data, sizeof(data));
- send_buff->done(sizeof(data));
-}
-
-/***********************************************************************
- * Receive Raw Data
- **********************************************************************/
-void usrp2_impl::recv_raw(rx_metadata_t &metadata){
- //do a receive
- _rx_smart_buff = _data_transport->get_recv_buff();
-
- //unpack the vrt header
- size_t num_packet_words32 = _rx_smart_buff->size()/sizeof(boost::uint32_t);
- if (num_packet_words32 == 0){
- _rx_copy_buff = boost::asio::buffer("", 0);
- return; //must exit here after setting the buffer
- }
- const boost::uint32_t *vrt_hdr = _rx_smart_buff->cast<const boost::uint32_t *>();
- size_t num_header_words32_out, num_payload_words32_out, packet_count_out;
- try{
- vrt::unpack(
- metadata, //output
- vrt_hdr, //input
- num_header_words32_out, //output
- num_payload_words32_out, //output
- num_packet_words32, //input
- packet_count_out, //output
- get_master_clock_freq()
- );
- }catch(const std::exception &e){
- std::cerr << "bad vrt header: " << e.what() << std::endl;
- _rx_copy_buff = boost::asio::buffer("", 0);
- return; //must exit here after setting the buffer
- }
-
- //handle the packet count / sequence number
- size_t expected_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id];
- if (packet_count_out != expected_packet_count){
- std::cerr << "S" << (packet_count_out - expected_packet_count)%16;
- }
- _rx_stream_id_to_packet_seq[metadata.stream_id] = (packet_count_out+1)%16;
-
- //setup the rx buffer to point to the data
- _rx_copy_buff = asio::buffer(
- vrt_hdr + num_header_words32_out,
- num_payload_words32_out*sizeof(boost::uint32_t)
+ boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER);
+ memcpy(send_buff->cast<void*>(), &data, sizeof(data));
+ send_buff->commit(sizeof(data));
+
+ //setup RX DSP regs
+ std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl;
+ _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, get_max_recv_samps_per_packet());
+ _iface->poke32(FR_RX_CTRL_NCHANNELS, 1);
+ _iface->poke32(FR_RX_CTRL_CLEAR_OVERRUN, 1); //reset
+ _iface->poke32(FR_RX_CTRL_VRT_HEADER, 0
+ | (0x1 << 28) //if data with stream id
+ | (0x1 << 26) //has trailer
+ | (0x3 << 22) //integer time other
+ | (0x1 << 20) //fractional time sample count
);
+ _iface->poke32(FR_RX_CTRL_VRT_STREAM_ID, 0);
+ _iface->poke32(FR_RX_CTRL_VRT_TRAILER, 0);
}
/***********************************************************************
@@ -102,49 +67,18 @@ void usrp2_impl::recv_raw(rx_metadata_t &metadata){
**********************************************************************/
size_t usrp2_impl::send(
const asio::const_buffer &buff,
- const tx_metadata_t &metadata_,
- const io_type_t &io_type
+ const tx_metadata_t &metadata,
+ const io_type_t &io_type,
+ send_mode_t send_mode
){
- tx_metadata_t metadata = metadata_; //rw copy to change later
-
- transport::managed_send_buffer::sptr send_buff = _data_transport->get_send_buff();
- boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>();
- size_t num_samps = std::min(std::min(
- asio::buffer_size(buff)/io_type.size,
- size_t(_max_tx_samples_per_packet)),
- send_buff->size()/io_type.size
- );
-
- //kill the end of burst flag if this is a fragment
- if (asio::buffer_size(buff)/io_type.size < num_samps)
- metadata.end_of_burst = false;
-
- size_t num_header_words32, num_packet_words32;
- size_t packet_count = _tx_stream_id_to_packet_seq[metadata.stream_id]++;
-
- //pack metadata into a vrt header
- vrt::pack(
- metadata, //input
- tx_mem, //output
- num_header_words32, //output
- num_samps, //input
- num_packet_words32, //output
- packet_count, //input
- get_master_clock_freq()
- );
-
- boost::uint32_t *items = tx_mem + num_header_words32; //offset for data
-
- //copy-convert the samples into the send buffer
- convert_io_type_to_otw_type(
- asio::buffer_cast<const void*>(buff), io_type,
- (void*)items, _otw_type,
- num_samps
+ return vrt_packet_handler::send(
+ _packet_handler_send_state, //last state of the send handler
+ buff, metadata, send_mode, //buffer to empty and samples metadata
+ io_type, _tx_otw_type, //input and output types to convert
+ get_master_clock_freq(), //master clock tick rate
+ _data_transport, //zero copy interface
+ get_max_send_samps_per_packet()
);
-
- //send and return number of samples
- send_buff->done(num_packet_words32*sizeof(boost::uint32_t));
- return num_samps;
}
/***********************************************************************
@@ -153,44 +87,14 @@ size_t usrp2_impl::send(
size_t usrp2_impl::recv(
const asio::mutable_buffer &buff,
rx_metadata_t &metadata,
- const io_type_t &io_type
+ const io_type_t &io_type,
+ recv_mode_t recv_mode
){
- //perform a receive if no rx data is waiting to be copied
- if (asio::buffer_size(_rx_copy_buff) == 0){
- _fragment_offset_in_samps = 0;
- recv_raw(metadata);
- }
- //otherwise flag the metadata to show that is is a fragment
- else{
- metadata = rx_metadata_t();
- }
-
- //extract the number of samples available to copy
- //and a pointer into the usrp2 received items memory
- size_t bytes_to_copy = asio::buffer_size(_rx_copy_buff);
- if (bytes_to_copy == 0) return 0; //nothing to receive
- size_t num_samps = std::min(
- asio::buffer_size(buff)/io_type.size,
- bytes_to_copy/sizeof(boost::uint32_t)
+ return vrt_packet_handler::recv(
+ _packet_handler_recv_state, //last state of the recv handler
+ buff, metadata, recv_mode, //buffer to fill and samples metadata
+ io_type, _rx_otw_type, //input and output types to convert
+ get_master_clock_freq(), //master clock tick rate
+ _data_transport //zero copy interface
);
- const boost::uint32_t *items = asio::buffer_cast<const boost::uint32_t*>(_rx_copy_buff);
-
- //setup the fragment flags and offset
- metadata.more_fragments = asio::buffer_size(buff)/io_type.size < num_samps;
- metadata.fragment_offset = _fragment_offset_in_samps;
- _fragment_offset_in_samps += num_samps; //set for next time
-
- //copy-convert the samples from the recv buffer
- convert_otw_type_to_io_type(
- (const void*)items, _otw_type,
- asio::buffer_cast<void*>(buff), io_type,
- num_samps
- );
-
- //update the rx copy buffer to reflect the bytes copied
- _rx_copy_buff = asio::buffer(
- items + num_samps, bytes_to_copy - num_samps*sizeof(boost::uint32_t)
- );
-
- return num_samps;
}
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 36bef4f25..a2aeadf16 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -17,13 +17,13 @@
#include "usrp2_impl.hpp"
#include "usrp2_regs.hpp"
-#include "ad9777_regs.hpp"
#include <uhd/usrp/mboard_props.hpp>
#include <uhd/utils/assert.hpp>
+#include <uhd/utils/algorithm.hpp>
#include <uhd/types/mac_addr.hpp>
#include <uhd/types/dict.hpp>
#include <boost/bind.hpp>
-#include <boost/asio.hpp> //htonl and ntohl
+#include <boost/asio/ip/address_v4.hpp>
#include <boost/assign/list_of.hpp>
using namespace uhd;
@@ -37,32 +37,6 @@ void usrp2_impl::mboard_init(void){
boost::bind(&usrp2_impl::mboard_get, this, _1, _2),
boost::bind(&usrp2_impl::mboard_set, this, _1, _2)
);
-
- _clk_ctrl = clock_control::make_ad9510(_iface);
-
- //setup the ad9777 dac
- ad9777_regs_t ad9777_regs;
- ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R;
- ad9777_regs.filter_interp_rate = ad9777_regs_t::FILTER_INTERP_RATE_4X;
- ad9777_regs.mix_mode = ad9777_regs_t::MIX_MODE_REAL;
- ad9777_regs.pll_divide_ratio = ad9777_regs_t::PLL_DIVIDE_RATIO_DIV1;
- ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_OFF;
- ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_ENB;
- //I dac values
- ad9777_regs.idac_fine_gain_adjust = 0;
- ad9777_regs.idac_coarse_gain_adjust = 0xf;
- ad9777_regs.idac_offset_adjust_lsb = 0;
- ad9777_regs.idac_offset_adjust_msb = 0;
- //Q dac values
- ad9777_regs.qdac_fine_gain_adjust = 0;
- ad9777_regs.qdac_coarse_gain_adjust = 0xf;
- ad9777_regs.qdac_offset_adjust_lsb = 0;
- ad9777_regs.qdac_offset_adjust_msb = 0;
- //write all regs
- for(boost::uint8_t addr = 0; addr <= 0xC; addr++){
- boost::uint16_t data = ad9777_regs.get_write_reg(addr);
- _iface->transact_spi(SPI_SS_AD9777, spi_config_t::EDGE_RISE, data, 16, false /*no rb*/);
- }
}
void usrp2_impl::init_clock_config(void){
@@ -97,62 +71,55 @@ void usrp2_impl::update_clock_config(void){
//clock source ref 10mhz
switch(_clock_config.ref_source){
- case clock_config_t::REF_INT : _iface->poke32(FR_CLOCK_CONTROL, 0x10); break;
- case clock_config_t::REF_SMA : _iface->poke32(FR_CLOCK_CONTROL, 0x1C); break;
- case clock_config_t::REF_MIMO: _iface->poke32(FR_CLOCK_CONTROL, 0x15); break;
+ case clock_config_t::REF_INT : _iface->poke32(FR_MISC_CTRL_CLOCK, 0x10); break;
+ case clock_config_t::REF_SMA : _iface->poke32(FR_MISC_CTRL_CLOCK, 0x1C); break;
+ case clock_config_t::REF_MIMO: _iface->poke32(FR_MISC_CTRL_CLOCK, 0x15); break;
default: throw std::runtime_error("usrp2: unhandled clock configuration reference source");
}
//clock source ref 10mhz
bool use_external = _clock_config.ref_source != clock_config_t::REF_INT;
- _clk_ctrl->enable_external_ref(use_external);
+ _clock_ctrl->enable_external_ref(use_external);
}
void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){
- //set ticks and seconds
- _iface->poke32(FR_TIME64_SECS, time_spec.secs);
+ //set the ticks
_iface->poke32(FR_TIME64_TICKS, time_spec.get_ticks(get_master_clock_freq()));
- //set the register to latch it all in
+ //set the flags register
boost::uint32_t imm_flags = (now)? FRF_TIME64_LATCH_NOW : FRF_TIME64_LATCH_NEXT_PPS;
_iface->poke32(FR_TIME64_IMM, imm_flags);
+
+ //set the seconds (latches in all 3 registers)
+ _iface->poke32(FR_TIME64_SECS, time_spec.secs);
}
void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO);
- out_data.data.stream_cmd.now = (stream_cmd.stream_now)? 1 : 0;
- out_data.data.stream_cmd.secs = htonl(stream_cmd.time_spec.secs);
- out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.get_ticks(get_master_clock_freq()));
-
- //set these to defaults, then change in the switch statement
- out_data.data.stream_cmd.continuous = 0;
- out_data.data.stream_cmd.chain = 0;
- out_data.data.stream_cmd.num_samps = htonl(stream_cmd.num_samps);
-
- //setup chain, num samps, and continuous below
- switch(stream_cmd.stream_mode){
- case stream_cmd_t::STREAM_MODE_START_CONTINUOUS:
- out_data.data.stream_cmd.continuous = 1;
- break;
-
- case stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS:
- out_data.data.stream_cmd.num_samps = htonl(0);
- break;
-
- case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE:
- //all set by defaults above
- break;
-
- case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE:
- out_data.data.stream_cmd.chain = 1;
- break;
- }
-
- //send and recv
- usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE);
+ UHD_ASSERT_THROW(stream_cmd.num_samps <= FR_RX_CTRL_MAX_SAMPS_PER_CMD);
+
+ //setup the mode to instruction flags
+ typedef boost::tuple<bool, bool, bool> inst_t;
+ static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of
+ //reload, chain, samps
+ (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false))
+ (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true))
+ ;
+
+ //setup the instruction flag values
+ bool inst_reload, inst_chain, inst_samps;
+ boost::tie(inst_reload, inst_chain, inst_samps) = mode_to_inst[stream_cmd.stream_mode];
+
+ //issue the stream command
+ _iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD(
+ (inst_samps)? stream_cmd.num_samps : ((inst_chain)? get_max_recv_samps_per_packet() : 1),
+ (stream_cmd.stream_now)? 1 : 0,
+ (inst_chain)? 1 : 0,
+ (inst_reload)? 1 : 0
+ ));
+ _iface->poke32(FR_RX_CTRL_TIME_SECS, stream_cmd.time_spec.secs);
+ _iface->poke32(FR_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_ticks(get_master_clock_freq()));
}
/***********************************************************************
@@ -165,30 +132,15 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
//handle the other props
if (key.type() == typeid(std::string)){
if (key.as<std::string>() == "mac-addr"){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO);
-
- //send and recv
- usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);
-
- //extract the address
- val = mac_addr_t::from_bytes(in_data.data.mac_addr).to_string();
+ byte_vector_t bytes = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, 6);
+ val = mac_addr_t::from_bytes(bytes).to_string();
return;
}
if (key.as<std::string>() == "ip-addr"){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO);
-
- //send and recv
- usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);
-
- //extract the address
- val = boost::asio::ip::address_v4(ntohl(in_data.data.ip_addr)).to_string();
+ boost::asio::ip::address_v4::bytes_type bytes;
+ std::copy(_iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, 4), bytes);
+ val = boost::asio::ip::address_v4(bytes).to_string();
return;
}
}
@@ -259,27 +211,15 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){
//handle the other props
if (key.type() == typeid(std::string)){
if (key.as<std::string>() == "mac-addr"){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO);
- mac_addr_t mac_addr = mac_addr_t::from_string(val.as<std::string>());
- std::copy(mac_addr.to_bytes(), mac_addr.to_bytes()+mac_addr_t::hlen, out_data.data.mac_addr);
-
- //send and recv
- usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);
+ byte_vector_t bytes = mac_addr_t::from_string(val.as<std::string>()).to_bytes();
+ _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, bytes);
return;
}
if (key.as<std::string>() == "ip-addr"){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_HERE_IS_A_NEW_IP_ADDR_BRO);
- out_data.data.ip_addr = htonl(boost::asio::ip::address_v4::from_string(val.as<std::string>()).to_ulong());
-
- //send and recv
- usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);
+ byte_vector_t bytes(4);
+ std::copy(boost::asio::ip::address_v4::from_string(val.as<std::string>()).to_bytes(), bytes);
+ _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, bytes);
return;
}
}
diff --git a/host/lib/usrp/usrp2/serdes_ctrl.cpp b/host/lib/usrp/usrp2/serdes_ctrl.cpp
new file mode 100644
index 000000000..dde22b499
--- /dev/null
+++ b/host/lib/usrp/usrp2/serdes_ctrl.cpp
@@ -0,0 +1,46 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "serdes_ctrl.hpp"
+#include "usrp2_regs.hpp"
+
+using namespace uhd;
+
+/*!
+ * A usrp2 serdes control implementation
+ */
+class serdes_ctrl_impl : public serdes_ctrl{
+public:
+ serdes_ctrl_impl(usrp2_iface::sptr iface){
+ _iface = iface;
+ _iface->poke32(FR_MISC_CTRL_SERDES, FRF_MISC_CTRL_SERDES_ENABLE | FRF_MISC_CTRL_SERDES_RXEN);
+ }
+
+ ~serdes_ctrl_impl(void){
+ _iface->poke32(FR_MISC_CTRL_SERDES, 0); //power-down
+ }
+
+private:
+ usrp2_iface::sptr _iface;
+};
+
+/***********************************************************************
+ * Public make function for the usrp2 serdes control
+ **********************************************************************/
+serdes_ctrl::sptr serdes_ctrl::make(usrp2_iface::sptr iface){
+ return sptr(new serdes_ctrl_impl(iface));
+}
diff --git a/host/lib/usrp/usrp2/serdes_ctrl.hpp b/host/lib/usrp/usrp2/serdes_ctrl.hpp
new file mode 100644
index 000000000..586238739
--- /dev/null
+++ b/host/lib/usrp/usrp2/serdes_ctrl.hpp
@@ -0,0 +1,40 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_SERDES_CTRL_HPP
+#define INCLUDED_SERDES_CTRL_HPP
+
+#include "usrp2_iface.hpp"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+class serdes_ctrl : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<serdes_ctrl> sptr;
+
+ /*!
+ * Make a serdes control object for the usrp2 serdes port.
+ * \param _iface a pointer to the usrp2 interface object
+ * \return a new serdes control object
+ */
+ static sptr make(usrp2_iface::sptr iface);
+
+ //TODO fill me in with virtual methods
+
+};
+
+#endif /* INCLUDED_SERDES_CTRL_HPP */
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
index 7158c58d0..caf6623e2 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.hpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.hpp
@@ -32,7 +32,14 @@
#define I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0)
#define I2C_ADDR_TX_DB (I2C_DEV_EEPROM | 0x4)
#define I2C_ADDR_RX_DB (I2C_DEV_EEPROM | 0x5)
+
+////////////////////////////////////////////////////////////////////////
+// EEPROM Layout
////////////////////////////////////////////////////////////////////////
+#define EE_MBOARD_REV_LSB 0x00 //1 byte
+#define EE_MBOARD_REV_MSB 0x01 //1 byte
+#define EE_MBOARD_MAC_ADDR 0x02 //6 bytes
+#define EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian
/*!
* The usrp2 interface class:
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 1dde8c054..af3ec216a 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -72,7 +72,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){
//send a hello control packet
usrp2_ctrl_data_t ctrl_data_out;
ctrl_data_out.proto_ver = htonl(USRP2_PROTO_VERSION);
- ctrl_data_out.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO);
+ ctrl_data_out.id = htonl(USRP2_CTRL_ID_WAZZUP_BRO);
udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out)));
//loop and recieve until the timeout
@@ -83,7 +83,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){
if (len >= sizeof(usrp2_ctrl_data_t)){
//handle the received data
switch(ntohl(ctrl_data_in.id)){
- case USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE:
+ case 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;
@@ -147,6 +147,9 @@ usrp2_impl::usrp2_impl(
//make a new interface for usrp2 stuff
_iface = usrp2_iface::make(ctrl_transport);
+ _clock_ctrl = clock_ctrl::make(_iface);
+ _codec_ctrl = codec_ctrl::make(_iface);
+ _serdes_ctrl = serdes_ctrl::make(_iface);
//load the allowed decim/interp rates
//_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4)
@@ -207,14 +210,6 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){
val = prop_names_t(1, "");
return;
- case DEVICE_PROP_MAX_RX_SAMPLES:
- val = size_t(_max_rx_samples_per_packet);
- return;
-
- case DEVICE_PROP_MAX_TX_SAMPLES:
- val = size_t(_max_tx_samples_per_packet);
- return;
-
default: UHD_THROW_PROP_GET_ERROR();
}
}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index 1c9387744..7948a2069 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -19,7 +19,9 @@
#define INCLUDED_USRP2_IMPL_HPP
#include "usrp2_iface.hpp"
-#include "clock_control.hpp"
+#include "clock_ctrl.hpp"
+#include "codec_ctrl.hpp"
+#include "serdes_ctrl.hpp"
#include <uhd/usrp/usrp2.hpp>
#include <uhd/types/dict.hpp>
#include <uhd/types/otw_type.hpp>
@@ -31,6 +33,7 @@
#include <uhd/transport/vrt.hpp>
#include <uhd/transport/udp_zero_copy.hpp>
#include <uhd/usrp/dboard_manager.hpp>
+#include "../../transport/vrt_packet_handler.hpp"
/*!
* Make a usrp2 dboard interface.
@@ -40,7 +43,7 @@
*/
uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface(
usrp2_iface::sptr iface,
- clock_control::sptr clk_ctrl
+ clock_ctrl::sptr clk_ctrl
);
/*!
@@ -101,8 +104,24 @@ public:
~usrp2_impl(void);
//the io interface
- size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &);
- size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &);
+ size_t get_max_send_samps_per_packet(void) const{
+ return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size();
+ }
+ size_t send(
+ const boost::asio::const_buffer &,
+ const uhd::tx_metadata_t &,
+ const uhd::io_type_t &,
+ uhd::device::send_mode_t
+ );
+ size_t get_max_recv_samps_per_packet(void) const{
+ return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size();
+ }
+ size_t recv(
+ const boost::asio::mutable_buffer &,
+ uhd::rx_metadata_t &,
+ const uhd::io_type_t &,
+ uhd::device::recv_mode_t
+ );
private:
double get_master_clock_freq(void){
@@ -114,28 +133,29 @@ private:
void set(const wax::obj &, const wax::obj &);
//interfaces
- clock_control::sptr _clk_ctrl;
usrp2_iface::sptr _iface;
+ clock_ctrl::sptr _clock_ctrl;
+ codec_ctrl::sptr _codec_ctrl;
+ serdes_ctrl::sptr _serdes_ctrl;
- //the raw io interface (samples are in the usrp2 native format)
- void recv_raw(uhd::rx_metadata_t &);
- uhd::dict<boost::uint32_t, size_t> _tx_stream_id_to_packet_seq;
- uhd::dict<boost::uint32_t, size_t> _rx_stream_id_to_packet_seq;
+ /*******************************************************************
+ * Deal with the rx and tx packet sizes
+ ******************************************************************/
static const size_t _mtu = 1500; //FIXME we have no idea
static const size_t _hdrs = (2 + 14 + 20 + 8); //size of headers (pad, eth, ip, udp)
- static const size_t _max_rx_samples_per_packet =
- (_mtu - _hdrs)/sizeof(boost::uint32_t) -
- USRP2_HOST_RX_VRT_HEADER_WORDS32 -
- USRP2_HOST_RX_VRT_TRAILER_WORDS32
+ static const size_t _max_rx_bytes_per_packet =
+ _mtu - _hdrs -
+ USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) -
+ USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t)
;
- static const size_t _max_tx_samples_per_packet =
- (_mtu - _hdrs)/sizeof(boost::uint32_t) -
- uhd::transport::vrt::max_header_words32
+ static const size_t _max_tx_bytes_per_packet =
+ _mtu - _hdrs -
+ uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t)
;
- uhd::transport::managed_recv_buffer::sptr _rx_smart_buff;
- boost::asio::const_buffer _rx_copy_buff;
- size_t _fragment_offset_in_samps;
- uhd::otw_type_t _otw_type;
+
+ vrt_packet_handler::recv_state _packet_handler_recv_state;
+ vrt_packet_handler::send_state _packet_handler_send_state;
+ uhd::otw_type_t _rx_otw_type, _tx_otw_type;
void io_init(void);
//udp transports for control and data
@@ -149,6 +169,7 @@ private:
//rx and tx dboard methods and objects
uhd::usrp::dboard_manager::sptr _dboard_manager;
+ uhd::usrp::dboard_iface::sptr _dboard_iface;
void dboard_init(void);
//properties for the mboard
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index 0e2a18756..0f675357b 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -64,7 +64,23 @@
/////////////////////////////////////////////////
// Misc Control
////////////////////////////////////////////////
-#define FR_CLOCK_CONTROL _SR_ADDR(0)
+#define FR_MISC_CTRL_CLOCK _SR_ADDR(0)
+#define FR_MISC_CTRL_SERDES _SR_ADDR(1)
+#define FR_MISC_CTRL_ADC _SR_ADDR(2)
+#define FR_MISC_CTRL_LEDS _SR_ADDR(3)
+#define FR_MISC_CTRL_PHY _SR_ADDR(4) // LSB is reset line to eth phy
+#define FR_MISC_CTRL_DBG_MUX _SR_ADDR(5)
+#define FR_MISC_CTRL_RAM_PAGE _SR_ADDR(6) // FIXME should go somewhere else...
+#define FR_MISC_CTRL_FLUSH_ICACHE _SR_ADDR(7) // Flush the icache
+#define FR_MISC_CTRL_LED_SRC _SR_ADDR(8) // HW or SW control for LEDs
+
+#define FRF_MISC_CTRL_SERDES_ENABLE 8
+#define FRF_MISC_CTRL_SERDES_PRBSEN 4
+#define FRF_MISC_CTRL_SERDES_LOOPEN 2
+#define FRF_MISC_CTRL_SERDES_RXEN 1
+
+#define FRF_MISC_CTRL_ADC_ON 0x0F
+#define FRF_MISC_CTRL_ADC_OFF 0x00
/////////////////////////////////////////////////
// VITA49 64 bit time (write only)
@@ -188,7 +204,7 @@
#define FR_GPIO_RX_SEL FR_GPIO_BASE + 12 // 16 2-bit fields select which source goes to RX DB
// each 2-bit sel field is layed out this way
-#define FRF_GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg
+#define FRF_GPIO_SEL_GPIO 0 // if pin is an output, set by GPIO register
#define FRF_GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic
#define FRF_GPIO_SEL_DEBUG_0 2 // if pin is an output, debug lines from FPGA fabric
#define FRF_GPIO_SEL_DEBUG_1 3 // if pin is an output, debug lines from FPGA fabric
@@ -207,4 +223,25 @@
#define FR_ATR_FULL_TXSIDE FR_ATR_BASE + 12
#define FR_ATR_FULL_RXSIDE FR_ATR_BASE + 14
+///////////////////////////////////////////////////
+// VITA RX CTRL regs
+///////////////////////////////////////////////////
+// The following 3 are logically a single command register.
+// They are clocked into the underlying fifo when time_ticks is written.
+#define FR_RX_CTRL_STREAM_CMD _SR_ADDR(SR_RX_CTRL + 0) // {now, chain, num_samples(30)
+#define FR_RX_CTRL_TIME_SECS _SR_ADDR(SR_RX_CTRL + 1)
+#define FR_RX_CTRL_TIME_TICKS _SR_ADDR(SR_RX_CTRL + 2)
+
+#define FR_RX_CTRL_CLEAR_OVERRUN _SR_ADDR(SR_RX_CTRL + 3) // write anything to clear overrun
+#define FR_RX_CTRL_VRT_HEADER _SR_ADDR(SR_RX_CTRL + 4) // word 0 of packet. FPGA fills in packet counter
+#define FR_RX_CTRL_VRT_STREAM_ID _SR_ADDR(SR_RX_CTRL + 5) // word 1 of packet.
+#define FR_RX_CTRL_VRT_TRAILER _SR_ADDR(SR_RX_CTRL + 6)
+#define FR_RX_CTRL_NSAMPS_PER_PKT _SR_ADDR(SR_RX_CTRL + 7)
+#define FR_RX_CTRL_NCHANNELS _SR_ADDR(SR_RX_CTRL + 8) // 1 in basic case, up to 4 for vector sources
+
+//helpful macros for dealing with stream cmd
+#define FR_RX_CTRL_MAX_SAMPS_PER_CMD 0x1fffffff
+#define FR_RX_CTRL_MAKE_CMD(nsamples, now, chain, reload) \
+ ((((now) & 0x1) << 31) | (((chain) & 0x1) << 30) | (((reload) & 0x1) << 29) | ((nsamples) & 0x1fffffff))
+
#endif /* INCLUDED_USRP2_REGS_HPP */
diff --git a/host/lib/usrp/usrp_e/dboard_iface.cpp b/host/lib/usrp/usrp_e/dboard_iface.cpp
index e70934b8c..23255b58c 100644
--- a/host/lib/usrp/usrp_e/dboard_iface.cpp
+++ b/host/lib/usrp/usrp_e/dboard_iface.cpp
@@ -49,8 +49,10 @@ public:
void write_aux_dac(unit_t, int, float);
float read_aux_adc(unit_t, int);
+ void set_pin_ctrl(unit_t, boost::uint16_t);
void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t);
void set_gpio_ddr(unit_t, boost::uint16_t);
+ void write_gpio(unit_t, boost::uint16_t);
boost::uint16_t read_gpio(unit_t);
void write_i2c(boost::uint8_t, const byte_vector_t &);
@@ -111,29 +113,41 @@ void usrp_e_dboard_iface::set_clock_enabled(unit_t unit, bool enb){
/***********************************************************************
* GPIO
**********************************************************************/
-void usrp_e_dboard_iface::set_gpio_ddr(unit_t bank, boost::uint16_t value){
- //define mapping of gpio bank to register address
- static const uhd::dict<unit_t, boost::uint32_t> bank_to_addr = map_list_of
- (UNIT_RX, UE_REG_GPIO_RX_DDR)
- (UNIT_TX, UE_REG_GPIO_TX_DDR)
- ;
- _iface->poke16(bank_to_addr[bank], value);
+void usrp_e_dboard_iface::set_pin_ctrl(unit_t unit, boost::uint16_t value){
+ UHD_ASSERT_THROW(GPIO_SEL_ATR == 1); //make this assumption
+ switch(unit){
+ case UNIT_RX: _iface->poke16(UE_REG_GPIO_RX_SEL, value); return;
+ case UNIT_TX: _iface->poke16(UE_REG_GPIO_TX_SEL, value); return;
+ }
}
-boost::uint16_t usrp_e_dboard_iface::read_gpio(unit_t bank){
- //define mapping of gpio bank to register address
- static const uhd::dict<unit_t, boost::uint32_t> bank_to_addr = map_list_of
- (UNIT_RX, UE_REG_GPIO_RX_IO)
- (UNIT_TX, UE_REG_GPIO_TX_IO)
- ;
- return _iface->peek16(bank_to_addr[bank]);
+void usrp_e_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){
+ switch(unit){
+ case UNIT_RX: _iface->poke16(UE_REG_GPIO_RX_DDR, value); return;
+ case UNIT_TX: _iface->poke16(UE_REG_GPIO_TX_DDR, value); return;
+ }
+}
+
+void usrp_e_dboard_iface::write_gpio(unit_t unit, boost::uint16_t value){
+ switch(unit){
+ case UNIT_RX: _iface->poke16(UE_REG_GPIO_RX_IO, value); return;
+ case UNIT_TX: _iface->poke16(UE_REG_GPIO_TX_IO, value); return;
+ }
+}
+
+boost::uint16_t usrp_e_dboard_iface::read_gpio(unit_t unit){
+ switch(unit){
+ case UNIT_RX: return _iface->peek16(UE_REG_GPIO_RX_IO);
+ case UNIT_TX: return _iface->peek16(UE_REG_GPIO_TX_IO);
+ }
+ UHD_ASSERT_THROW(false);
}
-void usrp_e_dboard_iface::set_atr_reg(unit_t bank, atr_reg_t atr, boost::uint16_t value){
- //define mapping of bank to atr regs to register address
+void usrp_e_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){
+ //define mapping of unit to atr regs to register address
static const uhd::dict<
unit_t, uhd::dict<atr_reg_t, boost::uint32_t>
- > bank_to_atr_to_addr = map_list_of
+ > unit_to_atr_to_addr = map_list_of
(UNIT_RX, map_list_of
(ATR_REG_IDLE, UE_REG_ATR_IDLE_RXSIDE)
(ATR_REG_TX_ONLY, UE_REG_ATR_INTX_RXSIDE)
@@ -147,7 +161,7 @@ void usrp_e_dboard_iface::set_atr_reg(unit_t bank, atr_reg_t atr, boost::uint16_
(ATR_REG_FULL_DUPLEX, UE_REG_ATR_FULL_TXSIDE)
)
;
- _iface->poke16(bank_to_atr_to_addr[bank][atr], value);
+ _iface->poke16(unit_to_atr_to_addr[unit][atr], value);
}
/***********************************************************************
diff --git a/host/lib/usrp/usrp_e/usrp_e_impl.cpp b/host/lib/usrp/usrp_e/usrp_e_impl.cpp
index 4f7361eca..4a398e21c 100644
--- a/host/lib/usrp/usrp_e/usrp_e_impl.cpp
+++ b/host/lib/usrp/usrp_e/usrp_e_impl.cpp
@@ -117,14 +117,6 @@ void usrp_e_impl::get(const wax::obj &key_, wax::obj &val){
val = prop_names_t(1, ""); //vector of size 1 with empty string
return;
- case DEVICE_PROP_MAX_RX_SAMPLES:
- val = size_t(_max_num_samples);
- return;
-
- case DEVICE_PROP_MAX_TX_SAMPLES:
- val = size_t(_max_num_samples);
- return;
-
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -142,7 +134,8 @@ void usrp_e_impl::set(const wax::obj &, const wax::obj &){
size_t usrp_e_impl::send(
const boost::asio::const_buffer &,
const uhd::tx_metadata_t &,
- const io_type_t &
+ const io_type_t &,
+ send_mode_t
){
if (true){
throw std::runtime_error(str(boost::format("usrp-e send: cannot handle type \"%s\"") % ""));
@@ -153,7 +146,8 @@ size_t usrp_e_impl::send(
size_t usrp_e_impl::recv(
const boost::asio::mutable_buffer &,
uhd::rx_metadata_t &,
- const io_type_t &
+ const io_type_t &,
+ recv_mode_t
){
if (true){
throw std::runtime_error(str(boost::format("usrp-e recv: cannot handle type \"%s\"") % ""));
diff --git a/host/lib/usrp/usrp_e/usrp_e_impl.hpp b/host/lib/usrp/usrp_e/usrp_e_impl.hpp
index 59f80c70c..a2cdbc31e 100644
--- a/host/lib/usrp/usrp_e/usrp_e_impl.hpp
+++ b/host/lib/usrp/usrp_e/usrp_e_impl.hpp
@@ -89,8 +89,10 @@ public:
~usrp_e_impl(void);
//the io interface
- size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &);
- size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &);
+ size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t);
+ size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t);
+ size_t get_max_send_samps_per_packet(void) const{return _max_num_samples;}
+ size_t get_max_recv_samps_per_packet(void) const{return _max_num_samples;}
private:
static const size_t _max_num_samples = 2048/sizeof(boost::uint32_t);
diff --git a/host/lib/usrp/usrp_e/usrp_e_regs.hpp b/host/lib/usrp/usrp_e/usrp_e_regs.hpp
index 7f35212f4..51a47f061 100644
--- a/host/lib/usrp/usrp_e/usrp_e_regs.hpp
+++ b/host/lib/usrp/usrp_e/usrp_e_regs.hpp
@@ -78,11 +78,13 @@
#define UE_REG_GPIO_RX_DBG UE_REG_GPIO_BASE + 12
#define UE_REG_GPIO_TX_DBG UE_REG_GPIO_BASE + 14
-// each 2-bit sel field is layed out this way
-#define GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg
-#define GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic
-#define GPIO_SEL_DEBUG_0 0 // if pin is an output, debug lines from FPGA fabric
-#define GPIO_SEL_DEBUG_1 1 // if pin is an output, debug lines from FPGA fabric
+//possible bit values for sel when dbg is 0:
+#define GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg
+#define GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic
+
+//possible bit values for sel when dbg is 1:
+#define GPIO_SEL_DEBUG_0 0 // if pin is an output, debug lines from FPGA fabric
+#define GPIO_SEL_DEBUG_1 1 // if pin is an output, debug lines from FPGA fabric
////////////////////////////////////////////////////
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt
index 78970ad0e..2cb95e66f 100644
--- a/host/utils/CMakeLists.txt
+++ b/host/utils/CMakeLists.txt
@@ -23,12 +23,17 @@ ADD_EXECUTABLE(usrp_e_load_fpga usrp_e_load_fpga.cpp)
TARGET_LINK_LIBRARIES(usrp_e_load_fpga uhd)
INSTALL(TARGETS usrp_e_load_fpga RUNTIME DESTINATION ${PKG_DATA_DIR}/utils)
-ADD_EXECUTABLE(usrp2_burner usrp2_burner.cpp)
-TARGET_LINK_LIBRARIES(usrp2_burner uhd)
-INSTALL(TARGETS usrp2_burner RUNTIME DESTINATION ${PKG_DATA_DIR}/utils)
+ADD_EXECUTABLE(usrp2_addr_burner usrp2_addr_burner.cpp)
+TARGET_LINK_LIBRARIES(usrp2_addr_burner uhd)
+INSTALL(TARGETS usrp2_addr_burner RUNTIME DESTINATION ${PKG_DATA_DIR}/utils)
ADD_EXECUTABLE(uhd_burn_db_eeprom uhd_burn_db_eeprom.cpp)
TARGET_LINK_LIBRARIES(uhd_burn_db_eeprom uhd)
INSTALL(TARGETS uhd_burn_db_eeprom RUNTIME DESTINATION ${PKG_DATA_DIR}/utils)
-INSTALL(PROGRAMS usrp2_recovery.py DESTINATION ${PKG_DATA_DIR}/utils)
+INSTALL(PROGRAMS
+ usrp2_recovery.py
+ usrp2_card_burner.py
+ usrp2_card_burner_gui.py
+ DESTINATION ${PKG_DATA_DIR}/utils
+)
diff --git a/host/utils/usrp2_burner.cpp b/host/utils/usrp2_addr_burner.cpp
index 9c1bf72fe..08fc1e218 100644
--- a/host/utils/usrp2_burner.cpp
+++ b/host/utils/usrp2_addr_burner.cpp
@@ -39,7 +39,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//print the help message
if (vm.count("help")){
- std::cout << boost::format("USRP2 Burner %s") % desc << std::endl;
+ std::cout << boost::format("USRP2 Address Burner %s") % desc << std::endl;
return ~0;
}
diff --git a/host/utils/usrp2_card_burner.py b/host/utils/usrp2_card_burner.py
new file mode 100755
index 000000000..d47a4f5f4
--- /dev/null
+++ b/host/utils/usrp2_card_burner.py
@@ -0,0 +1,226 @@
+#!/usr/bin/env python
+#
+# Copyright 2010 Ettus Research LLC
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import platform
+import tempfile
+import subprocess
+import urllib
+import optparse
+import os
+import re
+
+########################################################################
+# constants
+########################################################################
+SECTOR_SIZE = 512 # bytes
+MAX_FILE_SIZE = 1 * (2**20) # maximum number of bytes we'll burn to a slot
+
+FPGA_OFFSET = 0 # offset in flash to fpga image
+FIRMWARE_OFFSET = 1 * (2**20) # offset in flash to firmware image
+
+MAX_SD_CARD_SIZE = 2048e6 # bytes (any bigger is sdhc)
+
+########################################################################
+# helper functions
+########################################################################
+def command(*args):
+ p = subprocess.Popen(
+ args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ )
+ ret = p.wait()
+ verbose = p.stdout.read()
+ if ret != 0: raise Exception, verbose
+ return verbose
+
+def get_dd_path():
+ if platform.system() == 'Windows':
+ dd_path = os.path.join(tempfile.gettempdir(), 'dd.exe')
+ if not os.path.exists(dd_path):
+ print 'Downloading dd.exe to %s'%dd_path
+ dd_bin = urllib.urlopen('http://www.ettus.com/downloads/dd.exe').read()
+ open(dd_path, 'wb').write(dd_bin)
+ return dd_path
+ return 'dd'
+
+########################################################################
+# list possible devices
+########################################################################
+def get_raw_device_hints():
+ ####################################################################
+ # Platform Windows: parse the output of dd.exe --list
+ ####################################################################
+ if platform.system() == 'Windows':
+ def extract_info_value(info, key):
+ return info.split(key)[-1].split()[0]
+ def get_info_list(output):
+ in_info = False
+ for line in output.splitlines():
+ if line.startswith('\\\\'): in_info = True; info = ''
+ elif in_info and not line.strip(): in_info = False; yield info
+ if in_info: info += '\n'+line.strip()
+ def is_info_valid(info):
+ try:
+ assert 'link to' in info
+ #handles two spellings of remov(e)able:
+ assert 'remov' in info.lower()
+ if 'size is' in info: assert int(extract_info_value(info, 'size is')) <= MAX_SD_CARD_SIZE
+ return True
+ except: return False
+ def extract_info_name(info):
+ for key in ('Mounted on', 'link to'):
+ if key in info: return extract_info_value(info, key)
+ return info.splitlines()[0].strip()
+
+ return sorted(set(map(extract_info_name, filter(is_info_valid, get_info_list(command(get_dd_path(), '--list'))))))
+
+ ####################################################################
+ # Platform Linux: parse procfs /proc/partitions
+ ####################################################################
+ if platform.system() == 'Linux':
+ devs = list()
+ try: output = open('/proc/partitions', 'r').read()
+ except: return devs
+ for line in output.splitlines():
+ try:
+ major, minor, blocks, name = line.split()
+ assert not name[-1].isdigit() or int(minor) == 0
+ assert int(blocks)*1024 <= MAX_SD_CARD_SIZE
+ except: continue
+ devs.append(os.path.join('/dev', name))
+
+ return sorted(set(devs))
+
+ ####################################################################
+ # Platform Mac OS X: parse diskutil list and info commands
+ ####################################################################
+ if platform.system() == 'Darwin':
+ devs = map(lambda d: d.split()[0], filter(lambda l: l.startswith('/dev'), command('diskutil', 'list').splitlines()))
+ def output_to_info(output):
+ return dict([map(str.strip, pair.lower().split(':')) for pair in filter(lambda l: ':' in l, output.splitlines())])
+ def is_dev_valid(dev):
+ info = output_to_info(command('diskutil', 'info', dev))
+ try:
+ if info.has_key('internal'): assert info['internal'] == 'no'
+ if info.has_key('ejectable'): assert info['ejectable'] == 'yes'
+ if info.has_key('total size'):
+ size_match = re.match('^.*\((\d+)\s*bytes\).*$', info['total size'])
+ if size_match: assert int(size_match.groups()[0]) <= MAX_SD_CARD_SIZE
+ return True
+ except: return False
+
+ return sorted(set(filter(is_dev_valid, devs)))
+
+ ####################################################################
+ # Platform Others:
+ ####################################################################
+ return ()
+
+########################################################################
+# write and verify with dd
+########################################################################
+def verify_image(image_file, device_file, offset):
+ #create a temporary file to store the readback
+ tmp = tempfile.mkstemp()
+ os.close(tmp[0])
+ tmp_file = tmp[1]
+
+ #execute a dd subprocess
+ verbose = command(
+ get_dd_path(),
+ "of=%s"%tmp_file,
+ "if=%s"%device_file,
+ "skip=%d"%(offset/SECTOR_SIZE),
+ "bs=%d"%SECTOR_SIZE,
+ "count=%d"%(MAX_FILE_SIZE/SECTOR_SIZE),
+ )
+
+ #read in the image and readback
+ img_data = open(image_file, 'rb').read()
+ tmp_data = open(tmp_file, 'rb').read(len(img_data))
+
+ #verfy the data
+ if img_data != tmp_data: return 'Verification Failed:\n%s'%verbose
+ return 'Verification Passed:\n%s'%verbose
+
+def write_image(image_file, device_file, offset):
+ verbose = command(
+ get_dd_path(),
+ "if=%s"%image_file,
+ "of=%s"%device_file,
+ "seek=%d"%(offset/SECTOR_SIZE),
+ "bs=%d"%SECTOR_SIZE,
+ )
+
+ try: #exec the sync command (only works on linux)
+ if platform.system() == 'Linux': command('sync')
+ except: pass
+
+ return verbose
+
+def write_and_verify(image_file, device_file, offset):
+ if os.path.getsize(image_file) > MAX_FILE_SIZE:
+ raise Exception, 'Image file larger than %d bytes!'%MAX_FILE_SIZE
+ return '%s\n%s'%(
+ write_image(
+ image_file=image_file,
+ device_file=device_file,
+ offset=offset,
+ ), verify_image(
+ image_file=image_file,
+ device_file=device_file,
+ offset=offset,
+ ),
+ )
+
+def burn_sd_card(dev, fw, fpga):
+ verbose = ''
+ if fw: verbose += 'Burn firmware image:\n%s\n'%write_and_verify(
+ image_file=fw, device_file=dev, offset=FIRMWARE_OFFSET
+ )
+ if fpga: verbose += 'Burn fpga image:\n%s\n'%write_and_verify(
+ image_file=fpga, device_file=dev, offset=FPGA_OFFSET
+ )
+ return verbose
+
+########################################################################
+# command line options
+########################################################################
+def get_options():
+ parser = optparse.OptionParser()
+ parser.add_option("--dev", type="string", help="raw device path", default='')
+ 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)
+ (options, args) = parser.parse_args()
+
+ if options.list:
+ print 'Possible raw devices:'
+ print ' ' + '\n '.join(get_raw_device_hints())
+ exit()
+
+ return options
+
+########################################################################
+# main
+########################################################################
+if __name__=='__main__':
+ options = get_options()
+ 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/usrp2_card_burner_gui.py b/host/utils/usrp2_card_burner_gui.py
new file mode 100755
index 000000000..61fbadbe3
--- /dev/null
+++ b/host/utils/usrp2_card_burner_gui.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+#
+# Copyright 2010 Ettus Research LLC
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import usrp2_card_burner #import implementation
+import Tkinter, Tkconstants, tkFileDialog, tkFont, tkMessageBox
+import os
+
+class BinFileEntry(Tkinter.Frame):
+ """
+ Simple file entry widget for getting the file path of bin files.
+ Combines a label, entry, and button with file dialog callback.
+ """
+
+ def __init__(self, root, what, def_path=''):
+ self._what = what
+ Tkinter.Frame.__init__(self, root)
+ Tkinter.Label(self, text=what+":").pack(side=Tkinter.LEFT)
+ self._entry = Tkinter.Entry(self, width=50)
+ self._entry.insert(Tkinter.END, def_path)
+ self._entry.pack(side=Tkinter.LEFT)
+ Tkinter.Button(self, text="...", command=self._button_cb).pack(side=Tkinter.LEFT)
+
+ def _button_cb(self):
+ filename = tkFileDialog.askopenfilename(
+ parent=self,
+ filetypes=[('bin files', '*.bin'), ('all files', '*.*')],
+ title="Select bin file for %s"%self._what,
+ initialdir=os.path.dirname(self.get_filename()),
+ )
+
+ # open file on your own
+ if filename:
+ self._entry.delete(0, Tkinter.END)
+ self._entry.insert(0, filename)
+
+ def get_filename(self):
+ return self._entry.get()
+
+class DeviceEntryWidget(Tkinter.Frame):
+ """
+ Simple entry widget for getting the raw device name.
+ Combines a label, entry, and helpful text box with hints.
+ """
+
+ def __init__(self, root, text=''):
+ Tkinter.Frame.__init__(self, root)
+
+ Tkinter.Button(self, text="Rescan for Devices", command=self._reload_cb).pack()
+
+ self._hints = Tkinter.Listbox(self)
+ self._hints.bind("<<ListboxSelect>>", self._listbox_cb)
+ self._reload_cb()
+ self._hints.pack(expand=Tkinter.YES, fill=Tkinter.X)
+
+ frame = Tkinter.Frame(self)
+ frame.pack()
+
+ Tkinter.Label(frame, text="Raw Device:").pack(side=Tkinter.LEFT)
+ self._entry = Tkinter.Entry(frame, width=50)
+ self._entry.insert(Tkinter.END, text)
+ self._entry.pack(side=Tkinter.LEFT)
+
+ def _reload_cb(self):
+ self._hints.delete(0, Tkinter.END)
+ for hint in usrp2_card_burner.get_raw_device_hints():
+ self._hints.insert(Tkinter.END, hint)
+
+ def _listbox_cb(self, event):
+ try:
+ sel = self._hints.get(self._hints.curselection()[0])
+ self._entry.delete(0, Tkinter.END)
+ self._entry.insert(0, sel)
+ except Exception, e: print e
+
+ def get_devname(self):
+ return self._entry.get()
+
+class SectionLabel(Tkinter.Label):
+ """
+ Make a text label with bold font.
+ """
+
+ def __init__(self, root, text):
+ Tkinter.Label.__init__(self, root, text=text)
+
+ #set the font bold
+ f = tkFont.Font(font=self['font'])
+ f['weight'] = 'bold'
+ self['font'] = f.name
+
+class USRP2CardBurnerApp(Tkinter.Frame):
+ """
+ The top level gui application for the usrp2 sd card burner.
+ Creates entry widgets and button with callback to write images.
+ """
+
+ def __init__(self, root, dev, fw, fpga):
+
+ Tkinter.Frame.__init__(self, root)
+
+ #pack the file entry widgets
+ SectionLabel(self, text="Select Images").pack(pady=5)
+ self._fw_img_entry = BinFileEntry(self, "Firmware Image", def_path=fw)
+ self._fw_img_entry.pack()
+ self._fpga_img_entry = BinFileEntry(self, "FPGA Image", def_path=fpga)
+ self._fpga_img_entry.pack()
+
+ #pack the destination entry widget
+ SectionLabel(self, text="Select Device").pack(pady=5)
+ self._raw_dev_entry = DeviceEntryWidget(self, text=dev)
+ self._raw_dev_entry.pack()
+
+ #the do it button
+ SectionLabel(self, text="").pack(pady=5)
+ Tkinter.Label(self, text="Warning! This tool can overwrite your hard drive. Use with caution.").pack()
+ Tkinter.Button(self, text="Burn SD Card", command=self._burn).pack()
+
+ def _burn(self):
+ #grab strings from the gui
+ fw = self._fw_img_entry.get_filename()
+ fpga = self._fpga_img_entry.get_filename()
+ dev = self._raw_dev_entry.get_devname()
+
+ #check input
+ if not dev:
+ tkMessageBox.showerror('Error:', 'No device specified!')
+ return
+ if not fw and not fpga:
+ tkMessageBox.showerror('Error:', 'No images specified!')
+ return
+ if fw and not os.path.exists(fw):
+ tkMessageBox.showerror('Error:', 'Firmware image not found!')
+ return
+ if fpga and not os.path.exists(fpga):
+ tkMessageBox.showerror('Error:', 'FPGA image not found!')
+ return
+
+ #burn the sd card
+ try:
+ verbose = usrp2_card_burner.burn_sd_card(dev=dev, fw=fw, fpga=fpga)
+ tkMessageBox.showinfo('Verbose:', verbose)
+ except Exception, e:
+ tkMessageBox.showerror('Verbose:', 'Error: %s'%str(e))
+
+########################################################################
+# main
+########################################################################
+if __name__=='__main__':
+ options = usrp2_card_burner.get_options()
+ root = Tkinter.Tk()
+ root.title('USRP2 SD Card Burner')
+ USRP2CardBurnerApp(root, dev=options.dev, fw=options.fw, fpga=options.fpga).pack()
+ root.mainloop()
+ exit()