summaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-rw-r--r--host/CMakeLists.txt32
-rw-r--r--host/apps/CMakeLists.txt8
-rw-r--r--host/apps/discover_usrps.cpp33
-rwxr-xr-xhost/apps/omap_debug/set_debug_pins.py12
-rw-r--r--host/apps/usrp1e_load_fpga.cpp47
-rw-r--r--host/apps/usrp2_burner.cpp84
-rwxr-xr-xhost/apps/usrp2_recovery.py52
-rw-r--r--host/include/CMakeLists.txt5
-rw-r--r--host/include/uhd/CMakeLists.txt5
-rw-r--r--host/include/uhd/config.hpp76
-rw-r--r--host/include/uhd/device.hpp78
-rw-r--r--host/include/uhd/device_addr.hpp16
-rw-r--r--host/include/uhd/dict.hpp56
-rw-r--r--host/include/uhd/gain_handler.hpp75
-rw-r--r--host/include/uhd/metadata.hpp61
-rw-r--r--host/include/uhd/props.hpp70
-rw-r--r--host/include/uhd/shared_iovec.hpp54
-rw-r--r--host/include/uhd/simple_device.hpp90
-rw-r--r--host/include/uhd/time_spec.hpp30
-rw-r--r--host/include/uhd/transport/CMakeLists.txt5
-rw-r--r--host/include/uhd/transport/smart_buffer.hpp45
-rw-r--r--host/include/uhd/transport/udp.hpp75
-rw-r--r--host/include/uhd/transport/udp_simple.hpp80
-rw-r--r--host/include/uhd/transport/udp_zero_copy.hpp77
-rw-r--r--host/include/uhd/transport/vrt.hpp71
-rw-r--r--host/include/uhd/types.hpp83
-rw-r--r--host/include/uhd/usrp/CMakeLists.txt1
-rw-r--r--host/include/uhd/usrp/dboard_base.hpp14
-rw-r--r--host/include/uhd/usrp/dboard_id.hpp21
-rw-r--r--host/include/uhd/usrp/dboard_interface.hpp15
-rw-r--r--host/include/uhd/usrp/dboard_manager.hpp9
-rw-r--r--host/include/uhd/usrp/usrp1e.hpp55
-rw-r--r--host/include/uhd/usrp/usrp2.hpp19
-rw-r--r--host/include/uhd/utils.hpp121
-rw-r--r--host/include/uhd/wax.hpp56
-rw-r--r--host/lib/CMakeLists.txt85
-rw-r--r--host/lib/device.cpp126
-rw-r--r--host/lib/device_addr.cpp10
-rw-r--r--host/lib/gain_handler.cpp238
-rw-r--r--host/lib/load_modules.cpp117
-rw-r--r--host/lib/metadata.cpp (renamed from host/include/uhd.hpp)23
-rw-r--r--host/lib/simple_device.cpp293
-rw-r--r--host/lib/time_spec.cpp40
-rw-r--r--host/lib/transport/udp.cpp67
-rw-r--r--host/lib/transport/udp_simple.cpp158
-rw-r--r--host/lib/transport/udp_zero_copy_asio.cpp154
-rw-r--r--host/lib/transport/vrt.cpp109
-rw-r--r--host/lib/types.cpp57
-rw-r--r--host/lib/uhd.cpp20
-rw-r--r--host/lib/usrp/dboard/basic.cpp275
-rw-r--r--host/lib/usrp/dboard_manager.cpp186
-rw-r--r--host/lib/usrp/usrp1e/dboard_impl.cpp76
-rw-r--r--host/lib/usrp/usrp1e/dboard_interface.cpp189
-rw-r--r--host/lib/usrp/usrp1e/dsp_impl.cpp70
-rw-r--r--host/lib/usrp/usrp1e/fpga-downloader.cc262
-rw-r--r--host/lib/usrp/usrp1e/mboard_impl.cpp (renamed from host/lib/usrp/dboard/dboards.hpp)51
-rw-r--r--host/lib/usrp/usrp1e/usrp1e_impl.cpp178
-rw-r--r--host/lib/usrp/usrp1e/usrp1e_impl.hpp135
-rw-r--r--host/lib/usrp/usrp1e/usrp1e_none.cpp (renamed from host/lib/usrp/dboard_id.cpp)28
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp99
-rw-r--r--host/lib/usrp/usrp2/dboard_interface.cpp59
-rw-r--r--host/lib/usrp/usrp2/dboard_interface.hpp63
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp92
-rw-r--r--host/lib/usrp/usrp2/fw_common.h108
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp258
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp187
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp117
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp104
-rw-r--r--host/lib/wax.cpp14
-rw-r--r--host/test/CMakeLists.txt12
-rw-r--r--host/test/gain_handler_test.cpp87
-rw-r--r--host/test/module_test.cpp (renamed from host/lib/shared_iovec.cpp)16
-rw-r--r--host/test/vrt_test.cpp100
-rw-r--r--host/test/wax_test.cpp17
74 files changed, 4709 insertions, 1202 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index 70c04631b..2f5d03f7d 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -53,17 +53,32 @@ FUNCTION(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG flag have)
ENDIF(${have})
ENDFUNCTION(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG)
-UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wall HAVE_WALL)
-UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wextra HAVE_WEXTRA)
-UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-pedantic HAVE_PEDANTIC)
-UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-ansi HAVE_ANSI)
+IF(UNIX)
+ UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wall HAVE_WALL)
+ UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wextra HAVE_WEXTRA)
+ UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-pedantic HAVE_PEDANTIC)
+ 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)
+ENDIF(UNIX)
+
+IF(WIN32)
+ ADD_DEFINITIONS(-Dnot=! -Dand=&& -Dor=||) #logical operators
+ ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) #minimum version required is windows xp
+ ADD_DEFINITIONS(-DNOMINMAX) #disables stupidity and enables std::min and std::max
+ ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS) #avoid warnings from boost::split
+ ADD_DEFINITIONS(-DBOOST_ALL_DYN_LINK) #setup boost auto-linking in msvc
+ENDIF(WIN32)
########################################################################
# Setup Boost
########################################################################
+SET(Boost_ADDITIONAL_VERSIONS "1.42.0" "1.42")
FIND_PACKAGE(Boost 1.36 REQUIRED
date_time
+ filesystem
program_options
+ regex
system
thread
unit_test_framework
@@ -73,6 +88,15 @@ INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
########################################################################
+# Setup Endianess
+########################################################################
+INCLUDE(TestBigEndian)
+TEST_BIG_ENDIAN(HAVE_BIG_ENDIAN)
+IF(HAVE_BIG_ENDIAN)
+ ADD_DEFINITIONS(-DHAVE_BIG_ENDIAN)
+ENDIF(HAVE_BIG_ENDIAN)
+
+########################################################################
# Create Uninstall Target
########################################################################
CONFIGURE_FILE(
diff --git a/host/apps/CMakeLists.txt b/host/apps/CMakeLists.txt
index f4428f958..58f73fcd6 100644
--- a/host/apps/CMakeLists.txt
+++ b/host/apps/CMakeLists.txt
@@ -16,7 +16,11 @@
#
ADD_EXECUTABLE(discover_usrps discover_usrps.cpp)
-
TARGET_LINK_LIBRARIES(discover_usrps uhd)
-
INSTALL(TARGETS discover_usrps RUNTIME DESTINATION ${RUNTIME_DIR})
+
+ADD_EXECUTABLE(usrp1e_load_fpga usrp1e_load_fpga.cpp)
+TARGET_LINK_LIBRARIES(usrp1e_load_fpga uhd)
+
+ADD_EXECUTABLE(usrp2_burner usrp2_burner.cpp)
+TARGET_LINK_LIBRARIES(usrp2_burner uhd)
diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp
index 02c05b7cc..d670d1651 100644
--- a/host/apps/discover_usrps.cpp
+++ b/host/apps/discover_usrps.cpp
@@ -15,20 +15,20 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <uhd.hpp>
+#include <uhd/device.hpp>
#include <uhd/props.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <iostream>
namespace po = boost::program_options;
-using namespace uhd;
int main(int argc, char *argv[]){
po::options_description desc("Allowed options");
desc.add_options()
("help", "help message")
- ("ip-addr", po::value<std::string>(), "usrp2 ip address")
+ ("addr", po::value<std::string>(), "resolvable network address")
+ ("node", po::value<std::string>(), "path to linux device node")
;
po::variables_map vm;
@@ -36,31 +36,34 @@ int main(int argc, char *argv[]){
po::notify(vm);
//print the help message
- if (vm.count("help")) {
+ if (vm.count("help")){
std::cout << boost::format("Discover USRPs %s") % desc << std::endl;
return ~0;
}
- //extract the ip address (not optional for now)
+ //load the options into the address
uhd::device_addr_t device_addr;
- device_addr["type"] = "udp";
- if (vm.count("ip-addr")) {
- device_addr["addr"] = vm["ip-addr"].as<std::string>();
- } else {
- std::cout << "IP Addess was not set" << std::endl;
+ if (vm.count("addr")){
+ device_addr["addr"] = vm["addr"].as<std::string>();
+ }
+ if (vm.count("node")){
+ device_addr["node"] = vm["node"].as<std::string>();
+ }
+
+ //discover the usrps and print the results
+ uhd::device_addrs_t device_addrs = uhd::device::discover(device_addr);
+
+ if (device_addrs.size() == 0){
+ std::cerr << "No USRP Devices Found" << std::endl;
return ~0;
}
- //discover the usrps
- std::vector<uhd::device_addr_t> device_addrs = uhd::device::discover(device_addr);
for (size_t i = 0; i < device_addrs.size(); i++){
std::cout << "--------------------------------------------------" << std::endl;
std::cout << "-- USRP Device " << i << std::endl;
std::cout << "--------------------------------------------------" << std::endl;
std::cout << device_addrs[i] << std::endl << std::endl;
- //make each device just to test (TODO: remove this)
- uhd::device::sptr dev = device::make(device_addrs[i]);
- std::cout << wax::cast<std::string>((*dev)[uhd::DEVICE_PROP_MBOARD][uhd::MBOARD_PROP_NAME]) << std::endl;
+ uhd::device::make(device_addrs[i]); //test make
}
return 0;
diff --git a/host/apps/omap_debug/set_debug_pins.py b/host/apps/omap_debug/set_debug_pins.py
index bedabc20c..fdd085c9e 100755
--- a/host/apps/omap_debug/set_debug_pins.py
+++ b/host/apps/omap_debug/set_debug_pins.py
@@ -3,12 +3,12 @@
import os
# Memory Map
-misc_base = 0
-uart_base = 1
-spi_base = 2
-i2c_base = 3
-gpio_base = 4
-settings_base = 5
+misc_base = 0 << 7
+uart_base = 1 << 7
+spi_base = 2 << 7
+i2c_base = 3 << 7
+gpio_base = 4 << 7
+settings_base = 5 << 7
# GPIO offset
gpio_pins = 0
diff --git a/host/apps/usrp1e_load_fpga.cpp b/host/apps/usrp1e_load_fpga.cpp
new file mode 100644
index 000000000..d5960b391
--- /dev/null
+++ b/host/apps/usrp1e_load_fpga.cpp
@@ -0,0 +1,47 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/usrp/usrp1e.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+
+namespace po = boost::program_options;
+
+int main(int argc, char *argv[]){
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("file", po::value<std::string>(), "path to fpga bin file")
+ ;
+
+ 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") or vm.count("file") == 0){
+ std::cout << boost::format("USRP1E Load FPGA %s") % desc << std::endl;
+ return ~0;
+ }
+
+ //load the fpga
+ std::string file = vm["file"].as<std::string>();
+ uhd::usrp::usrp1e::load_fpga(file);
+
+ return 0;
+}
diff --git a/host/apps/usrp2_burner.cpp b/host/apps/usrp2_burner.cpp
new file mode 100644
index 000000000..941e71d0c
--- /dev/null
+++ b/host/apps/usrp2_burner.cpp
@@ -0,0 +1,84 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/usrp/usrp2.hpp>
+#include <uhd/props.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+
+namespace po = boost::program_options;
+
+int main(int argc, char *argv[]){
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("addr", po::value<std::string>(), "resolvable network address")
+ ("new-ip", po::value<std::string>(), "new ip address (optional)")
+ ("new-mac", po::value<std::string>(), "new mac address (optional)")
+ ;
+
+ 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("USRP2 Burner %s") % desc << std::endl;
+ return ~0;
+ }
+
+ //load the options into the address
+ uhd::device_addr_t device_addr;
+ if (vm.count("addr")){
+ device_addr["addr"] = vm["addr"].as<std::string>();
+ }
+ else{
+ std::cerr << "Error: missing addr option" << std::endl;
+ return ~0;
+ }
+
+ //create a usrp2 device
+ uhd::device::sptr u2_dev = uhd::usrp::usrp2::make(device_addr);
+ //FIXME usees the default mboard for now (until the mimo link is supported)
+ wax::obj u2_mb = (*u2_dev)[uhd::DEVICE_PROP_MBOARD];
+
+ //try to set the new ip (if provided)
+ if (vm.count("new-ip")){
+ std::cout << "Burning a new ip address into the usrp2 eeprom:" << std::endl;
+ std::string old_ip = u2_mb[std::string("ip-addr")].as<std::string>();
+ std::cout << boost::format(" Old IP Address: %s") % old_ip << std::endl;
+ std::string new_ip = vm["new-ip"].as<std::string>();
+ std::cout << boost::format(" New IP Address: %s") % new_ip << std::endl;
+ u2_mb[std::string("ip-addr")] = new_ip;
+ std::cout << " Done" << std::endl;
+ }
+
+ //try to set the new mac (if provided)
+ if (vm.count("new-mac")){
+ std::cout << "Burning a new mac address into the usrp2 eeprom:" << std::endl;
+ std::string old_mac = u2_mb[std::string("mac-addr")].as<std::string>();
+ std::cout << boost::format(" Old MAC Address: %s") % old_mac << std::endl;
+ std::string new_mac = vm["new-mac"].as<std::string>();
+ std::cout << boost::format(" New MAC Address: %s") % new_mac << std::endl;
+ u2_mb[std::string("mac-addr")] = new_mac;
+ std::cout << " Done" << std::endl;
+ }
+
+ std::cout << "Power-cycle the usrp2 for the changes to take effect." << std::endl;
+ return 0;
+}
diff --git a/host/apps/usrp2_recovery.py b/host/apps/usrp2_recovery.py
new file mode 100755
index 000000000..48c1121cb
--- /dev/null
+++ b/host/apps/usrp2_recovery.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+
+"""
+The usrp2 recovery app:
+
+When the usrp2 has an unknown or bad ip address in its eeprom,
+it may not be possible to communicate with the usrp2 over ip/udp.
+
+This app will send a raw ethernet packet to bypass the ip layer.
+The packet will contain a known ip address to burn into eeprom.
+Because the recovery packet is sent with a broadcast mac address,
+only one usrp2 should be present on the interface upon execution.
+
+This app requires super-user privileges and only works on linux.
+"""
+
+import socket
+import struct
+import optparse
+
+BCAST_MAC_ADDR = 'ff:ff:ff:ff:ff:ff'
+RECOVERY_ETHERTYPE = 0xbeee
+IP_RECOVERY_CODE = 'addr'
+
+def mac_addr_repr_to_binary_string(mac_addr):
+ return ''.join(map(lambda x: chr(int(x, 16)), mac_addr.split(':')))
+
+if __name__ == '__main__':
+ parser = optparse.OptionParser(usage='usage: %prog [options]\n'+__doc__)
+ parser.add_option('--ifc', type='string', help='ethernet interface name [default=%default]', default='eth0')
+ parser.add_option('--new-ip', type='string', help='ip address to set [default=%default]', default='192.168.10.2')
+ (options, args) = parser.parse_args()
+
+ #create the raw socket
+ print "Opening raw socket on interface:", options.ifc
+ soc = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
+ soc.bind((options.ifc, RECOVERY_ETHERTYPE))
+
+ #create the recovery packet
+ print "Loading packet with ip address:", options.new_ip
+ packet = struct.pack(
+ '!6s6sH4s4s',
+ mac_addr_repr_to_binary_string(BCAST_MAC_ADDR),
+ mac_addr_repr_to_binary_string(BCAST_MAC_ADDR),
+ RECOVERY_ETHERTYPE,
+ IP_RECOVERY_CODE,
+ socket.inet_aton(options.new_ip),
+ )
+
+ print "Sending packet (%d bytes)"%len(packet)
+ soc.send(packet)
+ print "Done"
diff --git a/host/include/CMakeLists.txt b/host/include/CMakeLists.txt
index 34b705cab..3f7ca2cb7 100644
--- a/host/include/CMakeLists.txt
+++ b/host/include/CMakeLists.txt
@@ -17,8 +17,3 @@
ADD_SUBDIRECTORY(uhd)
-
-INSTALL(FILES
- uhd.hpp
- DESTINATION ${HEADER_DIR}
-)
diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt
index 006c54f22..3d00462cf 100644
--- a/host/include/uhd/CMakeLists.txt
+++ b/host/include/uhd/CMakeLists.txt
@@ -20,13 +20,16 @@ ADD_SUBDIRECTORY(transport)
ADD_SUBDIRECTORY(usrp)
INSTALL(FILES
+ config.hpp
device.hpp
device_addr.hpp
dict.hpp
gain_handler.hpp
+ metadata.hpp
props.hpp
- shared_iovec.hpp
+ simple_device.hpp
time_spec.hpp
+ types.hpp
utils.hpp
wax.hpp
DESTINATION ${HEADER_DIR}/uhd
diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp
new file mode 100644
index 000000000..10f9c093f
--- /dev/null
+++ b/host/include/uhd/config.hpp
@@ -0,0 +1,76 @@
+//
+// 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_UHD_CONFIG_HPP
+#define INCLUDED_UHD_CONFIG_HPP
+
+// suppress warnings
+#include <boost/config.hpp>
+#ifdef BOOST_MSVC
+# pragma warning(push)
+//# pragma warning(disable: 4511) // copy constructor can't not be generated
+//# pragma warning(disable: 4512) // assignment operator can't not be generated
+//# pragma warning(disable: 4100) // unreferenced formal parameter
+//# pragma warning(disable: 4996) // <symbol> was declared deprecated
+//# pragma warning(disable: 4355) // 'this' : used in base member initializer list
+//# pragma warning(disable: 4706) // assignment within conditional expression
+# pragma warning(disable: 4251) // class 'A<T>' needs to have dll-interface to be used by clients of class 'B'
+//# pragma warning(disable: 4127) // conditional expression is constant
+//# pragma warning(disable: 4290) // C++ exception specification ignored except to ...
+//# pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored
+# pragma warning(disable: 4275) // non dll-interface class ... used as base for dll-interface class ...
+//# pragma warning(disable: 4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
+//# pragma warning(disable: 4511) // 'class' : copy constructor could not be generated
+#endif
+
+// http://gcc.gnu.org/wiki/Visibility
+// Generic helper definitions for shared library support
+#if defined _WIN32 || defined __CYGWIN__
+ #define UHD_HELPER_DLL_IMPORT __declspec(dllimport)
+ #define UHD_HELPER_DLL_EXPORT __declspec(dllexport)
+ #define UHD_HELPER_DLL_LOCAL
+#else
+ #if __GNUC__ >= 4
+ #define UHD_HELPER_DLL_IMPORT __attribute__ ((visibility("default")))
+ #define UHD_HELPER_DLL_EXPORT __attribute__ ((visibility("default")))
+ #define UHD_HELPER_DLL_LOCAL __attribute__ ((visibility("hidden")))
+ #else
+ #define UHD_HELPER_DLL_IMPORT
+ #define UHD_HELPER_DLL_EXPORT
+ #define UHD_HELPER_DLL_LOCAL
+ #endif
+#endif
+
+// Now we use the generic helper definitions above to define UHD_API and UHD_LOCAL.
+// UHD_API is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build)
+// UHD_LOCAL is used for non-api symbols.
+
+#define UHD_DLL // defined here, put into configuration if we need to make static libs
+
+#ifdef UHD_DLL // defined if UHD is compiled as a DLL
+ #ifdef UHD_DLL_EXPORTS // defined if we are building the UHD DLL (instead of using it)
+ #define UHD_API UHD_HELPER_DLL_EXPORT
+ #else
+ #define UHD_API UHD_HELPER_DLL_IMPORT
+ #endif // UHD_DLL_EXPORTS
+ #define UHD_LOCAL UHD_HELPER_DLL_LOCAL
+#else // UHD_DLL is not defined: this means UHD is a static lib.
+ #define UHD_API
+ #define UHD_LOCAL
+#endif // UHD_DLL
+
+#endif /* INCLUDED_UHD_CONFIG_HPP */
diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp
index dfbfbd7c0..13b40febe 100644
--- a/host/include/uhd/device.hpp
+++ b/host/include/uhd/device.hpp
@@ -18,15 +18,15 @@
#ifndef INCLUDED_UHD_DEVICE_HPP
#define INCLUDED_UHD_DEVICE_HPP
+#include <uhd/config.hpp>
#include <uhd/device_addr.hpp>
#include <uhd/props.hpp>
+#include <uhd/metadata.hpp>
#include <uhd/wax.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/asio/buffer.hpp>
-#include <uhd/shared_iovec.hpp>
-#include <vector>
namespace uhd{
@@ -34,14 +34,23 @@ namespace uhd{
* The usrp device interface represents the usrp hardware.
* The api allows for discovery, configuration, and streaming.
*/
-class device : boost::noncopyable, public wax::obj{
+class UHD_API device : boost::noncopyable, public wax::obj{
public:
typedef boost::shared_ptr<device> sptr;
+ typedef boost::function<device_addrs_t(const device_addr_t &)> discover_t;
+ typedef boost::function<sptr(const device_addr_t &)> make_t;
- //structors
- device(void);
- virtual ~device(void);
+ /*!
+ * Register a device into the discovery and factory system.
+ *
+ * \param discover a function that discovers devices
+ * \param make a factory function that makes a device
+ */
+ static void register_device(
+ const discover_t &discover,
+ const make_t &make
+ );
/*!
* \brief Discover usrp devices attached to the host.
@@ -68,13 +77,60 @@ public:
static sptr make(const device_addr_t &hint, size_t which = 0);
/*!
- * Get the device address for this board.
+ * 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.
+ * It is up to the caller to call send again on the un-sent
+ * portions of the buffer, until the buffer is exhausted.
+ *
+ * This is a blocking call and will not return until the number
+ * of samples returned have been read out of the buffer.
+ *
+ * \param buff a buffer pointing to some read-only memory
+ * \param metadata data describing the buffer's contents
+ * \param the type of data loaded in the buffer (32fc, 16sc)
+ * \return the number of samples sent
*/
- device_addr_t get_device_addr(void);
+ virtual size_t send(
+ const boost::asio::const_buffer &buff,
+ const tx_metadata_t &metadata,
+ const std::string &type = "32fc"
+ ) = 0;
- //the io interface
- virtual void send_raw(const std::vector<boost::asio::const_buffer> &) = 0;
- virtual uhd::shared_iovec recv_raw(void) = 0;
+ /*!
+ * Receive a buffer containing IF data and its metadata.
+ *
+ * Receive handles fragmentation as follows:
+ * If the buffer has insufficient space to hold all samples
+ * that were received in a single packet over-the-wire,
+ * then the buffer will be completely filled and the implementation
+ * will hold a pointer into the remaining portion of the packet.
+ * Subsequent calls will load from the remainder of the packet,
+ * and will flag the metadata to show that this is a fragment.
+ * The next call to receive, after the remainder becomes exahausted,
+ * will perform an over-the-wire receive as usual.
+ *
+ * This is a blocking call and will not return until the number
+ * of samples returned have been written into the buffer.
+ * However, a call to receive may timeout and return zero samples.
+ * The timeout duration is decided by the underlying transport layer.
+ * The caller should assume that the call to receive will not return
+ * immediately when no packets are available to the transport layer,
+ * and that the timeout duration is reasonably tuned for performance.
+ *
+ * \param buff the buffer to fill with IF data
+ * \param metadata data to fill describing the buffer
+ * \param the type of data to fill into the buffer (32fc, 16sc)
+ * \return the number of samples received
+ */
+ virtual size_t recv(
+ const boost::asio::mutable_buffer &buff,
+ rx_metadata_t &metadata,
+ const std::string &type = "32fc"
+ ) = 0;
};
} //namespace uhd
diff --git a/host/include/uhd/device_addr.hpp b/host/include/uhd/device_addr.hpp
index 8ea580321..7673faff0 100644
--- a/host/include/uhd/device_addr.hpp
+++ b/host/include/uhd/device_addr.hpp
@@ -18,11 +18,11 @@
#ifndef INCLUDED_UHD_DEVICE_ADDR_HPP
#define INCLUDED_UHD_DEVICE_ADDR_HPP
+#include <uhd/config.hpp>
#include <uhd/dict.hpp>
+#include <boost/cstdint.hpp>
#include <string>
#include <iostream>
-#include <netinet/ether.h>
-#include <stdint.h>
#include <vector>
namespace uhd{
@@ -31,8 +31,8 @@ namespace uhd{
* Wrapper for an ethernet mac address.
* Provides conversion between string and binary formats.
*/
- struct mac_addr_t{
- struct ether_addr mac_addr;
+ struct UHD_API mac_addr_t{
+ boost::uint8_t mac_addr[6];
mac_addr_t(const std::string &mac_addr_str = "00:00:00:00:00:00");
std::string to_string(void) const;
};
@@ -56,12 +56,14 @@ namespace uhd{
* \param device_addr a device address instance
* \return the string representation
*/
- std::string device_addr_to_string(const device_addr_t &device_addr);
+ namespace device_addr{
+ UHD_API std::string to_string(const device_addr_t &device_addr);
+ }
} //namespace uhd
//ability to use types with stream operators
-std::ostream& operator<<(std::ostream &, const uhd::device_addr_t &);
-std::ostream& operator<<(std::ostream &, const uhd::mac_addr_t &);
+UHD_API std::ostream& operator<<(std::ostream &, const uhd::device_addr_t &);
+UHD_API std::ostream& operator<<(std::ostream &, const uhd::mac_addr_t &);
#endif /* INCLUDED_UHD_DEVICE_ADDR_HPP */
diff --git a/host/include/uhd/dict.hpp b/host/include/uhd/dict.hpp
index 1ed28551a..f08493952 100644
--- a/host/include/uhd/dict.hpp
+++ b/host/include/uhd/dict.hpp
@@ -18,7 +18,7 @@
#ifndef INCLUDED_UHD_DICT_HPP
#define INCLUDED_UHD_DICT_HPP
-#include <map>
+#include <list>
#include <vector>
#include <stdexcept>
#include <boost/foreach.hpp>
@@ -27,11 +27,9 @@ namespace uhd{
/*!
* A templated dictionary class with a python-like interface.
- * Its wraps around a std::map internally.
*/
template <class Key, class Val> class dict{
public:
- typedef std::map<Key, Val> map_t;
typedef std::pair<Key, Val> pair_t;
/*!
@@ -42,11 +40,16 @@ namespace uhd{
}
/*!
- * Create a dictionary from a map.
- * \param map a map with key value pairs
+ * Input iterator constructor:
+ * Makes boost::assign::map_list_of work.
+ * \param first the begin iterator
+ * \param last the end iterator
*/
- dict(const map_t &map){
- _map = map;
+ template <class InputIterator>
+ dict(InputIterator first, InputIterator last){
+ for(InputIterator it = first; it != last; it++){
+ _map.push_back(*it);
+ }
}
/*!
@@ -57,12 +60,21 @@ namespace uhd{
}
/*!
+ * Get the number of elements in this dict.
+ * \param the number of elements
+ */
+ std::size_t size(void) const{
+ return _map.size();
+ }
+
+ /*!
* Get a list of the keys in this dict.
+ * Key order depends on insertion precedence.
* \return vector of keys
*/
std::vector<Key> get_keys(void) const{
std::vector<Key> keys;
- BOOST_FOREACH(pair_t p, _map){
+ BOOST_FOREACH(const pair_t &p, _map){
keys.push_back(p.first);
}
return keys;
@@ -70,11 +82,12 @@ namespace uhd{
/*!
* Get a list of the values in this dict.
+ * Value order depends on insertion precedence.
* \return vector of values
*/
std::vector<Val> get_vals(void) const{
std::vector<Val> vals;
- BOOST_FOREACH(pair_t p, _map){
+ BOOST_FOREACH(const pair_t &p, _map){
vals.push_back(p.second);
}
return vals;
@@ -86,7 +99,7 @@ namespace uhd{
* \return true if found
*/
bool has_key(const Key &key) const{
- BOOST_FOREACH(pair_t p, _map){
+ BOOST_FOREACH(const pair_t &p, _map){
if (p.first == key) return true;
}
return false;
@@ -100,8 +113,8 @@ namespace uhd{
* \throw an exception when not found
*/
const Val &operator[](const Key &key) const{
- if (has_key(key)){
- return _map.find(key)->second;
+ BOOST_FOREACH(const pair_t &p, _map){
+ if (p.first == key) return p.second;
}
throw std::invalid_argument("key not found in dict");
}
@@ -113,7 +126,11 @@ namespace uhd{
* \return a reference to the value
*/
Val &operator[](const Key &key){
- return _map[key];
+ BOOST_FOREACH(pair_t &p, _map){
+ if (p.first == key) return p.second;
+ }
+ _map.push_back(pair_t(key, Val()));
+ return _map.back().second;
}
/*!
@@ -122,17 +139,14 @@ namespace uhd{
* \return the value of the item
* \throw an exception when not found
*/
- Val pop_key(const Key &key){
- if (has_key(key)){
- Val val = _map.find(key)->second;
- _map.erase(key);
- return val;
- }
- throw std::invalid_argument("key not found in dict");
+ Val pop(const Key &key){
+ Val val = (*this)[key];
+ _map.remove(pair_t(key, val));
+ return val;
}
private:
- map_t _map; //private container
+ std::list<pair_t> _map; //private container
};
} //namespace uhd
diff --git a/host/include/uhd/gain_handler.hpp b/host/include/uhd/gain_handler.hpp
index 06800315a..65d6cecf9 100644
--- a/host/include/uhd/gain_handler.hpp
+++ b/host/include/uhd/gain_handler.hpp
@@ -15,43 +15,50 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <boost/shared_ptr.hpp>
-#include <uhd/wax.hpp>
-#include <uhd/props.hpp>
-#include <boost/function.hpp>
-#include <boost/bind.hpp>
-
#ifndef INCLUDED_UHD_GAIN_HANDLER_HPP
#define INCLUDED_UHD_GAIN_HANDLER_HPP
+#include <uhd/config.hpp>
+#include <uhd/wax.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+
namespace uhd{
-class gain_handler{
+class UHD_API gain_handler{
public:
typedef boost::shared_ptr<gain_handler> sptr;
+ typedef boost::function<bool(const wax::obj &, const wax::obj &)> is_equal_t;
- template <class T> gain_handler(
- wax::obj *wax_obj_ptr, const T &gain_prop,
- const T &gain_min_prop, const T &gain_max_prop,
- const T &gain_step_prop, const T &gain_names_prop
- ){
- _wax_obj_ptr = wax_obj_ptr;
- _gain_prop = gain_prop;
- _gain_min_prop = gain_min_prop;
- _gain_max_prop = gain_max_prop;
- _gain_step_prop = gain_step_prop;
- _gain_names_prop = gain_names_prop;
- _is_equal = boost::bind(&gain_handler::is_equal<T>, _1, _2);
- }
+ /*!
+ * A set of properties for dealing with gains.
+ */
+ struct UHD_API props_t{
+ wax::obj value, range, names;
+ props_t(void); //default constructor
+ };
- ~gain_handler(void);
+ /*!
+ * Make a new gain handler.
+ * The construction arguments are agnostic to the property type.
+ * It is up to the caller to provide an "is_equal" function that
+ * can tell weather two properties (in a wax obj) are equal.
+ * \param link a link to the wax obj with properties
+ * \param props a struct of properties keys
+ * \param is_equal the function that tests for equal properties
+ */
+ static sptr make(
+ const wax::obj &link,
+ const props_t &props,
+ is_equal_t is_equal
+ );
/*!
* Intercept gets for overall gain, min, max, step.
* Ensures that the gain name is valid.
* \return true for handled, false to pass on
*/
- bool intercept_get(const wax::obj &key, wax::obj &val);
+ virtual bool intercept_get(const wax::obj &key, wax::obj &val) = 0;
/*!
* Intercept sets for overall gain.
@@ -59,39 +66,21 @@ public:
* Ensures that the new gain is within range.
* \return true for handled, false to pass on
*/
- bool intercept_set(const wax::obj &key, const wax::obj &val);
-
-private:
-
- wax::obj *_wax_obj_ptr;
- wax::obj _gain_prop;
- wax::obj _gain_min_prop;
- wax::obj _gain_max_prop;
- wax::obj _gain_step_prop;
- wax::obj _gain_names_prop;
+ virtual bool intercept_set(const wax::obj &key, const wax::obj &val) = 0;
/*!
- * Verify that the key is valid:
- * If its a named prop for gain, ensure that name is valid.
- * If the name if not valid, throw a std::invalid_argument.
- * The name can only be valid if its in the list of gain names.
- */
- void _check_key(const wax::obj &key);
-
- /*
- * Private interface to test if two wax types are equal:
+ * Function template to test if two wax types are equal:
* The constructor will bind an instance of this for a specific type.
* This bound equals functions allows the intercept methods to be non-templated.
*/
template <class T> static bool is_equal(const wax::obj &a, const wax::obj &b){
try{
- return wax::cast<T>(a) == wax::cast<T>(b);
+ return a.as<T>() == b.as<T>();
}
catch(const wax::bad_cast &){
return false;
}
}
- boost::function<bool(const wax::obj &, const wax::obj &)> _is_equal;
};
diff --git a/host/include/uhd/metadata.hpp b/host/include/uhd/metadata.hpp
new file mode 100644
index 000000000..6d80f070d
--- /dev/null
+++ b/host/include/uhd/metadata.hpp
@@ -0,0 +1,61 @@
+//
+// 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_UHD_METADATA_HPP
+#define INCLUDED_UHD_METADATA_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/time_spec.hpp>
+
+namespace uhd{
+
+/*!
+ * RX metadata structure for describing sent IF data.
+ * Includes stream ID, time specification, and fragmentation flags.
+ * The receive routines will convert IF data headers into metadata.
+ */
+struct UHD_API rx_metadata_t{
+ boost::uint32_t stream_id;
+ time_spec_t time_spec;
+ bool has_stream_id;
+ bool has_time_spec;
+ bool is_fragment;
+
+ //default constructor
+ rx_metadata_t(void);
+};
+
+/*!
+ * TX metadata structure for describing received IF data.
+ * Includes stream ID, time specification, and burst flags.
+ * The send routines will convert the metadata to IF data headers.
+ */
+struct UHD_API tx_metadata_t{
+ boost::uint32_t stream_id;
+ time_spec_t time_spec;
+ bool has_stream_id;
+ bool has_time_spec;
+ bool start_of_burst;
+ bool end_of_burst;
+
+ //default constructor
+ tx_metadata_t(void);
+};
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_METADATA_HPP */
diff --git a/host/include/uhd/props.hpp b/host/include/uhd/props.hpp
index 2b6daf6c5..41e0eff63 100644
--- a/host/include/uhd/props.hpp
+++ b/host/include/uhd/props.hpp
@@ -15,30 +15,16 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <boost/tuple/tuple.hpp>
-#include <uhd/time_spec.hpp>
-#include <uhd/wax.hpp>
-#include <complex>
-#include <vector>
-
#ifndef INCLUDED_UHD_PROPS_HPP
#define INCLUDED_UHD_PROPS_HPP
-namespace uhd{
-
- //common typedefs for board properties
- typedef float gain_t;
- typedef double freq_t;
-
- //scalar types (have not used yet, dont uncomment until needed)
- //typedef int int_scalar_t;
- //typedef float real_scalar_t;
- //typedef std::complex<real_scalar_t> complex_scalar_t;
+#include <uhd/config.hpp>
+#include <uhd/wax.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <vector>
+#include <string>
- //vector types (have not used yet, dont uncomment until needed)
- //typedef std::vector<int_scalar_t> int_vec_t;
- //typedef std::vector<real_scalar_t> real_vec_t;
- //typedef std::vector<complex_scalar_t> complex_vec_t;
+namespace uhd{
//typedef for handling named properties
typedef std::vector<std::string> prop_names_t;
@@ -49,9 +35,10 @@ namespace uhd{
* \param key a reference to the prop object
* \param name a reference to the name object
*/
- inline named_prop_t extract_named_prop(const wax::obj &key, const std::string &name = ""){
+ inline UHD_API named_prop_t //must be exported as part of the api to work (TODO move guts to cpp file)
+ extract_named_prop(const wax::obj &key, const std::string &name = ""){
if (key.type() == typeid(named_prop_t)){
- return wax::cast<named_prop_t>(key);
+ return key.as<named_prop_t>();
}
return named_prop_t(key, name);
}
@@ -65,7 +52,9 @@ namespace uhd{
enum device_prop_t{
DEVICE_PROP_NAME, //ro, std::string
DEVICE_PROP_MBOARD, //ro, wax::obj
- DEVICE_PROP_MBOARD_NAMES //ro, prop_names_t
+ DEVICE_PROP_MBOARD_NAMES, //ro, prop_names_t
+ DEVICE_PROP_MAX_RX_SAMPLES, //ro, size_t
+ DEVICE_PROP_MAX_TX_SAMPLES //ro, size_t
};
/*!
@@ -77,7 +66,6 @@ namespace uhd{
enum mboard_prop_t{
MBOARD_PROP_NAME, //ro, std::string
MBOARD_PROP_OTHERS, //ro, prop_names_t
- MBOARD_PROP_MTU, //ro, size_t
MBOARD_PROP_CLOCK_RATE, //ro, freq_t
MBOARD_PROP_RX_DSP, //ro, wax::obj
MBOARD_PROP_RX_DSP_NAMES, //ro, prop_names_t
@@ -87,10 +75,8 @@ namespace uhd{
MBOARD_PROP_RX_DBOARD_NAMES, //ro, prop_names_t
MBOARD_PROP_TX_DBOARD, //ro, wax::obj
MBOARD_PROP_TX_DBOARD_NAMES, //ro, prop_names_t
- MBOARD_PROP_PPS_SOURCE, //rw, std::string (sma, mimo)
+ MBOARD_PROP_CLOCK_CONFIG, //rw, clock_config_t
MBOARD_PROP_PPS_SOURCE_NAMES, //ro, prop_names_t
- MBOARD_PROP_PPS_POLARITY, //rw, std::string (pos, neg)
- MBOARD_PROP_REF_SOURCE, //rw, std::string (int, sma, mimo)
MBOARD_PROP_REF_SOURCE_NAMES, //ro, prop_names_t
MBOARD_PROP_TIME_NOW, //wo, time_spec_t
MBOARD_PROP_TIME_NEXT_PPS //wo, time_spec_t
@@ -116,24 +102,23 @@ namespace uhd{
DBOARD_PROP_NAME, //ro, std::string
DBOARD_PROP_SUBDEV, //ro, wax::obj
DBOARD_PROP_SUBDEV_NAMES, //ro, prop_names_t
- DBOARD_PROP_CODEC //ro, wax::obj
- };
+ DBOARD_PROP_USED_SUBDEVS //ro, prop_names_t
+ //DBOARD_PROP_CODEC //ro, wax::obj //----> not sure, dont have to deal with yet
+ };
- /*!
+ /*! ------ not dealing with yet, commented out ------------
* Possible device codec properties:
* A codec is expected to have a rate and gain elements.
* Other properties can be discovered through the others prop.
*/
- enum codec_prop_t{
+ /*enum codec_prop_t{
CODEC_PROP_NAME, //ro, std::string
CODEC_PROP_OTHERS, //ro, prop_names_t
CODEC_PROP_GAIN, //rw, gain_t
- CODEC_PROP_GAIN_MAX, //ro, gain_t
- CODEC_PROP_GAIN_MIN, //ro, gain_t
- CODEC_PROP_GAIN_STEP, //ro, gain_t
+ CODEC_PROP_GAIN_RANGE, //ro, gain_range_t
CODEC_PROP_GAIN_NAMES, //ro, prop_names_t
- CODEC_PROP_CLOCK_RATE //ro, freq_t
- };
+ //CODEC_PROP_CLOCK_RATE //ro, freq_t //----> not sure we care to know
+ };*/
/*!
* Possible device subdev properties
@@ -142,22 +127,19 @@ namespace uhd{
SUBDEV_PROP_NAME, //ro, std::string
SUBDEV_PROP_OTHERS, //ro, prop_names_t
SUBDEV_PROP_GAIN, //rw, gain_t
- SUBDEV_PROP_GAIN_MAX, //ro, gain_t
- SUBDEV_PROP_GAIN_MIN, //ro, gain_t
- SUBDEV_PROP_GAIN_STEP, //ro, gain_t
+ SUBDEV_PROP_GAIN_RANGE, //ro, gain_range_t
SUBDEV_PROP_GAIN_NAMES, //ro, prop_names_t
SUBDEV_PROP_FREQ, //rw, freq_t
- SUBDEV_PROP_FREQ_MAX, //ro, freq_t
- SUBDEV_PROP_FREQ_MIN, //ro, freq_t
+ SUBDEV_PROP_FREQ_RANGE, //ro, freq_range_t
SUBDEV_PROP_ANTENNA, //rw, std::string
SUBDEV_PROP_ANTENNA_NAMES, //ro, prop_names_t
SUBDEV_PROP_ENABLED, //rw, bool
SUBDEV_PROP_QUADRATURE, //ro, bool
SUBDEV_PROP_IQ_SWAPPED, //ro, bool
SUBDEV_PROP_SPECTRUM_INVERTED, //ro, bool
- SUBDEV_PROP_IS_TX, //ro, bool
- SUBDEV_PROP_RSSI, //ro, gain_t
- SUBDEV_PROP_BANDWIDTH //rw, freq_t
+ SUBDEV_PROP_LO_INTERFERES //ro, bool
+ //SUBDEV_PROP_RSSI, //ro, gain_t //----> not on all boards, use named prop
+ //SUBDEV_PROP_BANDWIDTH //rw, freq_t //----> not on all boards, use named prop
};
} //namespace uhd
diff --git a/host/include/uhd/shared_iovec.hpp b/host/include/uhd/shared_iovec.hpp
deleted file mode 100644
index a120e55d5..000000000
--- a/host/include/uhd/shared_iovec.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#ifndef INCLUDED_UHD_SHARED_IOVEC_HPP
-#define INCLUDED_UHD_SHARED_IOVEC_HPP
-
-#include <boost/shared_array.hpp>
-#include <stdint.h>
-
-namespace uhd{
-
-/*!
- * A shared iovec contains a shared array and its length.
- * Creating a new shared iovec allocates new memory.
- * This memory is freed when all copies are destroyed.
- */
-class shared_iovec{
-public:
- /*!
- * Create a shared iovec and allocate memory.
- * \param len the length in bytes
- */
- shared_iovec(size_t len=0);
-
- /*!
- * Destroy a shared iovec.
- * Will not free the memory unless this is the last copy.
- */
- ~shared_iovec(void);
-
- void *base;
- size_t len;
-
-private:
- boost::shared_array<uint8_t> _shared_array;
-};
-
-} //namespace uhd
-
-#endif /* INCLUDED_UHD_SHARED_IOVEC_HPP */
diff --git a/host/include/uhd/simple_device.hpp b/host/include/uhd/simple_device.hpp
new file mode 100644
index 000000000..ad25eccdc
--- /dev/null
+++ b/host/include/uhd/simple_device.hpp
@@ -0,0 +1,90 @@
+//
+// 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_UHD_SIMPLE_DEVICE_HPP
+#define INCLUDED_UHD_SIMPLE_DEVICE_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/device.hpp>
+#include <uhd/types.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include <vector>
+
+namespace uhd{
+
+/*!
+ * The simple UHD device class:
+ * A simple device facilitates ease-of-use for most use-case scenarios.
+ * The wrapper provides convenience functions to tune the devices
+ * as well as to set the dboard gains, antennas, and other properties.
+ */
+class UHD_API simple_device : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<simple_device> sptr;
+ static sptr make(const std::string &args);
+
+ virtual device::sptr get_device(void) = 0;
+
+ virtual std::string get_name(void) = 0;
+
+ /*******************************************************************
+ * Streaming
+ ******************************************************************/
+ virtual void set_streaming(bool enb) = 0;
+ virtual bool get_streaming(void) = 0;
+
+ /*******************************************************************
+ * RX methods
+ ******************************************************************/
+ virtual void set_rx_rate(double rate) = 0;
+ virtual double get_rx_rate(void) = 0;
+ virtual std::vector<double> get_rx_rates(void) = 0;
+
+ virtual tune_result_t set_rx_freq(double freq) = 0;
+ virtual freq_range_t get_rx_freq_range(void) = 0;
+
+ virtual void set_rx_gain(float gain) = 0;
+ virtual float get_rx_gain(void) = 0;
+ virtual gain_range_t get_rx_gain_range(void) = 0;
+
+ virtual void set_rx_antenna(const std::string &ant) = 0;
+ virtual std::string get_rx_antenna(void) = 0;
+ virtual std::vector<std::string> get_rx_antennas(void) = 0;
+
+ /*******************************************************************
+ * TX methods
+ ******************************************************************/
+ virtual void set_tx_rate(double rate) = 0;
+ virtual double get_tx_rate(void) = 0;
+ virtual std::vector<double> get_tx_rates(void) = 0;
+
+ virtual tune_result_t set_tx_freq(double freq) = 0;
+ virtual freq_range_t get_tx_freq_range(void) = 0;
+
+ virtual void set_tx_gain(float gain) = 0;
+ virtual float get_tx_gain(void) = 0;
+ virtual gain_range_t get_tx_gain_range(void) = 0;
+
+ virtual void set_tx_antenna(const std::string &ant) = 0;
+ virtual std::string get_tx_antenna(void) = 0;
+ virtual std::vector<std::string> get_tx_antennas(void) = 0;
+};
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_SIMPLE_DEVICE_HPP */
diff --git a/host/include/uhd/time_spec.hpp b/host/include/uhd/time_spec.hpp
index e5657e555..c1e7cf3a1 100644
--- a/host/include/uhd/time_spec.hpp
+++ b/host/include/uhd/time_spec.hpp
@@ -15,11 +15,13 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <stdint.h>
-
#ifndef INCLUDED_UHD_TIME_SPEC_HPP
#define INCLUDED_UHD_TIME_SPEC_HPP
+#include <uhd/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
namespace uhd{
/*!
@@ -28,28 +30,30 @@ namespace uhd{
* The time_spec_t can be used when setting the time on devices
* and for controlling the start of streaming for applicable dsps.
*/
- struct time_spec_t{
- uint32_t secs;
- uint32_t ticks;
+ struct UHD_API time_spec_t{
+ boost::uint32_t secs;
+ boost::uint32_t ticks;
/*!
* Create a time_spec_t that holds a wildcard time.
* This will have implementation-specific meaning.
*/
- time_spec_t(void){
- secs = ~0;
- ticks = ~0;
- }
+ time_spec_t(void);
/*!
* Create a time_spec_t from seconds and ticks.
* \param new_secs the new seconds
* \param new_ticks the new ticks (default = 0)
*/
- time_spec_t(uint32_t new_secs, uint32_t new_ticks = 0){
- secs = new_secs;
- ticks = new_ticks;
- }
+ time_spec_t(boost::uint32_t new_secs, boost::uint32_t new_ticks = 0);
+
+ /*!
+ * Create a time_spec_t from boost posix time.
+ * \param time fine-grained boost posix time
+ * \param tick_rate the rate of ticks per second
+ */
+ time_spec_t(boost::posix_time::ptime time, double tick_rate);
+
};
} //namespace uhd
diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt
index b786eb945..7f5db2128 100644
--- a/host/include/uhd/transport/CMakeLists.txt
+++ b/host/include/uhd/transport/CMakeLists.txt
@@ -17,6 +17,9 @@
INSTALL(FILES
- udp.hpp
+ smart_buffer.hpp
+ udp_simple.hpp
+ udp_zero_copy.hpp
+ vrt.hpp
DESTINATION ${HEADER_DIR}/uhd/transport
)
diff --git a/host/include/uhd/transport/smart_buffer.hpp b/host/include/uhd/transport/smart_buffer.hpp
new file mode 100644
index 000000000..9e1032feb
--- /dev/null
+++ b/host/include/uhd/transport/smart_buffer.hpp
@@ -0,0 +1,45 @@
+//
+// 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_UHD_TRANSPORT_SMART_BUFFER_HPP
+#define INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP
+
+#include <boost/asio.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace uhd{ namespace transport{
+
+/*!
+ * A buffer that knows how to free itself:
+ *
+ * This is just the smart buffer interface.
+ * A transport implementation will have its own
+ * internal (custom) smart buffer implementation.
+ *
+ * A smart buffer contains a boost asio const buffer.
+ * On destruction, the buffer contents will be freed.
+ */
+class smart_buffer : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<smart_buffer> sptr;
+ virtual const boost::asio::const_buffer &get(void) const = 0;
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP */
diff --git a/host/include/uhd/transport/udp.hpp b/host/include/uhd/transport/udp.hpp
deleted file mode 100644
index 6db6bd377..000000000
--- a/host/include/uhd/transport/udp.hpp
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#include <boost/asio.hpp>
-#include <boost/utility.hpp>
-#include <boost/shared_ptr.hpp>
-#include <uhd/shared_iovec.hpp>
-
-#ifndef INCLUDED_UHD_TRANSPORT_UDP_HPP
-#define INCLUDED_UHD_TRANSPORT_UDP_HPP
-
-namespace uhd{ namespace transport{
-
-class udp : boost::noncopyable{
-public:
- typedef boost::shared_ptr<udp> sptr;
-
- /*!
- * Constructor.
- * The address will be resolved, it can be a host name or ipv4.
- * The port will be resolved, it can be a port type or number.
- * \param addr a string representing the destination address
- * \param port a string representing the destination port
- * \param bcast if true, enable the broadcast option on the socket
- */
- udp(const std::string &addr, const std::string &port, bool bcast = false);
-
- /*!
- * Destructor
- */
- ~udp(void);
-
- /*!
- * Send a vector of buffer (like send_msg).
- * \param buffs a vector of asio buffers
- */
- void send(const std::vector<boost::asio::const_buffer> &buffs);
-
- /*!
- * Send a single buffer.
- * \param buff single asio buffer
- */
- void send(const boost::asio::const_buffer &buff);
-
- /*!
- * Receive a buffer. The memory is managed internally.
- * Calling recv will invalidate the buffer of the previous recv.
- * \return a shared iovec with allocated memory
- */
- uhd::shared_iovec recv(void);
-
-private:
- boost::asio::ip::udp::socket *_socket;
- boost::asio::ip::udp::endpoint _receiver_endpoint;
- boost::asio::ip::udp::endpoint _sender_endpoint;
- boost::asio::io_service _io_service;
-};
-
-}} //namespace
-
-#endif /* INCLUDED_UHD_TRANSPORT_UDP_HPP */
diff --git a/host/include/uhd/transport/udp_simple.hpp b/host/include/uhd/transport/udp_simple.hpp
new file mode 100644
index 000000000..40e60d091
--- /dev/null
+++ b/host/include/uhd/transport/udp_simple.hpp
@@ -0,0 +1,80 @@
+//
+// 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_UHD_TRANSPORT_UDP_SIMPLE_HPP
+#define INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP
+
+#include <uhd/config.hpp>
+#include <boost/asio.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace uhd{ namespace transport{
+
+class UHD_API udp_simple : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<udp_simple> sptr;
+
+ /*!
+ * Make a new connected udp transport:
+ * This transport is for sending and receiving
+ * between this host and a single endpoint.
+ * The primary usage for this transport will be control transactions.
+ * The underlying implementation is simple and portable (not fast).
+ *
+ * The address will be resolved, it can be a host name or ipv4.
+ * The port will be resolved, it can be a port type or number.
+ *
+ * \param addr a string representing the destination address
+ * \param port a string representing the destination port
+ */
+ static sptr make_connected(const std::string &addr, const std::string &port);
+
+ /*!
+ * Make a new broadcasting udp transport:
+ * This transport can send udp broadcast datagrams
+ * and receive datagrams from multiple sources.
+ * The primary usage for this transport will be to discover devices.
+ *
+ * The address will be resolved, it can be a host name or ipv4.
+ * The port will be resolved, it can be a port type or number.
+ *
+ * \param addr a string representing the destination address
+ * \param port a string representing the destination port
+ */
+ static sptr make_broadcast(const std::string &addr, const std::string &port);
+
+ /*!
+ * Send a single buffer.
+ * Blocks until the data is sent.
+ * \param buff single asio buffer
+ * \return the number of bytes sent
+ */
+ virtual size_t send(const boost::asio::const_buffer &buff) = 0;
+
+ /*!
+ * Receive into the provided buffer.
+ * Blocks until data is received or a timeout occurs.
+ * \param buff a mutable buffer to receive into
+ * \return the number of bytes received or zero on timeout
+ */
+ virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0;
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP */
diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp
new file mode 100644
index 000000000..03d89b3a5
--- /dev/null
+++ b/host/include/uhd/transport/udp_zero_copy.hpp
@@ -0,0 +1,77 @@
+//
+// 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_UHD_TRANSPORT_UDP_ZERO_COPY_HPP
+#define INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/transport/smart_buffer.hpp>
+#include <boost/asio.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace uhd{ namespace transport{
+
+/*!
+ * A zero copy udp transport provides an efficient way to handle data.
+ * by avoiding the extra copy when recv() is called on the socket.
+ * Rather, the zero copy transport gives the caller a memory reference.
+ * The caller informs the transport when it is finished with the reference.
+ *
+ * On linux systems, the zero copy transport can use a kernel packet ring.
+ * If no platform specific solution is available, make returns a boost asio
+ * implementation that wraps the functionality around a standard recv() call.
+ */
+class UHD_API udp_zero_copy : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<udp_zero_copy> sptr;
+
+ /*!
+ * Make a new zero copy udp transport:
+ * This transport is for sending and receiving
+ * between this host and a single endpoint.
+ * The primary usage for this transport will be data transactions.
+ * The underlying implementation is fast and platform specific.
+ *
+ * The address will be resolved, it can be a host name or ipv4.
+ * The port will be resolved, it can be a port type or number.
+ *
+ * \param addr a string representing the destination address
+ * \param port a string representing the destination port
+ */
+ static sptr make(const std::string &addr, const std::string &port);
+
+ /*!
+ * Send a single buffer.
+ * Blocks until the data is sent.
+ * \param buff single asio buffer
+ * \return the number of bytes sent
+ */
+ virtual size_t send(const boost::asio::const_buffer &buff) = 0;
+
+ /*!
+ * Receive a buffer.
+ * Blocks until data is received or a timeout occurs.
+ * The memory is managed by the implementation.
+ * \return a smart buffer (empty on timeout)
+ */
+ virtual smart_buffer::sptr recv(void) = 0;
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP */
diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp
new file mode 100644
index 000000000..db2c57eba
--- /dev/null
+++ b/host/include/uhd/transport/vrt.hpp
@@ -0,0 +1,71 @@
+//
+// 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_UHD_TRANSPORT_VRT_HPP
+#define INCLUDED_UHD_TRANSPORT_VRT_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/metadata.hpp>
+#include <cstddef>
+
+namespace uhd{ namespace transport{
+
+namespace vrt{
+
+ static const size_t max_header_words32 = 7;
+
+ /*!
+ * Pack a vrt header from metadata.
+ * \param metadata the tx metadata with flags and timestamps
+ * \param header_buff memory to write the packed vrt header
+ * \param num_header_words32 number of words in the vrt header
+ * \param num_payload_words32 the length of the payload
+ * \param num_packet_words32 the length of the packet
+ * \param packet_count the packet count sequence number
+ */
+ UHD_API void pack(
+ const tx_metadata_t &metadata, //input
+ boost::uint32_t *header_buff, //output
+ size_t &num_header_words32, //output
+ size_t num_payload_words32, //input
+ size_t &num_packet_words32, //output
+ size_t packet_count //input
+ );
+
+ /*!
+ * Unpack a vrt header to metadata.
+ * \param metadata the rx metadata with flags and timestamps
+ * \param header_buff memory to read the packed vrt header
+ * \param num_header_words32 number of words in the vrt header
+ * \param num_payload_words32 the length of the payload
+ * \param num_packet_words32 the length of the packet
+ * \param packet_count the packet count sequence number
+ */
+ UHD_API void unpack(
+ rx_metadata_t &metadata, //output
+ const boost::uint32_t *header_buff, //input
+ size_t &num_header_words32, //output
+ size_t &num_payload_words32, //output
+ size_t num_packet_words32, //input
+ size_t &packet_count //output
+ );
+
+} //namespace vrt
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_VRT_HPP */
diff --git a/host/include/uhd/types.hpp b/host/include/uhd/types.hpp
new file mode 100644
index 000000000..1439f57a1
--- /dev/null
+++ b/host/include/uhd/types.hpp
@@ -0,0 +1,83 @@
+//
+// 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_UHD_TYPES_HPP
+#define INCLUDED_UHD_TYPES_HPP
+
+#include <uhd/config.hpp>
+#include <string>
+
+namespace uhd{
+
+ typedef float gain_t; //TODO REMOVE
+ typedef double freq_t; //TODO REMOVE
+
+ /*!
+ * The gain range struct describes possible gain settings.
+ * The mimumum gain, maximum gain, and step size are in dB.
+ */
+ struct UHD_API gain_range_t{
+ float min, max, step;
+ gain_range_t(float min = 0.0, float max = 0.0, float step = 0.0);
+ };
+
+ /*!
+ * The frequency range struct describes possible frequency settings.
+ * Because tuning is very granular (sub-Hz), step size is not listed.
+ * The mimumum frequency and maximum frequency are in Hz.
+ */
+ struct UHD_API freq_range_t{
+ double min, max;
+ freq_range_t(double min = 0.0, double max = 0.0);
+ };
+
+ /*!
+ * The tune result struct holds result of a 2-phase tuning:
+ * The struct hold the result of tuning the dboard as
+ * the target and actual intermediate frequency.
+ * The struct hold the result of tuning the DDC/DUC as
+ * the target and actual digital converter frequency.
+ * It also tell us weather or not the spectrum is inverted.
+ */
+ struct UHD_API tune_result_t{
+ double target_inter_freq;
+ double actual_inter_freq;
+ double target_dxc_freq;
+ double actual_dxc_freq;
+ bool spectrum_inverted;
+ tune_result_t(void);
+ };
+
+ /*!
+ * Clock configuration settings:
+ * The source for the 10MHz reference clock.
+ * The source and polarity for the PPS clock.
+ * Possible settings for the reference and pps source
+ * are implementation specific motherboard properties.
+ * See the MBOARD_PROP_XXX_SOURCE_NAMES properties.
+ */
+ struct clock_config_t{
+ enum polarity_t {POLARITY_NEG, POLARITY_POS};
+ std::string ref_source;
+ std::string pps_source;
+ polarity_t pps_polarity;
+ clock_config_t(void);
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_HPP */
diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt
index e7bdc1784..4e0a92365 100644
--- a/host/include/uhd/usrp/CMakeLists.txt
+++ b/host/include/uhd/usrp/CMakeLists.txt
@@ -21,6 +21,7 @@ INSTALL(FILES
dboard_id.hpp
dboard_interface.hpp
dboard_manager.hpp
+ usrp1e.hpp
usrp2.hpp
DESTINATION ${HEADER_DIR}/uhd/usrp
)
diff --git a/host/include/uhd/usrp/dboard_base.hpp b/host/include/uhd/usrp/dboard_base.hpp
index b5c0d40ed..907a7814a 100644
--- a/host/include/uhd/usrp/dboard_base.hpp
+++ b/host/include/uhd/usrp/dboard_base.hpp
@@ -18,6 +18,7 @@
#ifndef INCLUDED_UHD_USRP_DBOARD_BASE_HPP
#define INCLUDED_UHD_USRP_DBOARD_BASE_HPP
+#include <uhd/config.hpp>
#include <uhd/wax.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
@@ -31,7 +32,7 @@ namespace uhd{ namespace usrp{
* A daughter board dboard_base class for all dboards.
* Only other dboard dboard_base classes should inherit this.
*/
-class dboard_base : boost::noncopyable{
+class UHD_API dboard_base : boost::noncopyable{
public:
typedef boost::shared_ptr<dboard_base> sptr;
//the constructor args consist of a subdev name and an interface
@@ -56,21 +57,22 @@ protected:
dboard_id_t get_tx_id(void);
private:
- std::string _subdev_name;
+ std::string _subdev_name;
dboard_interface::sptr _dboard_interface;
- dboard_id_t _rx_id, _tx_id;
+ dboard_id_t _rx_id, _tx_id;
};
/*!
* A xcvr daughter board implements rx and tx methods
* Sub classes for xcvr boards should inherit this.
*/
-class xcvr_dboard_base : public dboard_base{
+class UHD_API xcvr_dboard_base : public dboard_base{
public:
/*!
* Create a new xcvr dboard object, override in subclasses.
*/
xcvr_dboard_base(ctor_args_t const&);
+
virtual ~xcvr_dboard_base(void);
};
@@ -78,7 +80,7 @@ public:
* A rx daughter board only implements rx methods.
* Sub classes for rx-only boards should inherit this.
*/
-class rx_dboard_base : public dboard_base{
+class UHD_API rx_dboard_base : public dboard_base{
public:
/*!
* Create a new rx dboard object, override in subclasses.
@@ -96,7 +98,7 @@ public:
* A tx daughter board only implements tx methods.
* Sub classes for rx-only boards should inherit this.
*/
-class tx_dboard_base : public dboard_base{
+class UHD_API tx_dboard_base : public dboard_base{
public:
/*!
* Create a new rx dboard object, override in subclasses.
diff --git a/host/include/uhd/usrp/dboard_id.hpp b/host/include/uhd/usrp/dboard_id.hpp
index 8e904ff33..4b2392bee 100644
--- a/host/include/uhd/usrp/dboard_id.hpp
+++ b/host/include/uhd/usrp/dboard_id.hpp
@@ -15,22 +15,23 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <string>
-
#ifndef INCLUDED_UHD_USRP_DBOARD_ID_HPP
#define INCLUDED_UHD_USRP_DBOARD_ID_HPP
+#include <uhd/config.hpp>
+#include <boost/cstdint.hpp>
+#include <string>
+
namespace uhd{ namespace usrp{
-enum dboard_id_t{
- ID_NONE = 0xffff,
- ID_BASIC_TX = 0x0000,
- ID_BASIC_RX = 0x0001
-};
+typedef boost::uint16_t dboard_id_t;
+
+static const dboard_id_t ID_NONE = 0xffff; //TODO: REMOVE ME
-struct dboard_id{
- static std::string to_string(const dboard_id_t &id);
-};
+namespace dboard_id{
+ static const dboard_id_t NONE = 0xffff;
+ UHD_API std::string to_string(const dboard_id_t &id);
+}
}} //namespace
diff --git a/host/include/uhd/usrp/dboard_interface.hpp b/host/include/uhd/usrp/dboard_interface.hpp
index 84e1f5b22..5b40616f0 100644
--- a/host/include/uhd/usrp/dboard_interface.hpp
+++ b/host/include/uhd/usrp/dboard_interface.hpp
@@ -18,9 +18,10 @@
#ifndef INCLUDED_UHD_USRP_DBOARD_INTERFACE_HPP
#define INCLUDED_UHD_USRP_DBOARD_INTERFACE_HPP
+#include <uhd/config.hpp>
#include <boost/shared_ptr.hpp>
+#include <boost/cstdint.hpp>
#include <vector>
-#include <stdint.h>
namespace uhd{ namespace usrp{
@@ -30,10 +31,10 @@ namespace uhd{ namespace usrp{
* This dboard_interface provides i2c, spi, gpio, atr, aux dac/adc access.
* Each mboard should have a specially tailored dboard dboard_interface.
*/
-class dboard_interface{
+class UHD_API dboard_interface{
public:
typedef boost::shared_ptr<dboard_interface> sptr;
- typedef std::vector<uint8_t> byte_vector_t;
+ typedef std::vector<boost::uint8_t> byte_vector_t;
//tells the host which unit to use
enum unit_type_t{
@@ -96,7 +97,7 @@ public:
* \param rx_value 16-bits, 0=FPGA output low, 1=FPGA output high
* \param mask 16-bits, 0=software, 1=atr
*/
- virtual void set_atr_reg(gpio_bank_t bank, uint16_t tx_value, uint16_t rx_value, uint16_t mask) = 0;
+ virtual void set_atr_reg(gpio_bank_t bank, boost::uint16_t tx_value, boost::uint16_t rx_value, boost::uint16_t mask) = 0;
/*!
* Set daughterboard GPIO data direction register.
@@ -105,7 +106,7 @@ public:
* \param value 16-bits, 0=FPGA input, 1=FPGA output
* \param mask 16-bits, 0=ignore, 1=set
*/
- virtual void set_gpio_ddr(gpio_bank_t bank, uint16_t value, uint16_t mask) = 0;
+ virtual void set_gpio_ddr(gpio_bank_t bank, boost::uint16_t value, boost::uint16_t mask) = 0;
/*!
* Set daughterboard GPIO pin values.
@@ -114,7 +115,7 @@ public:
* \param value 16 bits, 0=low, 1=high
* \param mask 16 bits, 0=ignore, 1=set
*/
- virtual void write_gpio(gpio_bank_t bank, uint16_t value, uint16_t mask) = 0;
+ virtual void write_gpio(gpio_bank_t bank, boost::uint16_t value, boost::uint16_t mask) = 0;
/*!
* Read daughterboard GPIO pin values
@@ -122,7 +123,7 @@ public:
* \param bank GPIO_TX_BANK or GPIO_RX_BANK
* \return the value of the gpio bank
*/
- virtual uint16_t read_gpio(gpio_bank_t bank) = 0;
+ virtual boost::uint16_t read_gpio(gpio_bank_t bank) = 0;
/*!
* \brief Write to I2C peripheral
diff --git a/host/include/uhd/usrp/dboard_manager.hpp b/host/include/uhd/usrp/dboard_manager.hpp
index 042947ac4..6a105d1de 100644
--- a/host/include/uhd/usrp/dboard_manager.hpp
+++ b/host/include/uhd/usrp/dboard_manager.hpp
@@ -18,6 +18,7 @@
#ifndef INCLUDED_UHD_USRP_DBOARD_MANAGER_HPP
#define INCLUDED_UHD_USRP_DBOARD_MANAGER_HPP
+#include <uhd/config.hpp>
#include <uhd/props.hpp>
#include <uhd/usrp/dboard_base.hpp>
#include <uhd/usrp/dboard_id.hpp>
@@ -31,7 +32,7 @@ namespace uhd{ namespace usrp{
* Create subdev instances for each subdev on a dboard.
* Provide wax::obj access to the subdevs inside.
*/
-class dboard_manager : boost::noncopyable{
+class UHD_API dboard_manager : boost::noncopyable{
public:
typedef boost::shared_ptr<dboard_manager> sptr;
@@ -40,15 +41,17 @@ public:
typedef dboard_base::sptr(*dboard_ctor_t)(dboard_base::ctor_args_t const&);
/*!
- * Register subdevices for a given dboard id.
+ * Register a dboard into the system.
*
* \param dboard_id the dboard id (rx or tx)
* \param dboard_ctor the dboard constructor function pointer
+ * \param name the canonical name for the dboard represented
* \param subdev_names the names of the subdevs on this dboard
*/
- static void register_subdevs(
+ static void register_dboard(
dboard_id_t dboard_id,
dboard_ctor_t dboard_ctor,
+ const std::string &name,
const prop_names_t &subdev_names
);
diff --git a/host/include/uhd/usrp/usrp1e.hpp b/host/include/uhd/usrp/usrp1e.hpp
new file mode 100644
index 000000000..f4cc39d8e
--- /dev/null
+++ b/host/include/uhd/usrp/usrp1e.hpp
@@ -0,0 +1,55 @@
+//
+// 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_UHD_USRP_USRP1E_HPP
+#define INCLUDED_UHD_USRP_USRP1E_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/device.hpp>
+
+namespace uhd{ namespace usrp{
+
+/*!
+ * The usrp1e device class.
+ */
+class UHD_API usrp1e : public device{
+public:
+ /*!
+ * Discover usrp1e devices on the system via the device node.
+ * This static method will be called by the device::discover.
+ * \param hint a device addr with the usrp1e address filled in
+ * \return a vector of device addresses for all usrp1es found
+ */
+ static device_addrs_t discover(const device_addr_t &hint);
+
+ /*!
+ * Make a usrp1e from a device address.
+ * \param addr the device address
+ * \return a device sptr to a new usrp1e
+ */
+ static device::sptr make(const device_addr_t &addr);
+
+ /*!
+ * Load the FPGA with an image file.
+ * \param bin_file the name of the fpga image file
+ */
+ static void load_fpga(const std::string &bin_file);
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_USRP1E_HPP */
diff --git a/host/include/uhd/usrp/usrp2.hpp b/host/include/uhd/usrp/usrp2.hpp
index f6e49cbd6..277ddc131 100644
--- a/host/include/uhd/usrp/usrp2.hpp
+++ b/host/include/uhd/usrp/usrp2.hpp
@@ -15,9 +15,10 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#ifndef INCLUDED_UHD_USRP_MBOARD_USRP2_HPP
-#define INCLUDED_UHD_USRP_MBOARD_USRP2_HPP
+#ifndef INCLUDED_UHD_USRP_USRP2_HPP
+#define INCLUDED_UHD_USRP_USRP2_HPP
+#include <uhd/config.hpp>
#include <uhd/device.hpp>
namespace uhd{ namespace usrp{
@@ -25,10 +26,15 @@ namespace uhd{ namespace usrp{
/*!
* The usrp2 device class.
*/
-class usrp2 : public device{
+class UHD_API usrp2 : public device{
public:
/*!
* Discover usrp2 devices over the ethernet.
+ *
+ * Recommended key/value pairs for the device hint address:
+ * hint["addr"] = address, where address is a resolvable address
+ * or ip address, which may or may not be a broadcast address.
+ *
* This static method will be called by the device::discover.
* \param hint a device addr with the usrp2 address filled in
* \return a vector of device addresses for all usrp2s found
@@ -37,6 +43,11 @@ public:
/*!
* Make a usrp2 from a device address.
+ *
+ * Required key/value pairs for the device address:
+ * hint["addr"] = address, where address is a resolvable address
+ * or ip address, which must be the specific address of a usrp2.
+ *
* \param addr the device address
* \return a device sptr to a new usrp2
*/
@@ -45,4 +56,4 @@ public:
}} //namespace
-#endif /* INCLUDED_UHD_USRP_MBOARD_USRP2_HPP */
+#endif /* INCLUDED_UHD_USRP_USRP2_HPP */
diff --git a/host/include/uhd/utils.hpp b/host/include/uhd/utils.hpp
index 4331aba7e..e5333539f 100644
--- a/host/include/uhd/utils.hpp
+++ b/host/include/uhd/utils.hpp
@@ -15,17 +15,28 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <uhd/wax.hpp>
-#include <boost/foreach.hpp>
+#ifndef INCLUDED_UHD_UTILS_HPP
+#define INCLUDED_UHD_UTILS_HPP
+
+#include <uhd/config.hpp>
#include <boost/format.hpp>
-#include <boost/function.hpp>
+#include <boost/current_function.hpp>
#include <stdexcept>
#include <algorithm>
-#include <vector>
-#include <map>
-#ifndef INCLUDED_UHD_UTILS_HPP
-#define INCLUDED_UHD_UTILS_HPP
+/*!
+ * Defines a function that implements the "construct on first use" idiom
+ * \param _t the type definition for the instance
+ * \param _x the name of the defined function
+ * \return a reference to the lazy instance
+ */
+#define STATIC_INSTANCE(_t, _x) static _t &_x(){static _t _x; return _x;}
+
+/*!
+ * Defines a static code block that will be called before main()
+ * \param _x the name of the defined struct (must be unique in file)
+ */
+#define STATIC_BLOCK(_x) static struct _x{_x();}_x;_x::_x()
/*!
* Useful templated functions and classes that I like to pretend are part of stl
@@ -40,7 +51,9 @@ namespace std{
};
#define ASSERT_THROW(_x) if (not (_x)) { \
- throw std::assert_error("Assertion Failed: " + std::string(#_x)); \
+ throw std::assert_error(str(boost::format( \
+ "Assertion Failed:\n %s:%d\n %s\n ---> %s <---" \
+ ) % __FILE__ % __LINE__ % BOOST_CURRENT_FUNCTION % std::string(#_x))); \
}
template<class T, class InputIterator, class Function>
@@ -52,14 +65,19 @@ namespace std{
return tmp;
}
+ template<class T, class Iterable, class Function>
+ T reduce(Iterable iterable, Function fcn, T init = 0){
+ return reduce(iterable.begin(), iterable.end(), fcn, init);
+ }
+
template<class T, class InputIterator>
bool has(InputIterator first, InputIterator last, const T &elem){
return last != std::find(first, last, elem);
}
- template<class T>
- T sum(const T &a, const T &b){
- return a + b;
+ template<class T, class Iterable>
+ bool has(const Iterable &iterable, const T &elem){
+ return has(iterable.begin(), iterable.end(), elem);
}
template<typename T> T signum(T n){
@@ -70,52 +88,43 @@ namespace std{
}//namespace std
-/*namespace uhd{
-
-inline void tune(
- freq_t target_freq,
- freq_t lo_offset,
- wax::obj subdev_freq_proxy,
- bool subdev_quadrature,
- bool subdev_spectrum_inverted,
- bool subdev_is_tx,
- wax::obj dsp_freq_proxy,
- freq_t dsp_sample_rate
-){
- // Ask the d'board to tune as closely as it can to target_freq+lo_offset
- subdev_freq_proxy = target_freq + lo_offset;
- freq_t inter_freq = wax::cast<freq_t>(subdev_freq_proxy);
-
- // Calculate the DDC setting that will downconvert the baseband from the
- // daughterboard to our target frequency.
- freq_t delta_freq = target_freq - inter_freq;
- freq_t delta_sign = std::signum(delta_freq);
- delta_freq *= delta_sign;
- delta_freq = fmod(delta_freq, dsp_sample_rate);
- bool inverted = delta_freq > dsp_sample_rate/2.0;
- freq_t dxc_freq = inverted? (delta_freq - dsp_sample_rate) : (-delta_freq);
- dxc_freq *= delta_sign;
-
- // If the spectrum is inverted, and the daughterboard doesn't do
- // quadrature downconversion, we can fix the inversion by flipping the
- // sign of the dxc_freq... (This only happens using the basic_rx board)
- if (subdev_spectrum_inverted){
- inverted = not inverted;
- }
- if (inverted and not subdev_quadrature){
- dxc_freq = -dxc_freq;
- inverted = not inverted;
- }
- if (subdev_is_tx){
- dxc_freq = -dxc_freq; // down conversion versus up conversion
+#include <boost/format.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+
+namespace uhd{
+
+ /*!
+ * Check that an element is found in a container.
+ * If not, throw a meaningful assertion error.
+ * The "what" in the error will show what is
+ * being set and a list of known good values.
+ *
+ * \param iterable a list of possible settings
+ * \param elem an element that may be in the list
+ * \param what a description of what is being set
+ * \throw assertion_error when elem not in list
+ */
+ template<class T, class Iterable> void assert_has(
+ const Iterable &iterable,
+ const T &elem,
+ const std::string &what = "unknown"
+ ){
+ if (std::has(iterable, elem)) return;
+ std::string possible_values = "";
+ BOOST_FOREACH(T e, iterable){
+ if (e != iterable.begin()[0]) possible_values += ", ";
+ possible_values += boost::lexical_cast<std::string>(e);
+ }
+ throw std::assert_error(str(boost::format(
+ "Error: %s is not a valid %s. "
+ "Possible values are: [%s]."
+ )
+ % boost::lexical_cast<std::string>(elem)
+ % what % possible_values
+ ));
}
- dsp_freq_proxy = dxc_freq;
- //freq_t actual_dxc_freq = wax::cast<freq_t>(dsp_freq_proxy);
-
- //return some kind of tune result tuple/struct
-}
-
-} //namespace uhd*/
+}//namespace uhd
#endif /* INCLUDED_UHD_UTILS_HPP */
diff --git a/host/include/uhd/wax.hpp b/host/include/uhd/wax.hpp
index 1d5054351..30645f491 100644
--- a/host/include/uhd/wax.hpp
+++ b/host/include/uhd/wax.hpp
@@ -18,33 +18,37 @@
#ifndef INCLUDED_WAX_HPP
#define INCLUDED_WAX_HPP
+#include <uhd/config.hpp>
#include <boost/any.hpp>
-#include <iostream>
/*!
* WAX - it's a metaphor!
*
- * The WAX framework allows object to have generic/anyobj properties.
+ * The WAX framework allows an object to have generic/anyobj properties.
* These properties can be addressed through generic/anyobj identifiers.
- * A property of a WAX object may even be another WAX object.
*
- * When a property is a WAX object, the returned value must be an obj pointer.
- * A WAX object provides two objs of pointers: obj::ptr and obj::sptr.
- * The choice of pointer vs smart pointer depends on the owner of the memory.
+ * The WAX object itself is an anytype container much like boost::any.
+ * To retrieve the value of the appropriate type, use my_obj.as<type>().
*
* Proprties may be referenced though the [] overloaded operator.
* The [] operator returns a special proxy that allows for assigment.
* Also, the [] operators may be chained as in the folowing examples:
- * my_obj[prop1][prop2][prop3] = value
- * value = my_obj[prop1][prop2][prop3]
+ * my_obj[prop1][prop2][prop3] = value;
+ * value = my_obj[prop1][prop2][prop3].as<type>();
*
- * Any value returned from an access operation is of wax::obj.
- * To use this value, it must be cast with wax::cast<new_obj>(value).
+ * Property nesting occurs when a WAX object gets another object's link.
+ * This special link is obtained through a call to my_obj.get_link().
*/
namespace wax{
/*!
+ * The wax::bad cast will be thrown when
+ * cast is called with the wrong typeid.
+ */
+ typedef boost::bad_any_cast bad_cast;
+
+ /*!
* WAX object base class:
*
* A wax obj has two major purposes:
@@ -56,7 +60,7 @@ namespace wax{
* For property nesting, wax obj subclasses return special links
* to other wax obj subclasses, and the api handles the magic.
*/
- class obj{
+ class UHD_API obj{
public:
/*!
@@ -124,6 +128,17 @@ namespace wax{
*/
const std::type_info & type(void) const;
+ /*!
+ * Cast this obj into the desired type.
+ * Usage: myobj.as<type>()
+ *
+ * \return an object of the desired type
+ * \throw wax::bad_cast when the cast fails
+ */
+ template<class T> T as(void) const{
+ return boost::any_cast<T>(resolve());
+ }
+
private:
//private interface (override in subclasses)
virtual void get(const obj &, obj &);
@@ -137,31 +152,12 @@ namespace wax{
* \return a boost any type with contents
*/
boost::any resolve(void) const;
- template<class T> friend T cast(const obj &);
//private contents of this obj
boost::any _contents;
};
- /*!
- * The wax::bad cast will be thrown when
- * cast is called with the wrong typeid.
- */
- typedef boost::bad_any_cast bad_cast;
-
- /*!
- * Cast a wax::obj into the desired obj.
- * Usage wax::cast<new_obj>(my_value).
- *
- * \param val the obj to cast
- * \return an object of the desired type
- * \throw wax::bad_cast when the cast fails
- */
- template<class T> T cast(const obj &val){
- return boost::any_cast<T>(val.resolve());
- }
-
} //namespace wax
#endif /* INCLUDED_WAX_HPP */
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index 5cf334678..46cce729e 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -15,29 +15,100 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-
+########################################################################
+# Create a list of libuhd sources
+########################################################################
SET(libuhd_sources
device.cpp
device_addr.cpp
gain_handler.cpp
- shared_iovec.cpp
- uhd.cpp
+ load_modules.cpp
+ metadata.cpp
+ simple_device.cpp
+ time_spec.cpp
+ types.cpp
wax.cpp
- transport/udp.cpp
+ transport/udp_simple.cpp
+ transport/vrt.cpp
usrp/dboard/basic.cpp
usrp/dboard_base.cpp
- usrp/dboard_id.cpp
usrp/dboard_interface.cpp
usrp/dboard_manager.cpp
usrp/usrp2/dboard_impl.cpp
usrp/usrp2/dboard_interface.cpp
usrp/usrp2/dsp_impl.cpp
+ usrp/usrp2/io_impl.cpp
usrp/usrp2/mboard_impl.cpp
usrp/usrp2/usrp2_impl.cpp
)
+########################################################################
+# Conditionally add the udp sources
+########################################################################
+LIST(APPEND libuhd_sources
+ transport/udp_zero_copy_asio.cpp
+)
+
+########################################################################
+# Conditionally add the usrp1e sources
+########################################################################
+INCLUDE(CheckIncludeFiles)
+SET(usrp1e_required_headers
+ linux/ioctl.h
+ linux/spi/spidev.h
+ linux/usrp1_e.h
+)
+CHECK_INCLUDE_FILES(
+ "${usrp1e_required_headers}"
+ HAS_USRP1E_REQUIRED_HEADERS
+)
+
+IF(HAS_USRP1E_REQUIRED_HEADERS)
+ MESSAGE(STATUS "Building usrp1e support...")
+ LIST(APPEND libuhd_sources
+ usrp/usrp1e/dboard_impl.cpp
+ usrp/usrp1e/dboard_interface.cpp
+ usrp/usrp1e/dsp_impl.cpp
+ usrp/usrp1e/fpga-downloader.cc
+ usrp/usrp1e/mboard_impl.cpp
+ usrp/usrp1e/usrp1e_impl.cpp
+ )
+ELSE(HAS_USRP1E_REQUIRED_HEADERS)
+ MESSAGE(STATUS "Skipping usrp1e support...")
+ LIST(APPEND libuhd_sources
+ usrp/usrp1e/usrp1e_none.cpp
+ )
+ENDIF(HAS_USRP1E_REQUIRED_HEADERS)
+
+########################################################################
+# Setup defines for module loading
+########################################################################
+INCLUDE(CheckIncludeFileCXX)
+
+CHECK_INCLUDE_FILE_CXX(dlfcn.h HAVE_DLFCN_H)
+CHECK_INCLUDE_FILE_CXX(Winbase.h HAVE_WINBASE_H)
+
+IF(HAVE_DLFCN_H)
+ MESSAGE(STATUS "Module loading supported through dlopen...")
+ ADD_DEFINITIONS(-DHAVE_DLFCN_H)
+ELSEIF(HAVE_WINBASE_H)
+ MESSAGE(STATUS "Module loading supported through LoadLibrary...")
+ ADD_DEFINITIONS(-DHAVE_WINBASE_H)
+ELSE(HAVE_DLFCN_H)
+ MESSAGE(STATUS "Module loading not supported...")
+ENDIF(HAVE_DLFCN_H)
+
+########################################################################
+# Setup libuhd library
+########################################################################
ADD_LIBRARY(uhd SHARED ${libuhd_sources})
-TARGET_LINK_LIBRARIES(uhd ${Boost_LIBRARIES})
+TARGET_LINK_LIBRARIES(uhd ${Boost_LIBRARIES} ${CMAKE_DL_LIBS})
+
+SET_TARGET_PROPERTIES(uhd PROPERTIES DEFINE_SYMBOL "UHD_DLL_EXPORTS")
-INSTALL(TARGETS uhd LIBRARY DESTINATION ${LIBRARY_DIR})
+INSTALL(TARGETS uhd
+ LIBRARY DESTINATION ${LIBRARY_DIR} # .so file
+ ARCHIVE DESTINATION ${LIBRARY_DIR} # .lib file
+ RUNTIME DESTINATION ${LIBRARY_DIR} # .dll file
+)
diff --git a/host/lib/device.cpp b/host/lib/device.cpp
index e376a5c50..cd8a01ab4 100644
--- a/host/lib/device.cpp
+++ b/host/lib/device.cpp
@@ -12,57 +12,133 @@
// 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/>.
+// asize_t with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <uhd/usrp/usrp2.hpp>
#include <uhd/device.hpp>
+#include <uhd/dict.hpp>
+#include <uhd/utils.hpp>
+#include <boost/foreach.hpp>
#include <boost/format.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/functional/hash.hpp>
+#include <boost/tuple/tuple.hpp>
#include <stdexcept>
+#include <algorithm>
using namespace uhd;
+/***********************************************************************
+ * Helper Functions
+ **********************************************************************/
+/*!
+ * Make a device hash that maps 1 to 1 with a device address.
+ * The hash will be used to identify created devices.
+ * \param dev_addr the device address
+ * \return the hash number
+ */
+static size_t hash_device_addr(
+ const device_addr_t &dev_addr
+){
+ //sort the keys of the device address
+ std::vector<std::string> keys = dev_addr.get_keys();
+ std::sort(keys.begin(), keys.end());
+
+ //combine the hashes of sorted keys/value pairs
+ size_t hash = 0;
+ BOOST_FOREACH(std::string key, keys){
+ boost::hash_combine(hash, key);
+ boost::hash_combine(hash, dev_addr[key]);
+ }
+ return hash;
+}
+
+/***********************************************************************
+ * Registration
+ **********************************************************************/
+typedef boost::tuple<device::discover_t, device::make_t> dev_fcn_reg_t;
+
+// instantiate the device function registry container
+STATIC_INSTANCE(std::vector<dev_fcn_reg_t>, get_dev_fcn_regs)
+
+void device::register_device(
+ const discover_t &discover,
+ const make_t &make
+){
+ //std::cout << "registering device" << std::endl;
+ get_dev_fcn_regs().push_back(dev_fcn_reg_t(discover, make));
+}
+
+/***********************************************************************
+ * Discover
+ **********************************************************************/
device_addrs_t device::discover(const device_addr_t &hint){
device_addrs_t device_addrs;
- if (not hint.has_key("type")){
- //TODO call discover for others and append results
- }
- else if (hint["type"] == "udp"){
- std::vector<device_addr_t> usrp2_addrs = usrp::usrp2::discover(hint);
- device_addrs.insert(device_addrs.begin(), usrp2_addrs.begin(), usrp2_addrs.end());
+
+ BOOST_FOREACH(dev_fcn_reg_t fcn, get_dev_fcn_regs()){
+ device_addrs_t discovered_addrs = fcn.get<0>()(hint);
+ device_addrs.insert(
+ device_addrs.begin(),
+ discovered_addrs.begin(),
+ discovered_addrs.end()
+ );
}
+
return device_addrs;
}
+/***********************************************************************
+ * Make
+ **********************************************************************/
device::sptr device::make(const device_addr_t &hint, size_t which){
- std::vector<device_addr_t> device_addrs = discover(hint);
+ typedef boost::tuple<device_addr_t, make_t> dev_addr_make_t;
+ std::vector<dev_addr_make_t> dev_addr_makers;
+
+ BOOST_FOREACH(dev_fcn_reg_t fcn, get_dev_fcn_regs()){
+ BOOST_FOREACH(device_addr_t dev_addr, fcn.get<0>()(hint)){
+ //copy keys that were in hint but not in dev_addr
+ //this way, we can pass additional transport arguments
+ BOOST_FOREACH(std::string key, hint.get_keys()){
+ if (not dev_addr.has_key(key)) dev_addr[key] = hint[key];
+ }
+ //append the discovered address and its factory function
+ dev_addr_makers.push_back(dev_addr_make_t(dev_addr, fcn.get<1>()));
+ }
+ }
//check that we found any devices
- if (device_addrs.size() == 0){
+ if (dev_addr_makers.size() == 0){
throw std::runtime_error(str(
- boost::format("No devices found for %s") % device_addr_to_string(hint)
+ boost::format("No devices found for ----->\n%s") % device_addr::to_string(hint)
));
}
//check that the which index is valid
- if (device_addrs.size() <= which){
+ if (dev_addr_makers.size() <= which){
throw std::runtime_error(str(
- boost::format("No device at index %d for %s") % which % device_addr_to_string(hint)
+ boost::format("No device at index %d for ----->\n%s") % which % device_addr::to_string(hint)
));
}
- //create the new device with the discovered address
- //TODO only a usrp2 device will be made (until others are supported)
- if (hint.has_key("type") and hint["type"] == "udp"){
- return usrp::usrp2::make(device_addrs.at(which));
- }
- throw std::runtime_error("cant make a device");
-}
+ //create a unique hash for the device address
+ device_addr_t dev_addr; make_t maker;
+ boost::tie(dev_addr, maker) = dev_addr_makers.at(which);
+ size_t dev_hash = hash_device_addr(dev_addr);
+ //std::cout << boost::format("Hash: %u") % dev_hash << std::endl;
-device::device(void){
- /* NOP */
-}
+ //map device address hash to created devices
+ static uhd::dict<size_t, boost::weak_ptr<device> > hash_to_device;
-device::~device(void){
- /* NOP */
+ //try to find an existing device
+ try{
+ ASSERT_THROW(hash_to_device.has_key(dev_hash));
+ ASSERT_THROW(not hash_to_device[dev_hash].expired());
+ return hash_to_device[dev_hash].lock();
+ }
+ //create and register a new device
+ catch(const std::assert_error &){
+ device::sptr dev = maker(dev_addr);
+ hash_to_device[dev_hash] = dev;
+ return dev;
+ }
}
diff --git a/host/lib/device_addr.cpp b/host/lib/device_addr.cpp
index ffd511f92..d26bb4b9d 100644
--- a/host/lib/device_addr.cpp
+++ b/host/lib/device_addr.cpp
@@ -28,7 +28,7 @@ uhd::mac_addr_t::mac_addr_t(const std::string &mac_addr_str_){
std::string mac_addr_str = (mac_addr_str_ == "")? "ff:ff:ff:ff:ff:ff" : mac_addr_str_;
//ether_aton_r(str.c_str(), &mac_addr);
- uint8_t p[6] = {0x00, 0x50, 0xC2, 0x85, 0x30, 0x00}; // Matt's IAB
+ boost::uint8_t p[6] = {0x00, 0x50, 0xC2, 0x85, 0x30, 0x00}; // Matt's IAB
try{
//only allow patterns of xx:xx or xx:xx:xx:xx:xx:xx
@@ -43,7 +43,7 @@ uhd::mac_addr_t::mac_addr_t(const std::string &mac_addr_str_){
int hex_num;
std::istringstream iss(hex_strs[i]);
iss >> std::hex >> hex_num;
- p[i] = uint8_t(hex_num);
+ p[i] = boost::uint8_t(hex_num);
}
}
@@ -58,7 +58,7 @@ uhd::mac_addr_t::mac_addr_t(const std::string &mac_addr_str_){
std::string uhd::mac_addr_t::to_string(void) const{
//ether_ntoa_r(&mac_addr, addr_buf);
- const uint8_t *p = reinterpret_cast<const uint8_t *>(&mac_addr);
+ const boost::uint8_t *p = reinterpret_cast<const boost::uint8_t *>(&mac_addr);
return str(
boost::format("%02x:%02x:%02x:%02x:%02x:%02x")
% int(p[0]) % int(p[1]) % int(p[2])
@@ -72,7 +72,7 @@ std::ostream& operator<<(std::ostream &os, const uhd::mac_addr_t &x){
}
//----------------------- usrp device_addr_t wrapper -------------------------//
-std::string uhd::device_addr_to_string(const uhd::device_addr_t &device_addr){
+std::string uhd::device_addr::to_string(const uhd::device_addr_t &device_addr){
std::stringstream ss;
BOOST_FOREACH(std::string key, device_addr.get_keys()){
ss << boost::format("%s: %s") % key % device_addr[key] << std::endl;
@@ -81,6 +81,6 @@ std::string uhd::device_addr_to_string(const uhd::device_addr_t &device_addr){
}
std::ostream& operator<<(std::ostream &os, const uhd::device_addr_t &device_addr){
- os << uhd::device_addr_to_string(device_addr);
+ os << uhd::device_addr::to_string(device_addr);
return os;
}
diff --git a/host/lib/gain_handler.cpp b/host/lib/gain_handler.cpp
index b03d5bda2..7dd1547cb 100644
--- a/host/lib/gain_handler.cpp
+++ b/host/lib/gain_handler.cpp
@@ -17,151 +17,161 @@
#include <uhd/gain_handler.hpp>
#include <uhd/utils.hpp>
+#include <uhd/types.hpp>
+#include <uhd/props.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
+#include <cmath>
#include <vector>
using namespace uhd;
/***********************************************************************
- * Helper functions and macros
+ * gain handler implementation interface
**********************************************************************/
-#define GET_PROP_NAMES() \
- wax::cast<prop_names_t>((*_wax_obj_ptr)[_gain_names_prop])
-
-/*!
- * Helper function to simplify getting a named gain (also min, max, step).
- */
-static gain_t get_named_gain(wax::obj *wax_obj_ptr, wax::obj prop, std::string name){
- return wax::cast<gain_t>((*wax_obj_ptr)[named_prop_t(prop, name)]);
+class gain_handler_impl : public gain_handler{
+public:
+ gain_handler_impl(
+ const wax::obj &link,
+ const props_t &props,
+ is_equal_t is_equal
+ );
+ ~gain_handler_impl(void);
+ bool intercept_get(const wax::obj &key, wax::obj &val);
+ bool intercept_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ wax::obj _link;
+ props_t _props;
+ is_equal_t _is_equal;
+
+ prop_names_t get_gain_names(void);
+ gain_t get_overall_gain_val(void);
+ gain_range_t get_overall_gain_range(void);
+ template <class T> T get_named_prop(const wax::obj &prop, const std::string &name){
+ return _link[named_prop_t(prop, name)].as<T>();
+ }
+};
+
+/***********************************************************************
+ * the make function
+ **********************************************************************/
+gain_handler::sptr gain_handler::make(
+ const wax::obj &link,
+ const props_t &props,
+ is_equal_t is_equal
+){
+ return sptr(new gain_handler_impl(link, props, is_equal));
}
/***********************************************************************
- * Class methods of gain handler
+ * gain handler implementation methods
**********************************************************************/
-gain_handler::~gain_handler(void){
+gain_handler::props_t::props_t(void){
/* NOP */
}
-void gain_handler::_check_key(const wax::obj &key_){
- wax::obj key; std::string name;
- boost::tie(key, name) = extract_named_prop(key_);
-
- try{
- //only handle non wildcard names
- ASSERT_THROW(name != "");
-
- //only handle these gain props
- ASSERT_THROW(
- _is_equal(key, _gain_prop) or
- _is_equal(key, _gain_min_prop) or
- _is_equal(key, _gain_max_prop) or
- _is_equal(key, _gain_step_prop)
- );
-
- //check that the name is allowed
- prop_names_t prop_names = GET_PROP_NAMES();
- ASSERT_THROW(not std::has(prop_names.begin(), prop_names.end(), name));
-
- //if we get here, throw an exception
- throw std::invalid_argument(str(
- boost::format("Unknown gain name %s") % name
- ));
- }
- catch(const std::assert_error &){}
+gain_handler_impl::gain_handler_impl(
+ const wax::obj &link,
+ const props_t &props,
+ is_equal_t is_equal
+){
+ _link = link;
+ _props = props;
+ _is_equal = is_equal;
}
-static gain_t gain_max(gain_t a, gain_t b){
- return std::max(a, b);
+gain_handler_impl::~gain_handler_impl(void){
+ /* NOP */
}
-static gain_t gain_sum(gain_t a, gain_t b){
- return std::sum(a, b);
+
+prop_names_t gain_handler_impl::get_gain_names(void){
+ return _link[_props.names].as<prop_names_t>();
}
-bool gain_handler::intercept_get(const wax::obj &key, wax::obj &val){
- _check_key(key); //verify the key
-
- std::vector<wax::obj> gain_props = boost::assign::list_of
- (_gain_prop)(_gain_min_prop)(_gain_max_prop)(_gain_step_prop);
-
- /*!
- * Handle getting overall gains when a name is not specified.
- * For the gain props below, set the overall value and return true.
- */
- BOOST_FOREACH(wax::obj prop_key, gain_props){
- if (_is_equal(key, prop_key)){
- //form the gains vector from the props vector
- prop_names_t prop_names = GET_PROP_NAMES();
- std::vector<gain_t> gains(prop_names.size());
- std::transform(
- prop_names.begin(), prop_names.end(), gains.begin(),
- boost::bind(get_named_gain, _wax_obj_ptr, key, _1)
- );
-
- //reduce across the gain vector
- if (_is_equal(key, _gain_step_prop)){
- val = std::reduce<gain_t>(gains.begin(), gains.end(), gain_max);
- }
- else{
- val = std::reduce<gain_t>(gains.begin(), gains.end(), gain_sum);
- }
- return true;
- }
+gain_t gain_handler_impl::get_overall_gain_val(void){
+ gain_t gain_val = 0;
+ BOOST_FOREACH(std::string name, get_gain_names()){
+ gain_val += get_named_prop<gain_t>(_props.value, name);
}
+ return gain_val;
+}
- return false;
+gain_range_t gain_handler_impl::get_overall_gain_range(void){
+ gain_t gain_min = 0, gain_max = 0, gain_step = 0;
+ BOOST_FOREACH(std::string name, get_gain_names()){
+ gain_range_t gain_tmp = get_named_prop<gain_range_t>(_props.range, name);
+ gain_min += gain_tmp.min;
+ gain_max += gain_tmp.max;
+ gain_step = std::max(gain_step, gain_tmp.step);
+ }
+ return gain_range_t(gain_min, gain_max, gain_step);
}
-bool gain_handler::intercept_set(const wax::obj &key_, const wax::obj &val){
- _check_key(key_); //verify the key
+/***********************************************************************
+ * gain handler implementation get method
+ **********************************************************************/
+bool gain_handler_impl::intercept_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //not a wildcard... dont handle (but check name)
+ if (name != ""){
+ assert_has(get_gain_names(), name, "gain name");
+ return false;
+ }
+
+ if (_is_equal(key, _props.value)){
+ val = get_overall_gain_val();
+ return true;
+ }
+
+ if (_is_equal(key, _props.range)){
+ val = get_overall_gain_range();
+ return true;
+ }
+
+ return false; //not handled
+}
+/***********************************************************************
+ * gain handler implementation set method
+ **********************************************************************/
+bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val){
wax::obj key; std::string name;
boost::tie(key, name) = extract_named_prop(key_);
- /*!
- * Verify that a named gain component is in range.
- */
- try{
- //only handle the gain props
- ASSERT_THROW(_is_equal(key, _gain_prop));
-
- //check that the gain is in range
- gain_t gain = wax::cast<gain_t>(val);
- gain_t gain_min = get_named_gain(_wax_obj_ptr, _gain_min_prop, name);
- gain_t gain_max = get_named_gain(_wax_obj_ptr, _gain_max_prop, name);
- ASSERT_THROW(gain > gain_max or gain < gain_min);
-
- //if we get here, throw an exception
- throw std::range_error(str(
- boost::format("gain %s is out of range of (%f, %f)") % name % gain_min % gain_max
+ //not a gain value key... dont handle
+ if (not _is_equal(key, _props.value)) return false;
+
+ gain_t gain_val = val.as<gain_t>();
+
+ //not a wildcard... dont handle (but check name and range)
+ if (name != ""){
+ assert_has(get_gain_names(), name, "gain name");
+ gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name);
+ if (gain_val > gain.max or gain_val < gain.min) throw std::range_error(str(
+ boost::format("A value of %f for gain %s is out of range of (%f, %f)")
+ % gain_val % name % gain.min % gain.max
));
+ return false;
}
- catch(const std::assert_error &){}
-
- /*!
- * Handle setting the overall gain.
- */
- if (_is_equal(key, _gain_prop) and name == ""){
- gain_t gain = wax::cast<gain_t>(val);
- prop_names_t prop_names = GET_PROP_NAMES();
- BOOST_FOREACH(std::string name, prop_names){
- //get the min, max, step for this gain name
- gain_t gain_min = get_named_gain(_wax_obj_ptr, _gain_min_prop, name);
- gain_t gain_max = get_named_gain(_wax_obj_ptr, _gain_max_prop, name);
- gain_t gain_step = get_named_gain(_wax_obj_ptr, _gain_step_prop, name);
-
- //clip g to be within the allowed range
- gain_t g = std::min(std::max(gain, gain_min), gain_max);
- //set g to be a multiple of the step size
- g -= fmod(g, gain_step);
- //set g to be the new gain
- (*_wax_obj_ptr)[named_prop_t(_gain_prop, name)] = g;
- //subtract g out of the total gain left to apply
- gain -= g;
- }
- return true;
+
+ //set the overall gain
+ BOOST_FOREACH(std::string name, get_gain_names()){
+ //get the min, max, step for this gain name
+ gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name);
+
+ //clip g to be within the allowed range
+ gain_t g = std::min(std::max(gain_val, gain.min), gain.max);
+ //set g to be a multiple of the step size
+ g -= std::fmod(g, gain.step);
+ //set g to be the new gain
+ _link[named_prop_t(_props.value, name)] = g;
+ //subtract g out of the total gain left to apply
+ gain_val -= g;
}
- return false;
+ return true;
}
diff --git a/host/lib/load_modules.cpp b/host/lib/load_modules.cpp
new file mode 100644
index 000000000..700afcd3f
--- /dev/null
+++ b/host/lib/load_modules.cpp
@@ -0,0 +1,117 @@
+//
+// 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.hpp>
+#include <boost/format.hpp>
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/filesystem.hpp>
+#include <iostream>
+#include <stdexcept>
+#include <cstdlib>
+
+namespace fs = boost::filesystem;
+
+/***********************************************************************
+ * Module Load Function
+ **********************************************************************/
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+
+static void load_module(const std::string &file_name){
+ if (dlopen(file_name.c_str(), RTLD_LAZY) == NULL){
+ throw std::runtime_error(str(
+ boost::format("dlopen failed to load \"%s\"") % file_name
+ ));
+ }
+}
+
+#elif HAVE_WINBASE_H
+#include <Winbase.h>
+
+static void load_module(const std::string &file_name){
+ if (LoadLibrary(file_name.c_str()) == NULL){
+ throw std::runtime_error(str(
+ boost::format("LoadLibrary failed to load \"%s\"") % file_name
+ ));
+ }
+}
+
+#else
+
+static void load_module(const std::string &file_name){
+ throw std::runtime_error(str(
+ boost::format("Module loading not supported: Cannot load \"%s\"") % file_name
+ ));
+}
+
+#endif
+
+/***********************************************************************
+ * Load Modules
+ **********************************************************************/
+/*!
+ * Load all modules in a given path.
+ * This will recurse into sub-directories.
+ * Does not throw, prints to std error.
+ * \param path the filesystem path
+ */
+static void load_path(const fs::path &path){
+ if (not fs::exists(path)){
+ std::cerr << boost::format("Module path \"%s\" not found.") % path.file_string() << std::endl;
+ return;
+ }
+
+ //try to load the files in this path
+ if (fs::is_directory(path)){
+ for(
+ fs::directory_iterator dir_itr(path);
+ dir_itr != fs::directory_iterator();
+ ++dir_itr
+ ){
+ load_path(dir_itr->path());
+ }
+ return;
+ }
+
+ //its not a directory, try to load it
+ try{
+ load_module(path.file_string());
+ }
+ catch(const std::exception &err){
+ std::cerr << boost::format("Error: %s") % err.what() << std::endl;
+ }
+}
+
+/*!
+ * Load all the modules given by the module path enviroment variable.
+ * The path variable may be several paths split by path separators.
+ */
+STATIC_BLOCK(load_modules){
+ //get the environment variable module path
+ char *env_module_path = std::getenv("UHD_MODULE_PATH");
+ if (env_module_path == NULL) return;
+
+ //split the path at the path separators
+ std::vector<std::string> module_paths;
+ boost::split(module_paths, env_module_path, boost::is_any_of(":;"));
+
+ //load modules in each path
+ BOOST_FOREACH(const std::string &module_path, module_paths){
+ load_path(fs::system_complete(fs::path(module_path)));
+ }
+}
diff --git a/host/include/uhd.hpp b/host/lib/metadata.cpp
index ee8c13dfe..40fdb7c73 100644
--- a/host/include/uhd.hpp
+++ b/host/lib/metadata.cpp
@@ -15,10 +15,23 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#ifndef INCLUDED_UHD_HPP
-#define INCLUDED_UHD_HPP
+#include <uhd/metadata.hpp>
-//include convenience headers
-#include <uhd/device.hpp>
+using namespace uhd;
-#endif /* INCLUDED_UHD_HPP */
+rx_metadata_t::rx_metadata_t(void){
+ stream_id = 0;
+ has_stream_id = false;
+ time_spec = time_spec_t();
+ has_time_spec = false;
+ is_fragment = false;
+}
+
+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;
+}
diff --git a/host/lib/simple_device.cpp b/host/lib/simple_device.cpp
new file mode 100644
index 000000000..ba1966e0d
--- /dev/null
+++ b/host/lib/simple_device.cpp
@@ -0,0 +1,293 @@
+//
+// 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/simple_device.hpp>
+#include <uhd/device.hpp>
+#include <uhd/utils.hpp>
+#include <uhd/props.hpp>
+#include <uhd/types.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <stdexcept>
+
+using namespace uhd;
+
+/***********************************************************************
+ * Tune Helper Function
+ **********************************************************************/
+static tune_result_t tune(
+ double target_freq,
+ double lo_offset,
+ wax::obj subdev,
+ wax::obj dxc,
+ bool is_tx
+){
+ wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ];
+ bool subdev_quadrature = subdev[SUBDEV_PROP_QUADRATURE].as<bool>();
+ bool subdev_spectrum_inverted = subdev[SUBDEV_PROP_SPECTRUM_INVERTED].as<bool>();
+ wax::obj dxc_freq_proxy = dxc[std::string("freq")];
+ double dxc_sample_rate = dxc[std::string("rate")].as<double>();
+
+ // Ask the d'board to tune as closely as it can to target_freq+lo_offset
+ double target_inter_freq = target_freq + lo_offset;
+ subdev_freq_proxy = target_inter_freq;
+ double actual_inter_freq = subdev_freq_proxy.as<double>();
+
+ // Calculate the DDC setting that will downconvert the baseband from the
+ // daughterboard to our target frequency.
+ double delta_freq = target_freq - actual_inter_freq;
+ double delta_sign = std::signum(delta_freq);
+ delta_freq *= delta_sign;
+ delta_freq = fmod(delta_freq, dxc_sample_rate);
+ bool inverted = delta_freq > dxc_sample_rate/2.0;
+ double target_dxc_freq = inverted? (delta_freq - dxc_sample_rate) : (-delta_freq);
+ target_dxc_freq *= delta_sign;
+
+ // If the spectrum is inverted, and the daughterboard doesn't do
+ // quadrature downconversion, we can fix the inversion by flipping the
+ // sign of the dxc_freq... (This only happens using the basic_rx board)
+ if (subdev_spectrum_inverted){
+ inverted = not inverted;
+ }
+ if (inverted and not subdev_quadrature){
+ target_dxc_freq *= -1.0;
+ inverted = not inverted;
+ }
+ // down conversion versus up conversion, fight!
+ // your mother is ugly and your going down...
+ target_dxc_freq *= (is_tx)? -1.0 : +1.0;
+
+ dxc_freq_proxy = target_dxc_freq;
+ double actual_dxc_freq = dxc_freq_proxy.as<double>();
+
+ //return some kind of tune result tuple/struct
+ tune_result_t tune_result;
+ tune_result.target_inter_freq = target_inter_freq;
+ tune_result.actual_inter_freq = actual_inter_freq;
+ tune_result.target_dxc_freq = target_dxc_freq;
+ tune_result.actual_dxc_freq = actual_dxc_freq;
+ tune_result.spectrum_inverted = inverted;
+ return tune_result;
+}
+
+/***********************************************************************
+ * Helper Functions
+ **********************************************************************/
+static std::string trim(const std::string &in){
+ return boost::algorithm::trim_copy(in);
+}
+
+device_addr_t args_to_device_addr(const std::string &args){
+ device_addr_t addr;
+
+ //split the args at the semi-colons
+ std::vector<std::string> pairs;
+ boost::split(pairs, args, boost::is_any_of(";"));
+ BOOST_FOREACH(std::string pair, pairs){
+ if (trim(pair) == "") continue;
+
+ //split the key value pairs at the equals
+ std::vector<std::string> key_val;
+ boost::split(key_val, pair, boost::is_any_of("="));
+ if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args);
+ addr[trim(key_val[0])] = trim(key_val[1]);
+ }
+
+ return addr;
+}
+
+static std::vector<double> get_xx_rates(wax::obj decerps, wax::obj rate){
+ std::vector<double> rates;
+ BOOST_FOREACH(size_t decerp, decerps.as<std::vector<size_t> >()){
+ rates.push_back(rate.as<double>()/decerp);
+ }
+ return rates;
+}
+
+/***********************************************************************
+ * Simple Device Implementation
+ **********************************************************************/
+class simple_device_impl : public simple_device{
+public:
+ simple_device_impl(const device_addr_t &addr){
+ _dev = device::make(addr);
+ _mboard = (*_dev)[DEVICE_PROP_MBOARD];
+ _rx_ddc = _mboard[named_prop_t(MBOARD_PROP_RX_DSP, "ddc0")];
+ _tx_duc = _mboard[named_prop_t(MBOARD_PROP_TX_DSP, "duc0")];
+
+ //extract rx subdevice
+ wax::obj rx_dboard = _mboard[MBOARD_PROP_RX_DBOARD];
+ std::string rx_subdev_in_use = rx_dboard[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0);
+ _rx_subdev = rx_dboard[named_prop_t(DBOARD_PROP_SUBDEV, rx_subdev_in_use)];
+
+ //extract tx subdevice
+ wax::obj tx_dboard = _mboard[MBOARD_PROP_TX_DBOARD];
+ std::string tx_subdev_in_use = tx_dboard[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0);
+ _tx_subdev = tx_dboard[named_prop_t(DBOARD_PROP_SUBDEV, tx_subdev_in_use)];
+ }
+
+ ~simple_device_impl(void){
+ /* NOP */
+ }
+
+ device::sptr get_device(void){
+ return _dev;
+ }
+
+ std::string get_name(void){
+ return _mboard[MBOARD_PROP_NAME].as<std::string>();
+ }
+
+ /*******************************************************************
+ * Streaming
+ ******************************************************************/
+ void set_streaming(bool enb){
+ _rx_ddc[std::string("enabled")] = enb;
+ }
+
+ bool get_streaming(void){
+ return _rx_ddc[std::string("enabled")].as<bool>();
+ }
+
+ /*******************************************************************
+ * RX methods
+ ******************************************************************/
+ void set_rx_rate(double rate){
+ double samp_rate = _rx_ddc[std::string("rate")].as<double>();
+ assert_has(get_rx_rates(), rate, "simple device rx rate");
+ _rx_ddc[std::string("decim")] = size_t(samp_rate/rate);
+ }
+
+ double get_rx_rate(void){
+ double samp_rate = _rx_ddc[std::string("rate")].as<double>();
+ size_t decim = _rx_ddc[std::string("decim")].as<size_t>();
+ return samp_rate/decim;
+ }
+
+ std::vector<double> get_rx_rates(void){
+ return get_xx_rates(_rx_ddc[std::string("decims")], _rx_ddc[std::string("rate")]);
+ }
+
+ tune_result_t set_rx_freq(double target_freq){
+ double lo_offset = 0.0;
+ //if the local oscillator will be in the passband, use an offset
+ if (_rx_subdev[SUBDEV_PROP_LO_INTERFERES].as<bool>()){
+ lo_offset = get_rx_rate()*2.0;
+ }
+ return tune(target_freq, lo_offset, _rx_subdev, _rx_ddc, false/* not tx */);
+ }
+
+ freq_range_t get_rx_freq_range(void){
+ return _rx_subdev[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>();
+ }
+
+ void set_rx_gain(float gain){
+ _rx_subdev[SUBDEV_PROP_GAIN] = gain;
+ }
+
+ float get_rx_gain(void){
+ return _rx_subdev[SUBDEV_PROP_GAIN].as<gain_t>();
+ }
+
+ gain_range_t get_rx_gain_range(void){
+ return _rx_subdev[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>();
+ }
+
+ void set_rx_antenna(const std::string &ant){
+ _rx_subdev[SUBDEV_PROP_ANTENNA] = ant;
+ }
+
+ std::string get_rx_antenna(void){
+ return _rx_subdev[SUBDEV_PROP_ANTENNA].as<std::string>();
+ }
+
+ std::vector<std::string> get_rx_antennas(void){
+ return _rx_subdev[SUBDEV_PROP_ANTENNA_NAMES].as<std::vector<std::string> >();
+ }
+
+ /*******************************************************************
+ * TX methods
+ ******************************************************************/
+ void set_tx_rate(double rate){
+ double samp_rate = _tx_duc[std::string("rate")].as<double>();
+ assert_has(get_tx_rates(), rate, "simple device tx rate");
+ _tx_duc[std::string("interp")] = size_t(samp_rate/rate);
+ }
+
+ double get_tx_rate(void){
+ double samp_rate = _tx_duc[std::string("rate")].as<double>();
+ size_t interp = _tx_duc[std::string("interp")].as<size_t>();
+ return samp_rate/interp;
+ }
+
+ std::vector<double> get_tx_rates(void){
+ return get_xx_rates(_tx_duc[std::string("interps")], _tx_duc[std::string("rate")]);
+ }
+
+ tune_result_t set_tx_freq(double target_freq){
+ double lo_offset = 0.0;
+ //if the local oscillator will be in the passband, use an offset
+ if (_tx_subdev[SUBDEV_PROP_LO_INTERFERES].as<bool>()){
+ lo_offset = get_tx_rate()*2.0;
+ }
+ return tune(target_freq, lo_offset, _tx_subdev, _tx_duc, true/* is tx */);
+ }
+
+ freq_range_t get_tx_freq_range(void){
+ return _tx_subdev[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>();
+ }
+
+ void set_tx_gain(float gain){
+ _tx_subdev[SUBDEV_PROP_GAIN] = gain;
+ }
+
+ float get_tx_gain(void){
+ return _tx_subdev[SUBDEV_PROP_GAIN].as<gain_t>();
+ }
+
+ gain_range_t get_tx_gain_range(void){
+ return _tx_subdev[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>();
+ }
+
+ void set_tx_antenna(const std::string &ant){
+ _tx_subdev[SUBDEV_PROP_ANTENNA] = ant;
+ }
+
+ std::string get_tx_antenna(void){
+ return _tx_subdev[SUBDEV_PROP_ANTENNA].as<std::string>();
+ }
+
+ std::vector<std::string> get_tx_antennas(void){
+ return _tx_subdev[SUBDEV_PROP_ANTENNA_NAMES].as<std::vector<std::string> >();
+ }
+
+private:
+ device::sptr _dev;
+ wax::obj _mboard;
+ wax::obj _rx_ddc;
+ wax::obj _tx_duc;
+ wax::obj _rx_subdev;
+ wax::obj _tx_subdev;
+};
+
+/***********************************************************************
+ * The Make Function
+ **********************************************************************/
+simple_device::sptr simple_device::make(const std::string &args){
+ return sptr(new simple_device_impl(args_to_device_addr(args)));
+}
diff --git a/host/lib/time_spec.cpp b/host/lib/time_spec.cpp
new file mode 100644
index 000000000..210010394
--- /dev/null
+++ b/host/lib/time_spec.cpp
@@ -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/>.
+//
+
+#include <uhd/time_spec.hpp>
+
+using namespace uhd;
+
+time_spec_t::time_spec_t(void){
+ secs = ~0;
+ ticks = ~0;
+}
+
+time_spec_t::time_spec_t(boost::uint32_t new_secs, boost::uint32_t new_ticks){
+ secs = new_secs;
+ ticks = new_ticks;
+}
+
+static const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
+static double time_tick_rate = double(boost::posix_time::time_duration::ticks_per_second());
+
+time_spec_t::time_spec_t(boost::posix_time::ptime time, double tick_rate){
+ boost::posix_time::time_duration td = time - epoch;
+ secs = boost::uint32_t(td.total_seconds());
+ double time_ticks_per_device_ticks = time_tick_rate/tick_rate;
+ ticks = boost::uint32_t(td.fractional_seconds()/time_ticks_per_device_ticks);
+}
diff --git a/host/lib/transport/udp.cpp b/host/lib/transport/udp.cpp
deleted file mode 100644
index 06defb107..000000000
--- a/host/lib/transport/udp.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#include <uhd/transport/udp.hpp>
-#include <boost/format.hpp>
-#include <boost/assign/list_of.hpp>
-#include <iostream>
-
-uhd::transport::udp::udp(const std::string &addr, const std::string &port, bool bcast){
- //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
-
- // resolve the address
- boost::asio::ip::udp::resolver resolver(_io_service);
- boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port);
- _receiver_endpoint = *resolver.resolve(query);
-
- // Create and open the socket
- _socket = new boost::asio::ip::udp::socket(_io_service);
- _socket->open(boost::asio::ip::udp::v4());
-
- if (bcast){
- // Allow broadcasting
- boost::asio::socket_base::broadcast option(true);
- _socket->set_option(option);
- }
-
-}
-
-uhd::transport::udp::~udp(void){
- delete _socket;
-}
-
-void uhd::transport::udp::send(const std::vector<boost::asio::const_buffer> &buffs){
- _socket->send_to(buffs, _receiver_endpoint);
-}
-
-void uhd::transport::udp::send(const boost::asio::const_buffer &buff){
- std::vector<boost::asio::const_buffer> buffs = boost::assign::list_of(buff);
- send(buffs);
-}
-
-uhd::shared_iovec uhd::transport::udp::recv(void){
- //allocate a buffer for the number of bytes available (could be zero)
- uhd::shared_iovec iov(_socket->available());
- //call recv only if data is available
- if (iov.len != 0){
- _socket->receive_from(
- boost::asio::buffer(iov.base, iov.len),
- _sender_endpoint
- );
- }
- return iov;
-}
diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp
new file mode 100644
index 000000000..3c8ecb70d
--- /dev/null
+++ b/host/lib/transport/udp_simple.cpp
@@ -0,0 +1,158 @@
+//
+// 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/transport/udp_simple.hpp>
+#include <boost/thread.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+
+using namespace uhd::transport;
+
+/***********************************************************************
+ * Helper Functions
+ **********************************************************************/
+/*!
+ * A receive timeout for a socket:
+ *
+ * It seems that asio cannot have timeouts with synchronous io.
+ * However, we can implement a polling loop that will timeout.
+ * This is okay bacause this is the slow-path implementation.
+ *
+ * \param socket the asio socket
+ */
+static void reasonable_recv_timeout(
+ boost::asio::ip::udp::socket &socket
+){
+ boost::asio::deadline_timer timer(socket.get_io_service());
+ timer.expires_from_now(boost::posix_time::milliseconds(100));
+ while (not (socket.available() or timer.expires_from_now().is_negative())){
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ }
+}
+
+/***********************************************************************
+ * UDP connected implementation class
+ **********************************************************************/
+class udp_connected_impl : public udp_simple{
+public:
+ //structors
+ udp_connected_impl(const std::string &addr, const std::string &port);
+ ~udp_connected_impl(void);
+
+ //send/recv
+ size_t send(const boost::asio::const_buffer &buff);
+ size_t recv(const boost::asio::mutable_buffer &buff);
+
+private:
+ boost::asio::ip::udp::socket *_socket;
+ boost::asio::io_service _io_service;
+};
+
+udp_connected_impl::udp_connected_impl(const std::string &addr, const std::string &port){
+ //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
+
+ // resolve the address
+ boost::asio::ip::udp::resolver resolver(_io_service);
+ 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
+ _socket = new boost::asio::ip::udp::socket(_io_service);
+ _socket->open(boost::asio::ip::udp::v4());
+ _socket->connect(receiver_endpoint);
+}
+
+udp_connected_impl::~udp_connected_impl(void){
+ delete _socket;
+}
+
+size_t udp_connected_impl::send(const boost::asio::const_buffer &buff){
+ return _socket->send(boost::asio::buffer(buff));
+}
+
+size_t udp_connected_impl::recv(const boost::asio::mutable_buffer &buff){
+ reasonable_recv_timeout(*_socket);
+ if (not _socket->available()) return 0;
+ return _socket->receive(boost::asio::buffer(buff));
+}
+
+/***********************************************************************
+ * UDP broadcast implementation class
+ **********************************************************************/
+class udp_broadcast_impl : public udp_simple{
+public:
+ //structors
+ udp_broadcast_impl(const std::string &addr, const std::string &port);
+ ~udp_broadcast_impl(void);
+
+ //send/recv
+ size_t send(const boost::asio::const_buffer &buff);
+ size_t recv(const boost::asio::mutable_buffer &buff);
+
+private:
+ boost::asio::ip::udp::socket *_socket;
+ boost::asio::ip::udp::endpoint _receiver_endpoint;
+ boost::asio::io_service _io_service;
+};
+
+udp_broadcast_impl::udp_broadcast_impl(const std::string &addr, const std::string &port){
+ //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
+
+ // resolve the address
+ boost::asio::ip::udp::resolver resolver(_io_service);
+ boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port);
+ _receiver_endpoint = *resolver.resolve(query);
+
+ // Create and open the socket
+ _socket = new boost::asio::ip::udp::socket(_io_service);
+ _socket->open(boost::asio::ip::udp::v4());
+
+ // Allow broadcasting
+ boost::asio::socket_base::broadcast option(true);
+ _socket->set_option(option);
+
+}
+
+udp_broadcast_impl::~udp_broadcast_impl(void){
+ delete _socket;
+}
+
+size_t udp_broadcast_impl::send(const boost::asio::const_buffer &buff){
+ return _socket->send_to(boost::asio::buffer(buff), _receiver_endpoint);
+}
+
+size_t udp_broadcast_impl::recv(const boost::asio::mutable_buffer &buff){
+ reasonable_recv_timeout(*_socket);
+ if (not _socket->available()) return 0;
+ boost::asio::ip::udp::endpoint sender_endpoint;
+ return _socket->receive_from(boost::asio::buffer(buff), sender_endpoint);
+}
+
+/***********************************************************************
+ * UDP public make functions
+ **********************************************************************/
+udp_simple::sptr udp_simple::make_connected(
+ const std::string &addr, const std::string &port
+){
+ return sptr(new udp_connected_impl(addr, port));
+}
+
+udp_simple::sptr udp_simple::make_broadcast(
+ const std::string &addr, const std::string &port
+){
+ return sptr(new udp_broadcast_impl(addr, port));
+}
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp
new file mode 100644
index 000000000..219ae8720
--- /dev/null
+++ b/host/lib/transport/udp_zero_copy_asio.cpp
@@ -0,0 +1,154 @@
+//
+// 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/transport/udp_zero_copy.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/thread.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+
+using namespace uhd::transport;
+
+/***********************************************************************
+ * Smart buffer implementation for udp zerocopy none
+ *
+ * This smart buffer implemention houses a const buffer.
+ * When the smart buffer is deleted, the buffer is freed.
+ * The memory in the const buffer is allocated with new [],
+ * and so the destructor frees the buffer with delete [].
+ **********************************************************************/
+class smart_buffer_impl : public smart_buffer{
+public:
+ smart_buffer_impl(const boost::asio::const_buffer &buff){
+ _buff = buff;
+ }
+
+ ~smart_buffer_impl(void){
+ delete [] boost::asio::buffer_cast<const boost::uint32_t *>(_buff);
+ }
+
+ const boost::asio::const_buffer &get(void) const{
+ return _buff;
+ }
+
+private:
+ boost::asio::const_buffer _buff;
+};
+
+/***********************************************************************
+ * UDP zero copy implementation class
+ *
+ * This is the portable zero copy implementation for systems
+ * where a faster, platform specific solution is not available.
+ *
+ * It uses boost asio udp sockets and the standard recv() class,
+ * and in-fact, is not actually doing a zero-copy implementation.
+ **********************************************************************/
+class udp_zero_copy_impl : public udp_zero_copy{
+public:
+ //structors
+ udp_zero_copy_impl(const std::string &addr, const std::string &port);
+ ~udp_zero_copy_impl(void);
+
+ //send/recv
+ size_t send(const boost::asio::const_buffer &buff);
+ smart_buffer::sptr recv(void);
+
+private:
+ boost::asio::ip::udp::socket *_socket;
+ boost::asio::io_service _io_service;
+
+ size_t get_recv_buff_size(void);
+ void set_recv_buff_size(size_t);
+};
+
+udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){
+ //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
+
+ // resolve the address
+ boost::asio::ip::udp::resolver resolver(_io_service);
+ 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
+ _socket = new boost::asio::ip::udp::socket(_io_service);
+ _socket->open(boost::asio::ip::udp::v4());
+ _socket->connect(receiver_endpoint);
+
+ // set the rx socket buffer size:
+ // pick a huge size, and deal with whatever we get
+ set_recv_buff_size(size_t(54321e3)); //some big number!
+ size_t current_buff_size = get_recv_buff_size();
+ std::cout << boost::format(
+ "Current rx socket buffer size: %d\n"
+ ) % current_buff_size;
+ if (current_buff_size < size_t(.1e6)) std::cout << boost::format(
+ "Adjust max rx socket buffer size (linux only):\n"
+ " sysctl -w net.core.rmem_max=VALUE\n"
+ );
+}
+
+udp_zero_copy_impl::~udp_zero_copy_impl(void){
+ delete _socket;
+}
+
+size_t udp_zero_copy_impl::send(const boost::asio::const_buffer &buff){
+ return _socket->send(boost::asio::buffer(buff));
+}
+
+smart_buffer::sptr udp_zero_copy_impl::recv(void){
+ size_t available = 0;
+
+ //implement timeout through polling and sleeping
+ boost::asio::deadline_timer timer(_socket->get_io_service());
+ timer.expires_from_now(boost::posix_time::milliseconds(50));
+ while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ }
+
+ //allocate memory and create buffer
+ boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)];
+ boost::asio::mutable_buffer buff(buff_mem, available);
+
+ //receive only if data is available
+ if (available){
+ _socket->receive(boost::asio::buffer(buff));
+ }
+
+ //create a new smart buffer to house the data
+ return smart_buffer::sptr(new smart_buffer_impl(buff));
+}
+
+size_t udp_zero_copy_impl::get_recv_buff_size(void){
+ boost::asio::socket_base::receive_buffer_size option;
+ _socket->get_option(option);
+ return option.value();
+}
+
+void udp_zero_copy_impl::set_recv_buff_size(size_t new_size){
+ boost::asio::socket_base::receive_buffer_size option(new_size);
+ _socket->set_option(option);
+}
+
+/***********************************************************************
+ * UDP zero copy make function
+ **********************************************************************/
+udp_zero_copy::sptr udp_zero_copy::make(
+ const std::string &addr, const std::string &port
+){
+ return sptr(new udp_zero_copy_impl(addr, port));
+}
diff --git a/host/lib/transport/vrt.cpp b/host/lib/transport/vrt.cpp
new file mode 100644
index 000000000..a06b5bf21
--- /dev/null
+++ b/host/lib/transport/vrt.cpp
@@ -0,0 +1,109 @@
+//
+// 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/transport/vrt.hpp>
+#include <boost/asio.hpp> //endianness conversion
+#include <stdexcept>
+
+using namespace uhd;
+using namespace uhd::transport;
+
+void vrt::pack(
+ const tx_metadata_t &metadata, //input
+ boost::uint32_t *header_buff, //output
+ size_t &num_header_words32, //output
+ size_t num_payload_words32, //input
+ size_t &num_packet_words32, //output
+ size_t packet_count //input
+){
+ boost::uint32_t vrt_hdr_flags = 0;
+ num_header_words32 = 1;
+
+ //load the vrt header and flags
+ if(metadata.has_stream_id){
+ vrt_hdr_flags |= (0x1 << 28); //IF Data packet with Stream Identifier
+ header_buff[num_header_words32++] = htonl(metadata.stream_id);
+ }
+
+ if(metadata.has_time_spec){
+ vrt_hdr_flags |= (0x3 << 22) | (0x1 << 20); //TSI: Other, TSF: Sample Count Timestamp
+ header_buff[num_header_words32++] = htonl(metadata.time_spec.secs);
+ header_buff[num_header_words32++] = htonl(metadata.time_spec.ticks);
+ header_buff[num_header_words32++] = 0; //unused part of fractional seconds
+ }
+
+ vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0;
+ vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0;
+
+ num_packet_words32 = num_header_words32 + num_payload_words32;
+
+ //fill in complete header word
+ header_buff[0] = htonl(vrt_hdr_flags |
+ ((packet_count & 0xf) << 16) |
+ (num_packet_words32 & 0xffff)
+ );
+}
+
+void vrt::unpack(
+ rx_metadata_t &metadata, //output
+ const boost::uint32_t *header_buff, //input
+ size_t &num_header_words32, //output
+ size_t &num_payload_words32, //output
+ size_t num_packet_words32, //input
+ size_t &packet_count //output
+){
+ //clear the metadata
+ metadata = rx_metadata_t();
+
+ //extract vrt header
+ boost::uint32_t vrt_hdr_word = ntohl(header_buff[0]);
+ size_t packet_words32 = vrt_hdr_word & 0xffff;
+ packet_count = (vrt_hdr_word >> 16) & 0xf;
+
+ //failure cases
+ if (packet_words32 == 0 or num_packet_words32 < packet_words32)
+ throw std::runtime_error("bad vrt header or packet fragment");
+ if (vrt_hdr_word & (0x7 << 29))
+ throw std::runtime_error("unsupported vrt packet type");
+
+ //parse the header flags
+ num_header_words32 = 1;
+
+ if (vrt_hdr_word & (0x1 << 28)){ //stream id
+ metadata.has_stream_id = true;
+ metadata.stream_id = ntohl(header_buff[num_header_words32++]);
+ }
+
+ if (vrt_hdr_word & (0x1 << 27)){ //class id (we dont use)
+ num_header_words32 += 2;
+ }
+
+ if (vrt_hdr_word & (0x3 << 22)){ //integer time
+ metadata.has_time_spec = true;
+ metadata.time_spec.secs = ntohl(header_buff[num_header_words32++]);
+ }
+
+ if (vrt_hdr_word & (0x3 << 20)){ //fractional time
+ metadata.has_time_spec = true;
+ metadata.time_spec.ticks = ntohl(header_buff[num_header_words32++]);
+ num_header_words32++; //unused part of fractional seconds
+ }
+
+ size_t num_trailer_words32 = (vrt_hdr_word & (0x1 << 26))? 1 : 0;
+
+ num_payload_words32 = packet_words32 - num_header_words32 - num_trailer_words32;
+}
diff --git a/host/lib/types.cpp b/host/lib/types.cpp
new file mode 100644
index 000000000..f8a9a9b36
--- /dev/null
+++ b/host/lib/types.cpp
@@ -0,0 +1,57 @@
+//
+// 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/types.hpp>
+
+using namespace uhd;
+
+/***********************************************************************
+ * gain range
+ **********************************************************************/
+gain_range_t::gain_range_t(float min_, float max_, float step_){
+ min = min_;
+ max = max_;
+ step = step_;
+}
+
+/***********************************************************************
+ * freq range
+ **********************************************************************/
+freq_range_t::freq_range_t(double min_, double max_){
+ min = min_;
+ max = max_;
+}
+
+/***********************************************************************
+ * tune result
+ **********************************************************************/
+tune_result_t::tune_result_t(void){
+ target_inter_freq = 0.0;
+ actual_inter_freq = 0.0;
+ target_dxc_freq = 0.0;
+ actual_dxc_freq = 0.0;
+ spectrum_inverted = false;
+}
+
+/***********************************************************************
+ * clock config
+ **********************************************************************/
+clock_config_t::clock_config_t(void){
+ ref_source = ""; //not a valid setting
+ pps_source = ""; //not a valid setting
+ pps_polarity = POLARITY_NEG;
+}
diff --git a/host/lib/uhd.cpp b/host/lib/uhd.cpp
deleted file mode 100644
index 5e250c76f..000000000
--- a/host/lib/uhd.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#include <uhd.hpp>
-
-//nothing here, just includes the header so the compiler can check
diff --git a/host/lib/usrp/dboard/basic.cpp b/host/lib/usrp/dboard/basic.cpp
index f39ebff2f..82485ae6a 100644
--- a/host/lib/usrp/dboard/basic.cpp
+++ b/host/lib/usrp/dboard/basic.cpp
@@ -15,42 +15,287 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include "dboards.hpp"
+#include <uhd/utils.hpp>
+#include <uhd/props.hpp>
+#include <uhd/types.hpp>
+#include <uhd/usrp/dboard_base.hpp>
+#include <uhd/usrp/dboard_manager.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
/***********************************************************************
- * Basic RX dboard
+ * The basic and lf boards:
+ * They share a common class because only the frequency bounds differ.
**********************************************************************/
-basic_rx::basic_rx(ctor_args_t const& args) : rx_dboard_base(args){
- /* NOP */
+class basic_rx : public rx_dboard_base{
+public:
+ basic_rx(ctor_args_t const& args, freq_t max_freq);
+ ~basic_rx(void);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ freq_t _max_freq;
+};
+
+class basic_tx : public tx_dboard_base{
+public:
+ basic_tx(ctor_args_t const& args, freq_t max_freq);
+ ~basic_tx(void);
+
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ freq_t _max_freq;
+};
+
+/***********************************************************************
+ * Register the basic and LF dboards
+ **********************************************************************/
+static dboard_base::sptr make_basic_rx(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new basic_rx(args, 90e9));
+}
+
+static dboard_base::sptr make_basic_tx(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new basic_tx(args, 90e9));
+}
+
+static dboard_base::sptr make_lf_rx(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new basic_rx(args, 32e6));
+}
+
+static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new basic_tx(args, 32e6));
+}
+
+STATIC_BLOCK(reg_dboards){
+ dboard_manager::register_dboard(0x0000, &make_basic_tx, "Basic TX", list_of(""));
+ dboard_manager::register_dboard(0x0001, &make_basic_rx, "Basic RX", list_of("ab")("a")("b"));
+ dboard_manager::register_dboard(0x000e, &make_lf_tx, "LF TX", list_of(""));
+ dboard_manager::register_dboard(0x000f, &make_lf_rx, "LF RX", list_of("ab")("a")("b"));
+}
+
+/***********************************************************************
+ * Basic and LF RX dboard
+ **********************************************************************/
+basic_rx::basic_rx(ctor_args_t const& args, freq_t max_freq) : rx_dboard_base(args){
+ _max_freq = max_freq;
+ // set the gpios to safe values (all inputs)
+ get_interface()->set_gpio_ddr(dboard_interface::GPIO_RX_BANK, 0x0000, 0xffff);
}
basic_rx::~basic_rx(void){
/* NOP */
}
-void basic_rx::rx_get(const wax::obj &, wax::obj &){
- /* TODO */
+void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = std::string(str(boost::format("%s - %s")
+ % dboard_id::to_string(get_rx_id())
+ % get_subdev_name()
+ ));
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ val = gain_t(0);
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ val = gain_range_t(0, 0, 0);
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = freq_t(0);
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = freq_range_t(+_max_freq, -_max_freq);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = prop_names_t(1, ""); //vector of 1 empty string
+ return;
+
+ case SUBDEV_PROP_ENABLED:
+ val = true; //always enabled
+ return;
+
+ case SUBDEV_PROP_QUADRATURE:
+ val = (get_subdev_name() == "ab"); //only quadrature in ab mode
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ case SUBDEV_PROP_LO_INTERFERES:
+ val = false;
+ return;
+ }
}
-void basic_rx::rx_set(const wax::obj &, const wax::obj &){
- /* TODO */
+void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_GAIN:
+ ASSERT_THROW(val.as<gain_t>() == gain_t(0));
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ ASSERT_THROW(val.as<std::string>() == std::string(""));
+ return;
+
+ case SUBDEV_PROP_ENABLED:
+ return; // it wont do you much good, but you can set it
+
+ case SUBDEV_PROP_FREQ:
+ return; // it wont do you much good, but you can set it
+
+ case SUBDEV_PROP_NAME:
+ case SUBDEV_PROP_OTHERS:
+ case SUBDEV_PROP_GAIN_RANGE:
+ case SUBDEV_PROP_GAIN_NAMES:
+ case SUBDEV_PROP_FREQ_RANGE:
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ case SUBDEV_PROP_QUADRATURE:
+ case SUBDEV_PROP_IQ_SWAPPED:
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ case SUBDEV_PROP_LO_INTERFERES:
+ throw std::runtime_error(str(boost::format(
+ "Error: trying to set read-only property on %s subdev"
+ ) % dboard_id::to_string(get_rx_id())));
+ }
}
/***********************************************************************
- * Basic TX dboard
+ * Basic and LF TX dboard
**********************************************************************/
-basic_tx::basic_tx(ctor_args_t const& args) : tx_dboard_base(args){
- /* NOP */
+basic_tx::basic_tx(ctor_args_t const& args, freq_t max_freq) : tx_dboard_base(args){
+ _max_freq = max_freq;
+ // set the gpios to safe values (all inputs)
+ get_interface()->set_gpio_ddr(dboard_interface::GPIO_TX_BANK, 0x0000, 0xffff);
}
basic_tx::~basic_tx(void){
/* NOP */
}
-void basic_tx::tx_get(const wax::obj &, wax::obj &){
- /* TODO */
+void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = dboard_id::to_string(get_tx_id());
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ val = gain_t(0);
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ val = gain_range_t(0, 0, 0);
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = freq_t(0);
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = freq_range_t(+_max_freq, -_max_freq);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = prop_names_t(1, ""); //vector of 1 empty string
+ return;
+
+ case SUBDEV_PROP_ENABLED:
+ val = true; //always enabled
+ return;
+
+ case SUBDEV_PROP_QUADRATURE:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ case SUBDEV_PROP_LO_INTERFERES:
+ val = false;
+ return;
+ }
}
-void basic_tx::tx_set(const wax::obj &, const wax::obj &){
- /* TODO */
+void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_GAIN:
+ ASSERT_THROW(val.as<gain_t>() == gain_t(0));
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ ASSERT_THROW(val.as<std::string>() == std::string(""));
+ return;
+
+ case SUBDEV_PROP_ENABLED:
+ return; // it wont do you much good, but you can set it
+
+ case SUBDEV_PROP_FREQ:
+ return; // it wont do you much good, but you can set it
+
+ case SUBDEV_PROP_NAME:
+ case SUBDEV_PROP_OTHERS:
+ case SUBDEV_PROP_GAIN_RANGE:
+ case SUBDEV_PROP_GAIN_NAMES:
+ case SUBDEV_PROP_FREQ_RANGE:
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ case SUBDEV_PROP_QUADRATURE:
+ case SUBDEV_PROP_IQ_SWAPPED:
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ case SUBDEV_PROP_LO_INTERFERES:
+ throw std::runtime_error(str(boost::format(
+ "Error: trying to set read-only property on %s subdev"
+ ) % dboard_id::to_string(get_tx_id())));
+ }
}
diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp
index f0846db25..6ca15e98c 100644
--- a/host/lib/usrp/dboard_manager.cpp
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -16,85 +16,49 @@
//
#include <uhd/usrp/dboard_manager.hpp>
+#include <uhd/gain_handler.hpp>
#include <uhd/utils.hpp>
#include <uhd/dict.hpp>
-#include <boost/assign/list_of.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/format.hpp>
+#include <boost/bind.hpp>
#include <boost/foreach.hpp>
-#include "dboard/dboards.hpp"
using namespace uhd;
using namespace uhd::usrp;
-using namespace boost::assign;
-
-/***********************************************************************
- * register internal dboards
- *
- * Register internal/known dboards located in this build tree.
- * Each board should have entries below mapping an id to a constructor.
- * The xcvr type boards should register both rx and tx sides.
- *
- * This function will be called before new boards are registered.
- * This allows for internal boards to be externally overridden.
- * This function will also be called when creating a new dboard_manager
- * to ensure that the maps are filled with the entries below.
- **********************************************************************/
-static void register_internal_dboards(void){
- //ensure that this function can only be called once per instance
- static bool called = false;
- if (called) return; called = true;
- //register the known dboards (dboard id, constructor, subdev names)
- dboard_manager::register_subdevs(ID_BASIC_TX, &basic_tx::make, list_of(""));
- dboard_manager::register_subdevs(ID_BASIC_RX, &basic_rx::make, list_of("a")("b")("ab"));
-}
/***********************************************************************
* storage and registering for dboards
**********************************************************************/
-typedef boost::tuple<dboard_manager::dboard_ctor_t, prop_names_t> args_t;
+//dboard registry tuple: dboard constructor, canonical name, subdev names
+typedef boost::tuple<dboard_manager::dboard_ctor_t, std::string, prop_names_t> args_t;
//map a dboard id to a dboard constructor
-static uhd::dict<dboard_id_t, args_t> id_to_args_map;
+typedef uhd::dict<dboard_id_t, args_t> id_to_args_map_t;
+STATIC_INSTANCE(id_to_args_map_t, get_id_to_args_map)
-void dboard_manager::register_subdevs(
+void dboard_manager::register_dboard(
dboard_id_t dboard_id,
dboard_ctor_t dboard_ctor,
+ const std::string &name,
const prop_names_t &subdev_names
){
- register_internal_dboards(); //always call first
- id_to_args_map[dboard_id] = args_t(dboard_ctor, subdev_names);
+ //std::cout << "registering: " << name << std::endl;
+ if (get_id_to_args_map().has_key(dboard_id)){
+ throw std::runtime_error(str(boost::format(
+ "The dboard id 0x%04x is already registered to %s."
+ ) % dboard_id % dboard_id::to_string(dboard_id)));
+ }
+ get_id_to_args_map()[dboard_id] = args_t(dboard_ctor, name, subdev_names);
}
-/***********************************************************************
- * dboard manager implementation class
- **********************************************************************/
-class dboard_manager_impl : public dboard_manager{
-
-public:
- dboard_manager_impl(
- dboard_id_t rx_dboard_id,
- dboard_id_t tx_dboard_id,
- dboard_interface::sptr interface
- );
- ~dboard_manager_impl(void);
-
- //dboard_interface
- prop_names_t get_rx_subdev_names(void);
- prop_names_t get_tx_subdev_names(void);
- wax::obj get_rx_subdev(const std::string &subdev_name);
- wax::obj get_tx_subdev(const std::string &subdev_name);
-
-private:
- //list of rx and tx dboards in this dboard_manager
- //each dboard here is actually a subdevice proxy
- //the subdevice proxy is internal to the cpp file
- uhd::dict<std::string, wax::obj> _rx_dboards;
- uhd::dict<std::string, wax::obj> _tx_dboards;
-};
+std::string dboard_id::to_string(const dboard_id_t &id){
+ std::string name = (get_id_to_args_map().has_key(id))? get_id_to_args_map()[id].get<1>() : "unknown";
+ return str(boost::format("%s (0x%04x)") % name % id);
+}
/***********************************************************************
- * internal helper classes
+ * internal helper classe
**********************************************************************/
/*!
* A special wax proxy object that forwards calls to a subdev.
@@ -108,7 +72,17 @@ public:
//structors
subdev_proxy(dboard_base::sptr subdev, type_t type)
: _subdev(subdev), _type(type){
- /* NOP */
+ //initialize gain props struct
+ gain_handler::props_t gain_props;
+ gain_props.value = SUBDEV_PROP_GAIN;
+ gain_props.range = SUBDEV_PROP_GAIN_RANGE;
+ gain_props.names = SUBDEV_PROP_GAIN_NAMES;
+
+ //make a new gain handler
+ _gain_handler = gain_handler::make(
+ this->get_link(), gain_props,
+ boost::bind(&gain_handler::is_equal<subdev_prop_t>, _1, _2)
+ );
}
~subdev_proxy(void){
@@ -116,11 +90,13 @@ public:
}
private:
+ gain_handler::sptr _gain_handler;
dboard_base::sptr _subdev;
type_t _type;
//forward the get calls to the rx or tx
void get(const wax::obj &key, wax::obj &val){
+ if (_gain_handler->intercept_get(key, val)) return;
switch(_type){
case RX_TYPE: return _subdev->rx_get(key, val);
case TX_TYPE: return _subdev->tx_get(key, val);
@@ -129,6 +105,7 @@ private:
//forward the set calls to the rx or tx
void set(const wax::obj &key, const wax::obj &val){
+ if (_gain_handler->intercept_set(key, val)) return;
switch(_type){
case RX_TYPE: return _subdev->rx_set(key, val);
case TX_TYPE: return _subdev->tx_set(key, val);
@@ -137,6 +114,35 @@ private:
};
/***********************************************************************
+ * dboard manager implementation class
+ **********************************************************************/
+class dboard_manager_impl : public dboard_manager{
+
+public:
+ dboard_manager_impl(
+ dboard_id_t rx_dboard_id,
+ dboard_id_t tx_dboard_id,
+ dboard_interface::sptr interface
+ );
+ ~dboard_manager_impl(void);
+
+ //dboard_interface
+ prop_names_t get_rx_subdev_names(void);
+ prop_names_t get_tx_subdev_names(void);
+ wax::obj get_rx_subdev(const std::string &subdev_name);
+ wax::obj get_tx_subdev(const std::string &subdev_name);
+
+private:
+ //list of rx and tx dboards in this dboard_manager
+ //each dboard here is actually a subdevice proxy
+ //the subdevice proxy is internal to the cpp file
+ uhd::dict<std::string, subdev_proxy::sptr> _rx_dboards;
+ uhd::dict<std::string, subdev_proxy::sptr> _tx_dboards;
+ dboard_interface::sptr _interface;
+ void set_nice_gpio_pins(void);
+};
+
+/***********************************************************************
* make routine for dboard manager
**********************************************************************/
dboard_manager::sptr dboard_manager::make(
@@ -158,16 +164,16 @@ static args_t get_dboard_args(
){
//special case, its rx and the none id (0xffff)
if (xx_type == "rx" and dboard_id == ID_NONE){
- return args_t(&basic_rx::make, list_of("ab"));
+ return get_dboard_args(0x0001, xx_type);
}
//special case, its tx and the none id (0xffff)
if (xx_type == "tx" and dboard_id == ID_NONE){
- return args_t(&basic_tx::make, list_of(""));
+ return get_dboard_args(0x0000, xx_type);
}
//verify that there is a registered constructor for this id
- if (not id_to_args_map.has_key(dboard_id)){
+ if (not get_id_to_args_map().has_key(dboard_id)){
throw std::runtime_error(str(
boost::format("Unregistered %s dboard id: %s")
% xx_type % dboard_id::to_string(dboard_id)
@@ -175,7 +181,7 @@ static args_t get_dboard_args(
}
//return the dboard args for this id
- return id_to_args_map[dboard_id];
+ return get_id_to_args_map()[dboard_id];
}
dboard_manager_impl::dboard_manager_impl(
@@ -183,37 +189,30 @@ dboard_manager_impl::dboard_manager_impl(
dboard_id_t tx_dboard_id,
dboard_interface::sptr interface
){
- register_internal_dboards(); //always call first
+ _interface = interface;
- dboard_ctor_t rx_dboard_ctor; prop_names_t rx_subdevs;
- boost::tie(rx_dboard_ctor, rx_subdevs) = get_dboard_args(rx_dboard_id, "rx");
+ dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs;
+ boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(rx_dboard_id, "rx");
- dboard_ctor_t tx_dboard_ctor; prop_names_t tx_subdevs;
- boost::tie(tx_dboard_ctor, tx_subdevs) = get_dboard_args(tx_dboard_id, "tx");
+ dboard_ctor_t tx_dboard_ctor; std::string tx_name; prop_names_t tx_subdevs;
+ boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(tx_dboard_id, "tx");
//initialize the gpio pins before creating subdevs
- interface->set_gpio_ddr(dboard_interface::GPIO_RX_BANK, 0x0000, 0xffff); //all inputs
- interface->set_gpio_ddr(dboard_interface::GPIO_TX_BANK, 0x0000, 0xffff);
-
- interface->write_gpio(dboard_interface::GPIO_RX_BANK, 0x0000, 0xffff); //all zeros
- interface->write_gpio(dboard_interface::GPIO_TX_BANK, 0x0000, 0xffff);
-
- interface->set_atr_reg(dboard_interface::GPIO_RX_BANK, 0x0000, 0x0000, 0x0000); //software controlled
- interface->set_atr_reg(dboard_interface::GPIO_TX_BANK, 0x0000, 0x0000, 0x0000);
+ set_nice_gpio_pins();
//make xcvr subdevs (make one subdev for both rx and tx dboards)
if (rx_dboard_ctor == tx_dboard_ctor){
ASSERT_THROW(rx_subdevs == tx_subdevs);
- BOOST_FOREACH(std::string name, rx_subdevs){
+ BOOST_FOREACH(std::string subdev, rx_subdevs){
dboard_base::sptr xcvr_dboard = rx_dboard_ctor(
- dboard_base::ctor_args_t(name, interface, rx_dboard_id, tx_dboard_id)
+ dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, tx_dboard_id)
);
//create a rx proxy for this xcvr board
- _rx_dboards[name] = subdev_proxy::sptr(
+ _rx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(xcvr_dboard, subdev_proxy::RX_TYPE)
);
//create a tx proxy for this xcvr board
- _tx_dboards[name] = subdev_proxy::sptr(
+ _tx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(xcvr_dboard, subdev_proxy::TX_TYPE)
);
}
@@ -222,22 +221,22 @@ dboard_manager_impl::dboard_manager_impl(
//make tx and rx subdevs (separate subdevs for rx and tx dboards)
else{
//make the rx subdevs
- BOOST_FOREACH(std::string name, rx_subdevs){
+ BOOST_FOREACH(std::string subdev, rx_subdevs){
dboard_base::sptr rx_dboard = rx_dboard_ctor(
- dboard_base::ctor_args_t(name, interface, rx_dboard_id, ID_NONE)
+ dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, ID_NONE)
);
//create a rx proxy for this rx board
- _rx_dboards[name] = subdev_proxy::sptr(
+ _rx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(rx_dboard, subdev_proxy::RX_TYPE)
);
}
//make the tx subdevs
- BOOST_FOREACH(std::string name, tx_subdevs){
+ BOOST_FOREACH(std::string subdev, tx_subdevs){
dboard_base::sptr tx_dboard = tx_dboard_ctor(
- dboard_base::ctor_args_t(name, interface, ID_NONE, tx_dboard_id)
+ dboard_base::ctor_args_t(subdev, interface, ID_NONE, tx_dboard_id)
);
//create a tx proxy for this tx board
- _tx_dboards[name] = subdev_proxy::sptr(
+ _tx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(tx_dboard, subdev_proxy::TX_TYPE)
);
}
@@ -245,7 +244,7 @@ dboard_manager_impl::dboard_manager_impl(
}
dboard_manager_impl::~dboard_manager_impl(void){
- /* NOP */
+ set_nice_gpio_pins();
}
prop_names_t dboard_manager_impl::get_rx_subdev_names(void){
@@ -261,7 +260,7 @@ wax::obj dboard_manager_impl::get_rx_subdev(const std::string &subdev_name){
str(boost::format("Unknown rx subdev name %s") % subdev_name)
);
//get a link to the rx subdev proxy
- return wax::cast<subdev_proxy::sptr>(_rx_dboards[subdev_name])->get_link();
+ return _rx_dboards[subdev_name]->get_link();
}
wax::obj dboard_manager_impl::get_tx_subdev(const std::string &subdev_name){
@@ -269,5 +268,18 @@ wax::obj dboard_manager_impl::get_tx_subdev(const std::string &subdev_name){
str(boost::format("Unknown tx subdev name %s") % subdev_name)
);
//get a link to the tx subdev proxy
- return wax::cast<subdev_proxy::sptr>(_tx_dboards[subdev_name])->get_link();
+ return _tx_dboards[subdev_name]->get_link();
+}
+
+void dboard_manager_impl::set_nice_gpio_pins(void){
+ //std::cout << "Set nice GPIO pins" << std::endl;
+
+ _interface->set_gpio_ddr(dboard_interface::GPIO_RX_BANK, 0x0000, 0xffff); //all inputs
+ _interface->set_gpio_ddr(dboard_interface::GPIO_TX_BANK, 0x0000, 0xffff);
+
+ _interface->write_gpio(dboard_interface::GPIO_RX_BANK, 0x0000, 0xffff); //all zeros
+ _interface->write_gpio(dboard_interface::GPIO_TX_BANK, 0x0000, 0xffff);
+
+ _interface->set_atr_reg(dboard_interface::GPIO_RX_BANK, 0x0000, 0x0000, 0x0000); //software controlled
+ _interface->set_atr_reg(dboard_interface::GPIO_TX_BANK, 0x0000, 0x0000, 0x0000);
}
diff --git a/host/lib/usrp/usrp1e/dboard_impl.cpp b/host/lib/usrp/usrp1e/dboard_impl.cpp
new file mode 100644
index 000000000..a2798dce3
--- /dev/null
+++ b/host/lib/usrp/usrp1e/dboard_impl.cpp
@@ -0,0 +1,76 @@
+//
+// 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 <boost/bind.hpp>
+#include <uhd/utils.hpp>
+#include "usrp1e_impl.hpp"
+
+using namespace uhd::usrp;
+
+/***********************************************************************
+ * Dboard Initialization
+ **********************************************************************/
+void usrp1e_impl::dboard_init(void){
+ dboard_id_t rx_dboard_id = dboard_id::NONE; //TODO get these from the eeprom
+ dboard_id_t tx_dboard_id = dboard_id::NONE;
+
+ //create a new dboard interface and manager
+ dboard_interface::sptr dboard_interface(
+ make_usrp1e_dboard_interface(this)
+ );
+ _dboard_manager = dboard_manager::make(
+ rx_dboard_id, tx_dboard_id, dboard_interface
+ );
+
+ //setup the dboard proxies
+ _rx_dboard_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp1e_impl::rx_dboard_get, this, _1, _2),
+ boost::bind(&usrp1e_impl::rx_dboard_set, this, _1, _2)
+ );
+ _tx_dboard_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp1e_impl::tx_dboard_get, this, _1, _2),
+ boost::bind(&usrp1e_impl::tx_dboard_set, this, _1, _2)
+ );
+}
+
+/***********************************************************************
+ * RX Dboard Get
+ **********************************************************************/
+void usrp1e_impl::rx_dboard_get(const wax::obj &, wax::obj &){
+
+}
+
+/***********************************************************************
+ * RX Dboard Set
+ **********************************************************************/
+void usrp1e_impl::rx_dboard_set(const wax::obj &, const wax::obj &){
+
+}
+
+/***********************************************************************
+ * TX Dboard Get
+ **********************************************************************/
+void usrp1e_impl::tx_dboard_get(const wax::obj &, wax::obj &){
+
+}
+
+/***********************************************************************
+ * TX Dboard Set
+ **********************************************************************/
+void usrp1e_impl::tx_dboard_set(const wax::obj &, const wax::obj &){
+
+}
diff --git a/host/lib/usrp/usrp1e/dboard_interface.cpp b/host/lib/usrp/usrp1e/dboard_interface.cpp
new file mode 100644
index 000000000..ef91014ac
--- /dev/null
+++ b/host/lib/usrp/usrp1e/dboard_interface.cpp
@@ -0,0 +1,189 @@
+//
+// 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.hpp>
+#include <algorithm> //std::copy
+#include "usrp1e_impl.hpp"
+#include <linux/usrp1_e.h>
+
+using namespace uhd::usrp;
+
+class usrp1e_dboard_interface : public dboard_interface{
+public:
+ usrp1e_dboard_interface(usrp1e_impl *impl);
+ ~usrp1e_dboard_interface(void);
+
+ void write_aux_dac(unit_type_t, int, int);
+ int read_aux_adc(unit_type_t, int);
+
+ void set_atr_reg(gpio_bank_t, boost::uint16_t, boost::uint16_t, boost::uint16_t);
+ void set_gpio_ddr(gpio_bank_t, boost::uint16_t, boost::uint16_t);
+ void write_gpio(gpio_bank_t, boost::uint16_t, boost::uint16_t);
+ boost::uint16_t read_gpio(gpio_bank_t);
+
+ void write_i2c(int, const byte_vector_t &);
+ byte_vector_t read_i2c(int, size_t);
+
+ double get_rx_clock_rate(void);
+ double get_tx_clock_rate(void);
+
+private:
+ byte_vector_t transact_spi(
+ spi_dev_t dev,
+ spi_latch_t latch,
+ spi_push_t push,
+ const byte_vector_t &buf,
+ bool readback
+ );
+
+ usrp1e_impl *_impl;
+};
+
+/***********************************************************************
+ * Make Function
+ **********************************************************************/
+dboard_interface::sptr make_usrp1e_dboard_interface(usrp1e_impl *impl){
+ return dboard_interface::sptr(new usrp1e_dboard_interface(impl));
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+usrp1e_dboard_interface::usrp1e_dboard_interface(usrp1e_impl *impl){
+ _impl = impl;
+}
+
+usrp1e_dboard_interface::~usrp1e_dboard_interface(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Clock Rates
+ **********************************************************************/
+double usrp1e_dboard_interface::get_rx_clock_rate(void){
+ throw std::runtime_error("not implemented");
+}
+
+double usrp1e_dboard_interface::get_tx_clock_rate(void){
+ throw std::runtime_error("not implemented");
+}
+
+/***********************************************************************
+ * GPIO
+ **********************************************************************/
+void usrp1e_dboard_interface::set_gpio_ddr(gpio_bank_t bank, boost::uint16_t value, boost::uint16_t mask){
+ throw std::runtime_error("not implemented");
+}
+
+void usrp1e_dboard_interface::write_gpio(gpio_bank_t bank, boost::uint16_t value, boost::uint16_t mask){
+ throw std::runtime_error("not implemented");
+}
+
+boost::uint16_t usrp1e_dboard_interface::read_gpio(gpio_bank_t bank){
+ throw std::runtime_error("not implemented");
+}
+
+void usrp1e_dboard_interface::set_atr_reg(gpio_bank_t bank, boost::uint16_t tx_value, boost::uint16_t rx_value, boost::uint16_t mask){
+ throw std::runtime_error("not implemented");
+}
+
+/***********************************************************************
+ * SPI
+ **********************************************************************/
+dboard_interface::byte_vector_t usrp1e_dboard_interface::transact_spi(
+ spi_dev_t dev,
+ spi_latch_t latch,
+ spi_push_t push,
+ const byte_vector_t &buf,
+ bool readback
+){
+ //load data struct
+ usrp_e_spi data;
+ data.readback = (readback)? UE_SPI_TXRX : UE_SPI_TXONLY;
+ data.slave = (dev == SPI_RX_DEV)? UE_SPI_CTRL_RXNEG : UE_SPI_CTRL_TXNEG;
+ data.length = buf.size() * 8; //bytes to bits
+ boost::uint8_t *data_bytes = reinterpret_cast<boost::uint8_t*>(&data.data);
+
+ //load the data
+ ASSERT_THROW(buf.size() <= sizeof(data.data));
+ std::copy(buf.begin(), buf.end(), data_bytes);
+
+ //load the flags
+ data.flags = 0;
+ data.flags |= (latch == SPI_LATCH_RISE)? UE_SPI_LATCH_RISE : UE_SPI_LATCH_FALL;
+ data.flags |= (push == SPI_PUSH_RISE)? UE_SPI_PUSH_RISE : UE_SPI_PUSH_FALL;
+
+ //call the spi ioctl
+ _impl->ioctl(USRP_E_SPI, &data);
+
+ //unload the data
+ byte_vector_t ret(data.length/8); //bits to bytes
+ ASSERT_THROW(ret.size() <= sizeof(data.data));
+ std::copy(data_bytes, data_bytes+ret.size(), ret.begin());
+ return ret;
+}
+
+/***********************************************************************
+ * I2C
+ **********************************************************************/
+static const size_t max_i2c_data_bytes = 10;
+
+void usrp1e_dboard_interface::write_i2c(int i2c_addr, const byte_vector_t &buf){
+ //allocate some memory for this transaction
+ ASSERT_THROW(buf.size() <= max_i2c_data_bytes);
+ boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes];
+
+ //load the data struct
+ usrp_e_i2c &data = reinterpret_cast<usrp_e_i2c&>(mem);
+ data.addr = i2c_addr;
+ data.len = buf.size();
+ std::copy(buf.begin(), buf.end(), data.data);
+
+ //call the spi ioctl
+ _impl->ioctl(USRP_E_I2C_WRITE, &data);
+}
+
+dboard_interface::byte_vector_t usrp1e_dboard_interface::read_i2c(int i2c_addr, size_t num_bytes){
+ //allocate some memory for this transaction
+ ASSERT_THROW(num_bytes <= max_i2c_data_bytes);
+ boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes];
+
+ //load the data struct
+ usrp_e_i2c &data = reinterpret_cast<usrp_e_i2c&>(mem);
+ data.addr = i2c_addr;
+ data.len = num_bytes;
+
+ //call the spi ioctl
+ _impl->ioctl(USRP_E_I2C_READ, &data);
+
+ //unload the data
+ byte_vector_t ret(data.len);
+ ASSERT_THROW(ret.size() == num_bytes);
+ std::copy(data.data, data.data+ret.size(), ret.begin());
+ return ret;
+}
+
+/***********************************************************************
+ * Aux DAX/ADC
+ **********************************************************************/
+void usrp1e_dboard_interface::write_aux_dac(dboard_interface::unit_type_t unit, int which, int value){
+ throw std::runtime_error("not implemented");
+}
+
+int usrp1e_dboard_interface::read_aux_adc(dboard_interface::unit_type_t unit, int which){
+ throw std::runtime_error("not implemented");
+}
diff --git a/host/lib/usrp/usrp1e/dsp_impl.cpp b/host/lib/usrp/usrp1e/dsp_impl.cpp
new file mode 100644
index 000000000..862b89184
--- /dev/null
+++ b/host/lib/usrp/usrp1e/dsp_impl.cpp
@@ -0,0 +1,70 @@
+//
+// 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 <boost/bind.hpp>
+#include <uhd/utils.hpp>
+#include "usrp1e_impl.hpp"
+
+using namespace uhd::usrp;
+
+/***********************************************************************
+ * RX DDC Initialization
+ **********************************************************************/
+void usrp1e_impl::rx_ddc_init(void){
+ _rx_ddc_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp1e_impl::rx_ddc_get, this, _1, _2),
+ boost::bind(&usrp1e_impl::rx_ddc_set, this, _1, _2)
+ );
+}
+
+/***********************************************************************
+ * RX DDC Get
+ **********************************************************************/
+void usrp1e_impl::rx_ddc_get(const wax::obj &, wax::obj &){
+
+}
+
+/***********************************************************************
+ * RX DDC Set
+ **********************************************************************/
+void usrp1e_impl::rx_ddc_set(const wax::obj &, const wax::obj &){
+
+}
+
+/***********************************************************************
+ * TX DUC Initialization
+ **********************************************************************/
+void usrp1e_impl::tx_duc_init(void){
+ _tx_duc_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp1e_impl::tx_duc_get, this, _1, _2),
+ boost::bind(&usrp1e_impl::tx_duc_set, this, _1, _2)
+ );
+}
+
+/***********************************************************************
+ * TX DUC Get
+ **********************************************************************/
+void usrp1e_impl::tx_duc_get(const wax::obj &, wax::obj &){
+
+}
+
+/***********************************************************************
+ * TX DUC Set
+ **********************************************************************/
+void usrp1e_impl::tx_duc_set(const wax::obj &, const wax::obj &){
+
+}
diff --git a/host/lib/usrp/usrp1e/fpga-downloader.cc b/host/lib/usrp/usrp1e/fpga-downloader.cc
new file mode 100644
index 000000000..f7c78b875
--- /dev/null
+++ b/host/lib/usrp/usrp1e/fpga-downloader.cc
@@ -0,0 +1,262 @@
+//
+// 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 <iostream>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <cstdlib>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <linux/spi/spidev.h>
+
+/*
+ * Configuration connections
+ *
+ * CCK - MCSPI1_CLK
+ * DIN - MCSPI1_MOSI
+ * PROG_B - GPIO_175 - output (change mux)
+ * DONE - GPIO_173 - input (change mux)
+ * INIT_B - GPIO_114 - input (change mux)
+ *
+*/
+
+const unsigned int PROG_B = 175;
+const unsigned int DONE = 173;
+const unsigned int INIT_B = 114;
+
+//static std::string bit_file = "safe_u1e.bin";
+
+const int BUF_SIZE = 4096;
+
+enum gpio_direction {IN, OUT};
+
+class gpio {
+ public:
+
+ gpio(unsigned int gpio_num, gpio_direction pin_direction);
+
+ bool get_value();
+ void set_value(bool state);
+
+ private:
+
+ std::stringstream base_path;
+ std::fstream value_file;
+};
+
+class spidev {
+ public:
+
+ spidev(std::string dev_name);
+ ~spidev();
+
+ void send(char *wbuf, char *rbuf, unsigned int nbytes);
+
+ private:
+
+ int fd;
+
+};
+
+gpio::gpio(unsigned int gpio_num, gpio_direction pin_direction)
+{
+ std::fstream export_file;
+
+ export_file.open("/sys/class/gpio/export", std::ios::out);
+ if (!export_file.is_open()) ///\todo Poor error handling
+ std::cout << "Failed to open gpio export file." << std::endl;
+
+ export_file << gpio_num << std::endl;
+
+ base_path << "/sys/class/gpio/gpio" << gpio_num << std::flush;
+
+ std::fstream direction_file;
+ std::string direction_file_name;
+
+ direction_file_name = base_path.str() + "/direction";
+
+ direction_file.open(direction_file_name.c_str());
+ if (!direction_file.is_open())
+ std::cout << "Failed to open direction file." << std::endl;
+ if (pin_direction == OUT)
+ direction_file << "out" << std::endl;
+ else
+ direction_file << "in" << std::endl;
+
+ std::string value_file_name;
+
+ value_file_name = base_path.str() + "/value";
+
+ value_file.open(value_file_name.c_str(), std::ios_base::in | std::ios_base::out);
+ if (!value_file.is_open())
+ std::cout << "Failed to open value file." << std::endl;
+}
+
+bool gpio::get_value()
+{
+
+ std::string val;
+
+ std::getline(value_file, val);
+ value_file.seekg(0);
+
+ if (val == "0")
+ return false;
+ else if (val == "1")
+ return true;
+ else
+ std::cout << "Data read from value file|" << val << "|" << std::endl;
+
+ return false;
+}
+
+void gpio::set_value(bool state)
+{
+
+ if (state)
+ value_file << "1" << std::endl;
+ else
+ value_file << "0" << std::endl;
+}
+
+static void prepare_fpga_for_configuration(gpio &prog, gpio &)//init)
+{
+
+ prog.set_value(true);
+ prog.set_value(false);
+ prog.set_value(true);
+
+#if 0
+ bool ready_to_program(false);
+ unsigned int count(0);
+ do {
+ ready_to_program = init.get_value();
+ count++;
+
+ sleep(1);
+ } while (count < 10 && !ready_to_program);
+
+ if (count == 10) {
+ std::cout << "FPGA not ready for programming." << std::endl;
+ exit(-1);
+ }
+#endif
+}
+
+spidev::spidev(std::string fname)
+{
+ int ret;
+ int mode = 0;
+ int speed = 12000000;
+ int bits = 8;
+
+ fd = open(fname.c_str(), O_RDWR);
+
+ ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
+ ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
+ ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
+}
+
+
+spidev::~spidev()
+{
+ close(fd);
+}
+
+void spidev::send(char *buf, char *rbuf, unsigned int nbytes)
+{
+ int ret;
+
+ struct spi_ioc_transfer tr;
+ tr.tx_buf = (unsigned long) buf;
+ tr.rx_buf = (unsigned long) rbuf;
+ tr.len = nbytes;
+ tr.delay_usecs = 0;
+ tr.speed_hz = 48000000;
+ tr.bits_per_word = 8;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+
+}
+
+static void send_file_to_fpga(const std::string &file_name, gpio &error, gpio &done)
+{
+ std::ifstream bitstream;
+
+ std::cout << "File name - " << file_name.c_str() << std::endl;
+
+ bitstream.open(file_name.c_str(), std::ios::binary);
+ if (!bitstream.is_open())
+ std::cout << "File " << file_name << " not opened succesfully." << std::endl;
+
+ spidev spi("/dev/spidev1.0");
+ char buf[BUF_SIZE];
+ char rbuf[BUF_SIZE];
+
+ do {
+ bitstream.read(buf, BUF_SIZE);
+ spi.send(buf, rbuf, bitstream.gcount());
+
+ if (error.get_value())
+ std::cout << "INIT_B went high, error occured." << std::endl;
+
+ if (!done.get_value())
+ std::cout << "Configuration complete." << std::endl;
+
+ } while (bitstream.gcount() == BUF_SIZE);
+}
+
+/*
+int main(int argc, char *argv[])
+{
+
+ gpio gpio_prog_b(PROG_B, OUT);
+ gpio gpio_init_b(INIT_B, IN);
+ gpio gpio_done (DONE, IN);
+
+ if (argc == 2)
+ bit_file = argv[1];
+
+ std::cout << "FPGA config file: " << bit_file << std::endl;
+
+ prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b);
+
+ std::cout << "Done = " << gpio_done.get_value() << std::endl;
+
+ send_file_to_fpga(bit_file, gpio_init_b, gpio_done);
+}
+*/
+
+#include <uhd/usrp/usrp1e.hpp>
+void uhd::usrp::usrp1e::load_fpga(const std::string &bin_file){
+ gpio gpio_prog_b(PROG_B, OUT);
+ gpio gpio_init_b(INIT_B, IN);
+ gpio gpio_done (DONE, IN);
+
+ std::cout << "FPGA config file: " << bin_file << std::endl;
+
+ prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b);
+
+ std::cout << "Done = " << gpio_done.get_value() << std::endl;
+
+ send_file_to_fpga(bin_file, gpio_init_b, gpio_done);
+}
diff --git a/host/lib/usrp/dboard/dboards.hpp b/host/lib/usrp/usrp1e/mboard_impl.cpp
index 79b90d593..b480f7616 100644
--- a/host/lib/usrp/dboard/dboards.hpp
+++ b/host/lib/usrp/usrp1e/mboard_impl.cpp
@@ -15,39 +15,32 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#ifndef INCLUDED_LOCAL_DBOARDS_HPP
-#define INCLUDED_LOCAL_DBOARDS_HPP
-
-#include <uhd/usrp/dboard_base.hpp>
+#include <boost/bind.hpp>
+#include <uhd/utils.hpp>
+#include "usrp1e_impl.hpp"
using namespace uhd::usrp;
/***********************************************************************
- * The basic boards:
+ * Mboard Initialization
**********************************************************************/
-class basic_rx : public rx_dboard_base{
-public:
- static dboard_base::sptr make(ctor_args_t const& args){
- return dboard_base::sptr(new basic_rx(args));
- }
- basic_rx(ctor_args_t const& args);
- ~basic_rx(void);
-
- void rx_get(const wax::obj &key, wax::obj &val);
- void rx_set(const wax::obj &key, const wax::obj &val);
-};
-
-class basic_tx : public tx_dboard_base{
-public:
- static dboard_base::sptr make(ctor_args_t const& args){
- return dboard_base::sptr(new basic_tx(args));
- }
- basic_tx(ctor_args_t const& args);
- ~basic_tx(void);
-
- void tx_get(const wax::obj &key, wax::obj &val);
- void tx_set(const wax::obj &key, const wax::obj &val);
+void usrp1e_impl::mboard_init(void){
+ _mboard_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp1e_impl::mboard_get, this, _1, _2),
+ boost::bind(&usrp1e_impl::mboard_set, this, _1, _2)
+ );
+}
-};
+/***********************************************************************
+ * Mboard Get
+ **********************************************************************/
+void usrp1e_impl::mboard_get(const wax::obj &, wax::obj &){
+
+}
-#endif /* INCLUDED_LOCAL_DBOARDS_HPP */
+/***********************************************************************
+ * Mboard Set
+ **********************************************************************/
+void usrp1e_impl::mboard_set(const wax::obj &, const wax::obj &){
+
+}
diff --git a/host/lib/usrp/usrp1e/usrp1e_impl.cpp b/host/lib/usrp/usrp1e/usrp1e_impl.cpp
new file mode 100644
index 000000000..8230cc8e4
--- /dev/null
+++ b/host/lib/usrp/usrp1e/usrp1e_impl.cpp
@@ -0,0 +1,178 @@
+//
+// 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.hpp>
+#include <boost/format.hpp>
+#include <boost/filesystem.hpp>
+#include "usrp1e_impl.hpp"
+#include <fcntl.h> //open
+#include <sys/ioctl.h> //ioctl
+
+using namespace uhd;
+using namespace uhd::usrp;
+namespace fs = boost::filesystem;
+
+STATIC_BLOCK(register_usrp1e_device){
+ device::register_device(&usrp1e::discover, &usrp1e::make);
+}
+
+/***********************************************************************
+ * Helper Functions
+ **********************************************************************/
+static std::string abs_path(const std::string &file_path){
+ return fs::system_complete(fs::path(file_path)).file_string();
+}
+
+/***********************************************************************
+ * Discovery
+ **********************************************************************/
+device_addrs_t usrp1e::discover(const device_addr_t &device_addr){
+ device_addrs_t usrp1e_addrs;
+
+ //if a node was provided, use it and only it
+ if (device_addr.has_key("node")){
+ if (not fs::exists(device_addr["node"])) return usrp1e_addrs;
+ device_addr_t new_addr;
+ new_addr["name"] = "USRP1E";
+ new_addr["node"] = abs_path(device_addr["node"]);
+ usrp1e_addrs.push_back(new_addr);
+ }
+
+ //otherwise look for a few nodes at small indexes
+ else{
+ for(size_t i = 0; i < 5; i++){
+ std::string node = str(boost::format("/dev/usrp1_e%d") % i);
+ if (not fs::exists(node)) continue;
+ device_addr_t new_addr;
+ new_addr["name"] = "USRP1E";
+ new_addr["node"] = abs_path(node);
+ usrp1e_addrs.push_back(new_addr);
+ }
+ }
+
+ return usrp1e_addrs;
+}
+
+/***********************************************************************
+ * Make
+ **********************************************************************/
+device::sptr usrp1e::make(const device_addr_t &device_addr){
+ return sptr(new usrp1e_impl(device_addr["node"]));
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+usrp1e_impl::usrp1e_impl(const std::string &node){
+ //open the device node and check file descriptor
+ if ((_node_fd = ::open(node.c_str(), O_RDWR)) < 0){
+ throw std::runtime_error(str(
+ boost::format("Failed to open %s") % node
+ ));
+ }
+
+ //initialize the mboard
+ mboard_init();
+
+ //initialize the dboards
+ dboard_init();
+
+ //initialize the dsps
+ rx_ddc_init();
+ tx_duc_init();
+}
+
+usrp1e_impl::~usrp1e_impl(void){
+ //close the device node file descriptor
+ ::close(_node_fd);
+}
+
+/***********************************************************************
+ * Misc Methods
+ **********************************************************************/
+void usrp1e_impl::ioctl(int request, void *mem){
+ if (::ioctl(_node_fd, request, mem) < 0){
+ throw std::runtime_error(str(
+ boost::format("ioctl failed with request %d") % request
+ ));
+ }
+}
+
+/***********************************************************************
+ * Device Get
+ **********************************************************************/
+void usrp1e_impl::get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<device_prop_t>()){
+ case DEVICE_PROP_NAME:
+ val = std::string("usrp1e device");
+ return;
+
+ case DEVICE_PROP_MBOARD:
+ ASSERT_THROW(name == "");
+ val = _mboard_proxy->get_link();
+ return;
+
+ case DEVICE_PROP_MBOARD_NAMES:
+ 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;
+
+ }
+}
+
+/***********************************************************************
+ * Device Set
+ **********************************************************************/
+void usrp1e_impl::set(const wax::obj &, const wax::obj &){
+ throw std::runtime_error("Cannot set in usrp1e device");
+}
+
+/***********************************************************************
+ * Device IO (TODO)
+ **********************************************************************/
+size_t usrp1e_impl::send(
+ const boost::asio::const_buffer &,
+ const uhd::tx_metadata_t &,
+ const std::string &type
+){
+ if (type != "16sc"){
+ throw std::runtime_error(str(boost::format("usrp1e send: cannot handle type \"%s\"") % type));
+ }
+ return 0;
+}
+
+size_t usrp1e_impl::recv(
+ const boost::asio::mutable_buffer &,
+ uhd::rx_metadata_t &,
+ const std::string &type
+){
+ if (type != "16sc"){
+ throw std::runtime_error(str(boost::format("usrp1e recv: cannot handle type \"%s\"") % type));
+ }
+ return 0;
+}
diff --git a/host/lib/usrp/usrp1e/usrp1e_impl.hpp b/host/lib/usrp/usrp1e/usrp1e_impl.hpp
new file mode 100644
index 000000000..c199a0465
--- /dev/null
+++ b/host/lib/usrp/usrp1e/usrp1e_impl.hpp
@@ -0,0 +1,135 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/usrp/usrp1e.hpp>
+#include <uhd/usrp/dboard_manager.hpp>
+
+#ifndef INCLUDED_USRP1E_IMPL_HPP
+#define INCLUDED_USRP1E_IMPL_HPP
+
+class usrp1e_impl; // dummy class declaration
+
+/*!
+ * Make a usrp1e dboard interface.
+ * \param impl a pointer to the usrp1e impl object
+ * \return a sptr to a new dboard interface
+ */
+uhd::usrp::dboard_interface::sptr make_usrp1e_dboard_interface(usrp1e_impl *impl);
+
+/*!
+ * Simple wax obj proxy class:
+ * Provides a wax obj interface for a set and a get function.
+ * This allows us to create nested properties structures
+ * while maintaining flattened code within the implementation.
+ */
+class wax_obj_proxy : public wax::obj{
+public:
+ typedef boost::function<void(const wax::obj &, wax::obj &)> get_t;
+ typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t;
+ typedef boost::shared_ptr<wax_obj_proxy> sptr;
+
+ static sptr make(const get_t &get, const set_t &set){
+ return sptr(new wax_obj_proxy(get, set));
+ }
+
+ ~wax_obj_proxy(void){
+ /* NOP */
+ }
+
+private:
+ get_t _get;
+ set_t _set;
+
+ wax_obj_proxy(const get_t &get, const set_t &set){
+ _get = get;
+ _set = set;
+ };
+
+ void get(const wax::obj &key, wax::obj &val){
+ return _get(key, val);
+ }
+
+ void set(const wax::obj &key, const wax::obj &val){
+ return _set(key, val);
+ }
+};
+
+/*!
+ * USRP1E implementation guts:
+ * The implementation details are encapsulated here.
+ * Handles properties on the mboard, dboard, dsps...
+ */
+class usrp1e_impl : public uhd::device{
+public:
+ //structors
+ usrp1e_impl(const std::string &node);
+ ~usrp1e_impl(void);
+
+ //the io interface
+ size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const std::string &);
+ size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const std::string &);
+
+ /*!
+ * Perform an ioctl call on the device node file descriptor.
+ * This will throw when the internal ioctl call fails.
+ * \param request the control word
+ * \param mem pointer to some memory
+ */
+ void ioctl(int request, void *mem);
+
+private:
+ static const size_t _max_num_samples = 2048/sizeof(boost::uint32_t);
+ int _node_fd;
+
+ //device functions and settings
+ void get(const wax::obj &, wax::obj &);
+ void set(const wax::obj &, const wax::obj &);
+
+ //mboard functions and settings
+ void mboard_init(void);
+ void mboard_get(const wax::obj &, wax::obj &);
+ void mboard_set(const wax::obj &, const wax::obj &);
+ wax_obj_proxy::sptr _mboard_proxy;
+
+ //xx dboard functions and settings
+ void dboard_init(void);
+ uhd::usrp::dboard_manager::sptr _dboard_manager;
+
+ //rx dboard functions and settings
+ void rx_dboard_get(const wax::obj &, wax::obj &);
+ void rx_dboard_set(const wax::obj &, const wax::obj &);
+ wax_obj_proxy::sptr _rx_dboard_proxy;
+
+ //tx dboard functions and settings
+ void tx_dboard_get(const wax::obj &, wax::obj &);
+ void tx_dboard_set(const wax::obj &, const wax::obj &);
+ wax_obj_proxy::sptr _tx_dboard_proxy;
+
+ //rx ddc functions and settings
+ void rx_ddc_init(void);
+ void rx_ddc_get(const wax::obj &, wax::obj &);
+ void rx_ddc_set(const wax::obj &, const wax::obj &);
+ wax_obj_proxy::sptr _rx_ddc_proxy;
+
+ //tx duc functions and settings
+ void tx_duc_init(void);
+ void tx_duc_get(const wax::obj &, wax::obj &);
+ void tx_duc_set(const wax::obj &, const wax::obj &);
+ wax_obj_proxy::sptr _tx_duc_proxy;
+};
+
+#endif /* INCLUDED_USRP1E_IMPL_HPP */
diff --git a/host/lib/usrp/dboard_id.cpp b/host/lib/usrp/usrp1e/usrp1e_none.cpp
index d2ef7cd7d..ac0b12a75 100644
--- a/host/lib/usrp/dboard_id.cpp
+++ b/host/lib/usrp/usrp1e/usrp1e_none.cpp
@@ -15,20 +15,24 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <uhd/usrp/dboard_id.hpp>
-#include <boost/format.hpp>
-#include <uhd/dict.hpp>
+#include <uhd/usrp/usrp1e.hpp>
+using namespace uhd;
using namespace uhd::usrp;
-std::string dboard_id::to_string(const dboard_id_t &id){
- //map the dboard ids to string representations
- uhd::dict<dboard_id_t, std::string> id_to_str;
- id_to_str[ID_NONE] = "none";
- id_to_str[ID_BASIC_TX] = "basic tx";
- id_to_str[ID_BASIC_RX] = "basic rx";
+/*!
+ * This file defines the usrp1e discover and make functions
+ * when the required kernel module headers are not present.
+ */
- //get the string representation
- std::string name = (id_to_str.has_key(id))? id_to_str[id] : "unknown";
- return str(boost::format("%s (0x%.4x)") % name % id);
+device_addrs_t usrp1e::discover(const device_addr_t &){
+ return device_addrs_t(); //return empty list
+}
+
+device::sptr usrp1e::make(const device_addr_t &){
+ throw std::runtime_error("this build has no usrp1e support");
+}
+
+void usrp1e::load_fpga(const std::string &){
+ throw std::runtime_error("this build has no usrp1e support");
}
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
index 32c64f541..66e02d469 100644
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ b/host/lib/usrp/usrp2/dboard_impl.cpp
@@ -16,8 +16,8 @@
//
#include <uhd/utils.hpp>
+#include <boost/format.hpp>
#include "usrp2_impl.hpp"
-#include "dboard_interface.hpp"
using namespace uhd;
using namespace uhd::usrp;
@@ -31,35 +31,68 @@ void usrp2_impl::dboard_init(void){
out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_DBOARD_IDS_BRO);
usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THESE_ARE_MY_DBOARD_IDS_DUDE);
- std::cout << boost::format("rx id 0x%.2x, tx id 0x%.2x")
- % ntohs(in_data.data.dboard_ids.rx_id)
- % ntohs(in_data.data.dboard_ids.tx_id) << std::endl;
- //extract the dboard ids an convert them to enums
- dboard_id_t rx_dboard_id = static_cast<dboard_id_t>(
- ntohs(in_data.data.dboard_ids.rx_id)
- );
- dboard_id_t tx_dboard_id = static_cast<dboard_id_t>(
- ntohs(in_data.data.dboard_ids.tx_id)
- );
+ //extract the dboard ids an convert them
+ dboard_id_t rx_dboard_id = ntohs(in_data.data.dboard_ids.rx_id);
+ dboard_id_t tx_dboard_id = ntohs(in_data.data.dboard_ids.tx_id);
//create a new dboard interface and manager
dboard_interface::sptr _dboard_interface(
- new usrp2_dboard_interface(this)
+ make_usrp2_dboard_interface(this)
);
- dboard_manager::sptr _dboard_manager = dboard_manager::make(
+ _dboard_manager = dboard_manager::make(
rx_dboard_id, tx_dboard_id, _dboard_interface
);
//load dboards
- _rx_dboards[""] = wax_obj_proxy(
+ _rx_dboards[""] = wax_obj_proxy::make(
boost::bind(&usrp2_impl::rx_dboard_get, this, _1, _2),
boost::bind(&usrp2_impl::rx_dboard_set, this, _1, _2)
);
- _tx_dboards[""] = wax_obj_proxy(
+ _tx_dboards[""] = wax_obj_proxy::make(
boost::bind(&usrp2_impl::tx_dboard_get, this, _1, _2),
boost::bind(&usrp2_impl::tx_dboard_set, this, _1, _2)
);
+
+ //init the subdevs in use (use the first subdevice)
+ _rx_subdevs_in_use = prop_names_t(1, _dboard_manager->get_rx_subdev_names().at(0));
+ _tx_subdevs_in_use = prop_names_t(1, _dboard_manager->get_tx_subdev_names().at(0));
+ update_mux_config();
+}
+
+void usrp2_impl::update_mux_config(void){
+ //calculate the rx mux
+ boost::uint32_t rx_mux = 0;
+ ASSERT_THROW(_rx_subdevs_in_use.size() == 1);
+ wax::obj rx_subdev = _dboard_manager->get_rx_subdev(_rx_subdevs_in_use.at(0));
+ std::cout << "Using: " << rx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl;
+ if (rx_subdev[SUBDEV_PROP_QUADRATURE].as<bool>()){
+ rx_mux = (0x01 << 2) | (0x00 << 0); //Q=ADC1, I=ADC0
+ }else{
+ rx_mux = 0x00; //ADC0
+ }
+ if (rx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>()){
+ rx_mux = (((rx_mux >> 0) & 0x3) << 2) | (((rx_mux >> 2) & 0x3) << 0);
+ }
+
+ //calculate the tx mux
+ boost::uint32_t tx_mux = 0x10;
+ ASSERT_THROW(_tx_subdevs_in_use.size() == 1);
+ wax::obj tx_subdev = _dboard_manager->get_tx_subdev(_tx_subdevs_in_use.at(0));
+ std::cout << "Using: " << tx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl;
+ if (tx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>()){
+ tx_mux = (((tx_mux >> 0) & 0x1) << 1) | (((tx_mux >> 1) & 0x1) << 0);
+ }
+
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_UPDATE_THOSE_MUX_SETTINGS_BRO);
+ out_data.data.mux_args.rx_mux = htonl(rx_mux);
+ out_data.data.mux_args.tx_mux = htonl(tx_mux);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_UPDATED_THE_MUX_SETTINGS_DUDE);
}
/***********************************************************************
@@ -70,7 +103,7 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
boost::tie(key, name) = extract_named_prop(key_);
//handle the get request conditioned on the key
- switch(wax::cast<dboard_prop_t>(key)){
+ switch(key.as<dboard_prop_t>()){
case DBOARD_PROP_NAME:
val = std::string("usrp2 dboard (rx unit)");
return;
@@ -83,12 +116,22 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_manager->get_rx_subdev_names();
return;
- case DBOARD_PROP_CODEC:
- throw std::runtime_error("unhandled prop in usrp2 dboard");
+ case DBOARD_PROP_USED_SUBDEVS:
+ val = _rx_subdevs_in_use;
+ return;
+
+ //case DBOARD_PROP_CODEC:
+ // throw std::runtime_error("unhandled prop in usrp2 dboard");
}
}
-void usrp2_impl::rx_dboard_set(const wax::obj &, const wax::obj &){
+void usrp2_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){
+ if (key.as<dboard_prop_t>() == DBOARD_PROP_USED_SUBDEVS){
+ _rx_subdevs_in_use = val.as<prop_names_t>();
+ update_mux_config(); //if the val is bad, this will throw
+ return;
+ }
+
throw std::runtime_error("Cannot set on usrp2 dboard");
}
@@ -100,7 +143,7 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
boost::tie(key, name) = extract_named_prop(key_);
//handle the get request conditioned on the key
- switch(wax::cast<dboard_prop_t>(key)){
+ switch(key.as<dboard_prop_t>()){
case DBOARD_PROP_NAME:
val = std::string("usrp2 dboard (tx unit)");
return;
@@ -113,11 +156,21 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_manager->get_tx_subdev_names();
return;
- case DBOARD_PROP_CODEC:
- throw std::runtime_error("unhandled prop in usrp2 dboard");
+ case DBOARD_PROP_USED_SUBDEVS:
+ val = _tx_subdevs_in_use;
+ return;
+
+ //case DBOARD_PROP_CODEC:
+ // throw std::runtime_error("unhandled prop in usrp2 dboard");
}
}
-void usrp2_impl::tx_dboard_set(const wax::obj &, const wax::obj &){
+void usrp2_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){
+ if (key.as<dboard_prop_t>() == DBOARD_PROP_USED_SUBDEVS){
+ _tx_subdevs_in_use = val.as<prop_names_t>();
+ update_mux_config(); //if the val is bad, this will throw
+ return;
+ }
+
throw std::runtime_error("Cannot set on usrp2 dboard");
}
diff --git a/host/lib/usrp/usrp2/dboard_interface.cpp b/host/lib/usrp/usrp2/dboard_interface.cpp
index f12b101f3..d20465147 100644
--- a/host/lib/usrp/usrp2/dboard_interface.cpp
+++ b/host/lib/usrp/usrp2/dboard_interface.cpp
@@ -16,11 +16,48 @@
//
#include <uhd/utils.hpp>
-#include "dboard_interface.hpp"
#include "usrp2_impl.hpp"
using namespace uhd::usrp;
+class usrp2_dboard_interface : public dboard_interface{
+public:
+ usrp2_dboard_interface(usrp2_impl *impl);
+ ~usrp2_dboard_interface(void);
+
+ void write_aux_dac(unit_type_t, int, int);
+ int read_aux_adc(unit_type_t, int);
+
+ void set_atr_reg(gpio_bank_t, boost::uint16_t, boost::uint16_t, boost::uint16_t);
+ void set_gpio_ddr(gpio_bank_t, boost::uint16_t, boost::uint16_t);
+ void write_gpio(gpio_bank_t, boost::uint16_t, boost::uint16_t);
+ boost::uint16_t read_gpio(gpio_bank_t);
+
+ void write_i2c(int, const byte_vector_t &);
+ byte_vector_t read_i2c(int, size_t);
+
+ double get_rx_clock_rate(void);
+ double get_tx_clock_rate(void);
+
+private:
+ byte_vector_t transact_spi(
+ spi_dev_t dev,
+ spi_latch_t latch,
+ spi_push_t push,
+ const byte_vector_t &buf,
+ bool readback
+ );
+
+ usrp2_impl *_impl;
+};
+
+/***********************************************************************
+ * Make Function
+ **********************************************************************/
+dboard_interface::sptr make_usrp2_dboard_interface(usrp2_impl *impl){
+ return dboard_interface::sptr(new usrp2_dboard_interface(impl));
+}
+
/***********************************************************************
* Structors
**********************************************************************/
@@ -52,7 +89,7 @@ double usrp2_dboard_interface::get_tx_clock_rate(void){
* \param bank the dboard interface gpio bank enum
* \return an over the wire representation
*/
-static uint8_t gpio_bank_to_otw(dboard_interface::gpio_bank_t bank){
+static boost::uint8_t gpio_bank_to_otw(dboard_interface::gpio_bank_t bank){
switch(bank){
case uhd::usrp::dboard_interface::GPIO_TX_BANK: return USRP2_DIR_TX;
case uhd::usrp::dboard_interface::GPIO_RX_BANK: return USRP2_DIR_RX;
@@ -60,7 +97,7 @@ static uint8_t gpio_bank_to_otw(dboard_interface::gpio_bank_t bank){
throw std::invalid_argument("unknown gpio bank type");
}
-void usrp2_dboard_interface::set_gpio_ddr(gpio_bank_t bank, uint16_t value, uint16_t mask){
+void usrp2_dboard_interface::set_gpio_ddr(gpio_bank_t bank, boost::uint16_t value, boost::uint16_t mask){
//setup the out data
usrp2_ctrl_data_t out_data;
out_data.id = htonl(USRP2_CTRL_ID_USE_THESE_GPIO_DDR_SETTINGS_BRO);
@@ -73,7 +110,7 @@ void usrp2_dboard_interface::set_gpio_ddr(gpio_bank_t bank, uint16_t value, uint
ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THE_GPIO_DDR_SETTINGS_DUDE);
}
-void usrp2_dboard_interface::write_gpio(gpio_bank_t bank, uint16_t value, uint16_t mask){
+void usrp2_dboard_interface::write_gpio(gpio_bank_t bank, boost::uint16_t value, boost::uint16_t mask){
//setup the out data
usrp2_ctrl_data_t out_data;
out_data.id = htonl(USRP2_CTRL_ID_SET_YOUR_GPIO_PIN_OUTS_BRO);
@@ -86,7 +123,7 @@ void usrp2_dboard_interface::write_gpio(gpio_bank_t bank, uint16_t value, uint16
ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_I_SET_THE_GPIO_PIN_OUTS_DUDE);
}
-uint16_t usrp2_dboard_interface::read_gpio(gpio_bank_t bank){
+boost::uint16_t usrp2_dboard_interface::read_gpio(gpio_bank_t bank){
//setup the out data
usrp2_ctrl_data_t out_data;
out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_GPIO_PIN_VALS_BRO);
@@ -98,7 +135,7 @@ uint16_t usrp2_dboard_interface::read_gpio(gpio_bank_t bank){
return ntohs(in_data.data.gpio_config.value);
}
-void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, uint16_t tx_value, uint16_t rx_value, uint16_t mask){
+void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, boost::uint16_t tx_value, boost::uint16_t rx_value, boost::uint16_t mask){
//setup the out data
usrp2_ctrl_data_t out_data;
out_data.id = htonl(USRP2_CTRL_ID_USE_THESE_ATR_SETTINGS_BRO);
@@ -121,7 +158,7 @@ void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, uint16_t tx_value, ui
* \param dev the dboard interface spi dev enum
* \return an over the wire representation
*/
-static uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){
+static boost::uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){
switch(dev){
case uhd::usrp::dboard_interface::SPI_TX_DEV: return USRP2_DIR_TX;
case uhd::usrp::dboard_interface::SPI_RX_DEV: return USRP2_DIR_RX;
@@ -135,7 +172,7 @@ static uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){
* \param latch the dboard interface spi latch enum
* \return an over the wire representation
*/
-static uint8_t spi_latch_to_otw(dboard_interface::spi_latch_t latch){
+static boost::uint8_t spi_latch_to_otw(dboard_interface::spi_latch_t latch){
switch(latch){
case uhd::usrp::dboard_interface::SPI_LATCH_RISE: return USRP2_CLK_EDGE_RISE;
case uhd::usrp::dboard_interface::SPI_LATCH_FALL: return USRP2_CLK_EDGE_FALL;
@@ -149,7 +186,7 @@ static uint8_t spi_latch_to_otw(dboard_interface::spi_latch_t latch){
* \param push the dboard interface spi push enum
* \return an over the wire representation
*/
-static uint8_t spi_push_to_otw(dboard_interface::spi_push_t push){
+static boost::uint8_t spi_push_to_otw(dboard_interface::spi_push_t push){
switch(push){
case uhd::usrp::dboard_interface::SPI_PUSH_RISE: return USRP2_CLK_EDGE_RISE;
case uhd::usrp::dboard_interface::SPI_PUSH_FALL: return USRP2_CLK_EDGE_FALL;
@@ -249,7 +286,7 @@ dboard_interface::byte_vector_t usrp2_dboard_interface::read_i2c(int i2c_addr, s
* \param unit the dboard interface unit type enum
* \return an over the wire representation
*/
-static uint8_t spi_dev_to_otw(dboard_interface::unit_type_t unit){
+static boost::uint8_t spi_dev_to_otw(dboard_interface::unit_type_t unit){
switch(unit){
case uhd::usrp::dboard_interface::UNIT_TYPE_TX: return USRP2_DIR_TX;
case uhd::usrp::dboard_interface::UNIT_TYPE_RX: return USRP2_DIR_RX;
@@ -263,7 +300,7 @@ void usrp2_dboard_interface::write_aux_dac(dboard_interface::unit_type_t unit, i
out_data.id = htonl(USRP2_CTRL_ID_WRITE_THIS_TO_THE_AUX_DAC_BRO);
out_data.data.aux_args.dir = spi_dev_to_otw(unit);
out_data.data.aux_args.which = which;
- out_data.data.aux_args.dir = htonl(value);
+ out_data.data.aux_args.value = htonl(value);
//send and recv
usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data);
diff --git a/host/lib/usrp/usrp2/dboard_interface.hpp b/host/lib/usrp/usrp2/dboard_interface.hpp
deleted file mode 100644
index a06359e5e..000000000
--- a/host/lib/usrp/usrp2/dboard_interface.hpp
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#include <uhd/usrp/dboard_interface.hpp>
-
-#ifndef INCLUDED_DBOARD_INTERFACE_HPP
-#define INCLUDED_DBOARD_INTERFACE_HPP
-
-class usrp2_impl; //dummy class declaration
-
-class usrp2_dboard_interface : public uhd::usrp::dboard_interface{
-public:
- usrp2_dboard_interface(usrp2_impl *impl);
-
- ~usrp2_dboard_interface(void);
-
- void write_aux_dac(unit_type_t, int, int);
-
- int read_aux_adc(unit_type_t, int);
-
- void set_atr_reg(gpio_bank_t, uint16_t, uint16_t, uint16_t);
-
- void set_gpio_ddr(gpio_bank_t, uint16_t, uint16_t);
-
- void write_gpio(gpio_bank_t, uint16_t, uint16_t);
-
- uint16_t read_gpio(gpio_bank_t);
-
- void write_i2c(int, const byte_vector_t &);
-
- byte_vector_t read_i2c(int, size_t);
-
- double get_rx_clock_rate(void);
-
- double get_tx_clock_rate(void);
-
-private:
- byte_vector_t transact_spi(
- spi_dev_t dev,
- spi_latch_t latch,
- spi_push_t push,
- const byte_vector_t &buf,
- bool readback
- );
-
- usrp2_impl *_impl;
-};
-
-#endif /* INCLUDED_DBOARD_INTERFACE_HPP */
diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp
index 22c00d99a..34cce0afb 100644
--- a/host/lib/usrp/usrp2/dsp_impl.cpp
+++ b/host/lib/usrp/usrp2/dsp_impl.cpp
@@ -16,19 +16,30 @@
//
#include <uhd/utils.hpp>
+#include <boost/format.hpp>
#include <boost/assign/list_of.hpp>
+#include <boost/math/special_functions/round.hpp>
#include "usrp2_impl.hpp"
using namespace uhd;
+static const size_t default_decim = 16;
+static const size_t default_interp = 16;
+
+#define rint boost::math::iround
+
+template <class T> T log2(T num){
+ return std::log(num)/std::log(T(2));
+}
+
/***********************************************************************
* DDC Helper Methods
**********************************************************************/
-static uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t clock_freq){
- double scale_factor = pow(2.0, 32);
+static boost::uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t clock_freq){
+ double scale_factor = std::pow(2.0, 32);
//calculate the freq register word
- uint32_t freq_word = rint((freq / clock_freq) * scale_factor);
+ boost::uint32_t freq_word = rint((freq / clock_freq) * scale_factor);
//update the actual frequency
freq = (double(freq_word) / scale_factor) * clock_freq;
@@ -36,15 +47,19 @@ static uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t
return freq_word;
}
+static boost::uint32_t calculate_iq_scale_word(boost::int16_t i, boost::int16_t q){
+ return (boost::uint16_t(i) << 16) | (boost::uint16_t(q) << 0);
+}
+
void usrp2_impl::init_ddc_config(void){
//create the ddc in the rx dsp dict
- _rx_dsps["ddc0"] = wax_obj_proxy(
+ _rx_dsps["ddc0"] = wax_obj_proxy::make(
boost::bind(&usrp2_impl::ddc_get, this, _1, _2),
boost::bind(&usrp2_impl::ddc_set, this, _1, _2)
);
//initial config and update
- _ddc_decim = 16;
+ _ddc_decim = default_decim;
_ddc_freq = 0;
update_ddc_config();
@@ -61,6 +76,10 @@ void usrp2_impl::update_ddc_config(void){
calculate_freq_word_and_update_actual_freq(_ddc_freq, get_master_clock_freq())
);
out_data.data.ddc_args.decim = htonl(_ddc_decim);
+ static const boost::int16_t default_rx_scale_iq = 1024;
+ out_data.data.ddc_args.scale_iq = htonl(
+ calculate_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq)
+ );
//send and recv
usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
@@ -74,6 +93,7 @@ void usrp2_impl::update_ddc_enabled(void){
out_data.data.streaming.enabled = (_ddc_enabled)? 1 : 0;
out_data.data.streaming.secs = htonl(_ddc_stream_at.secs);
out_data.data.streaming.ticks = htonl(_ddc_stream_at.ticks);
+ out_data.data.streaming.samples = htonl(_max_rx_samples_per_packet);
//send and recv
usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
@@ -89,7 +109,7 @@ void usrp2_impl::update_ddc_enabled(void){
void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){
//handle the case where the key is an expected dsp property
if (key.type() == typeid(dsp_prop_t)){
- switch(wax::cast<dsp_prop_t>(key)){
+ switch(key.as<dsp_prop_t>()){
case DSP_PROP_NAME:
val = std::string("usrp2 ddc0");
return;
@@ -98,7 +118,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){
prop_names_t others = boost::assign::list_of
("rate")
("decim")
- ("decim_rates")
+ ("decims")
("freq")
("enabled")
("stream_at")
@@ -110,7 +130,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){
}
//handle string-based properties specific to this dsp
- std::string key_name = wax::cast<std::string>(key);
+ std::string key_name = key.as<std::string>();
if (key_name == "rate"){
val = get_master_clock_freq();
return;
@@ -119,7 +139,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){
val = _ddc_decim;
return;
}
- else if (key_name == "decim_rates"){
+ else if (key_name == "decims"){
val = _allowed_decim_and_interp_rates;
return;
}
@@ -139,20 +159,19 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){
void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){
//handle string-based properties specific to this dsp
- std::string key_name = wax::cast<std::string>(key);
+ std::string key_name = key.as<std::string>();
if (key_name == "decim"){
- size_t new_decim = wax::cast<size_t>(val);
- ASSERT_THROW(std::has(
- _allowed_decim_and_interp_rates.begin(),
- _allowed_decim_and_interp_rates.end(),
- new_decim
- ));
+ size_t new_decim = val.as<size_t>();
+ assert_has(
+ _allowed_decim_and_interp_rates,
+ new_decim, "usrp2 decimation"
+ );
_ddc_decim = new_decim; //shadow
update_ddc_config();
return;
}
else if (key_name == "freq"){
- freq_t new_freq = wax::cast<freq_t>(val);
+ freq_t new_freq = val.as<freq_t>();
ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0);
ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0);
_ddc_freq = new_freq; //shadow
@@ -160,13 +179,13 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){
return;
}
else if (key_name == "enabled"){
- bool new_enabled = wax::cast<bool>(val);
+ bool new_enabled = val.as<bool>();
_ddc_enabled = new_enabled; //shadow
update_ddc_enabled();
return;
}
else if (key_name == "stream_at"){
- time_spec_t new_stream_at = wax::cast<time_spec_t>(val);
+ time_spec_t new_stream_at = val.as<time_spec_t>();
_ddc_stream_at = new_stream_at; //shadow
//update_ddc_enabled(); //dont update from here
return;
@@ -182,13 +201,13 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){
**********************************************************************/
void usrp2_impl::init_duc_config(void){
//create the duc in the tx dsp dict
- _tx_dsps["duc0"] = wax_obj_proxy(
+ _tx_dsps["duc0"] = wax_obj_proxy::make(
boost::bind(&usrp2_impl::duc_get, this, _1, _2),
boost::bind(&usrp2_impl::duc_set, this, _1, _2)
);
//initial config and update
- _duc_interp = 16;
+ _duc_interp = default_interp;
_duc_freq = 0;
update_duc_config();
}
@@ -199,8 +218,8 @@ void usrp2_impl::update_duc_config(void){
while(tmp_interp > 128) tmp_interp /= 2;
// Calculate closest multiplier constant to reverse gain absent scale multipliers
- size_t interp_cubed = pow(tmp_interp, 3);
- size_t scale = rint((4096*pow(2, ceil(log2(interp_cubed))))/(1.65*interp_cubed));
+ double interp_cubed = std::pow(double(tmp_interp), 3);
+ boost::int16_t scale = rint((4096*std::pow(2, ceil(log2(interp_cubed))))/(1.65*interp_cubed));
//setup the out data
usrp2_ctrl_data_t out_data;
@@ -209,7 +228,9 @@ void usrp2_impl::update_duc_config(void){
calculate_freq_word_and_update_actual_freq(_duc_freq, get_master_clock_freq())
);
out_data.data.duc_args.interp = htonl(_duc_interp);
- out_data.data.duc_args.scale_iq = htonl(scale);
+ out_data.data.duc_args.scale_iq = htonl(
+ calculate_iq_scale_word(scale, scale)
+ );
//send and recv
usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
@@ -222,7 +243,7 @@ void usrp2_impl::update_duc_config(void){
void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){
//handle the case where the key is an expected dsp property
if (key.type() == typeid(dsp_prop_t)){
- switch(wax::cast<dsp_prop_t>(key)){
+ switch(key.as<dsp_prop_t>()){
case DSP_PROP_NAME:
val = std::string("usrp2 duc0");
return;
@@ -231,7 +252,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){
prop_names_t others = boost::assign::list_of
("rate")
("interp")
- ("interp_rates")
+ ("interps")
("freq")
;
val = others;
@@ -241,7 +262,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){
}
//handle string-based properties specific to this dsp
- std::string key_name = wax::cast<std::string>(key);
+ std::string key_name = key.as<std::string>();
if (key_name == "rate"){
val = get_master_clock_freq();
return;
@@ -250,7 +271,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){
val = _duc_interp;
return;
}
- else if (key_name == "interp_rates"){
+ else if (key_name == "interps"){
val = _allowed_decim_and_interp_rates;
return;
}
@@ -266,20 +287,19 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){
void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){
//handle string-based properties specific to this dsp
- std::string key_name = wax::cast<std::string>(key);
+ std::string key_name = key.as<std::string>();
if (key_name == "interp"){
- size_t new_interp = wax::cast<size_t>(val);
- ASSERT_THROW(std::has(
- _allowed_decim_and_interp_rates.begin(),
- _allowed_decim_and_interp_rates.end(),
- new_interp
- ));
+ size_t new_interp = val.as<size_t>();
+ assert_has(
+ _allowed_decim_and_interp_rates,
+ new_interp, "usrp2 interpolation"
+ );
_duc_interp = new_interp; //shadow
update_duc_config();
return;
}
else if (key_name == "freq"){
- freq_t new_freq = wax::cast<freq_t>(val);
+ freq_t new_freq = val.as<freq_t>();
ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0);
ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0);
_duc_freq = new_freq; //shadow
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index 3def8ddaa..7fcae6fb2 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -24,9 +24,18 @@
* Therefore, this header may only contain valid C code.
*/
#ifdef __cplusplus
+#include <boost/cstdint.hpp>
+#define _SINS_ boost:://stdint namespace when in c++
extern "C" {
+#else
+#include <stdint.h>
+#define _SINS_
#endif
+// size of the vrt header and trailer to the host
+#define USRP2_HOST_RX_VRT_HEADER_WORDS32 5
+#define USRP2_HOST_RX_VRT_TRAILER_WORDS32 1 //FIXME fpga sets wrong header size when no trailer present
+
// udp ports for the usrp2 communication
// Dynamic and/or private ports: 49152-65535
#define USRP2_UDP_CTRL_PORT 49152
@@ -87,6 +96,12 @@ typedef enum{
USRP2_CTRL_ID_SETUP_THIS_DUC_FOR_ME_BRO,
USRP2_CTRL_ID_TOTALLY_SETUP_THE_DUC_DUDE,
+ USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO,
+ USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE,
+
+ USRP2_CTRL_ID_UPDATE_THOSE_MUX_SETTINGS_BRO,
+ USRP2_CTRL_ID_UPDATED_THE_MUX_SETTINGS_DUDE,
+
USRP2_CTRL_ID_PEACE_OUT
} usrp2_ctrl_id_t;
@@ -118,68 +133,79 @@ typedef enum{
} usrp2_clk_edge_t;
typedef struct{
- uint32_t id;
- uint32_t seq;
+ _SINS_ uint32_t id;
+ _SINS_ uint32_t seq;
union{
- uint32_t ip_addr;
- uint8_t mac_addr[6];
+ _SINS_ uint32_t ip_addr;
+ _SINS_ uint8_t mac_addr[6];
struct {
- uint16_t rx_id;
- uint16_t tx_id;
+ _SINS_ uint16_t rx_id;
+ _SINS_ uint16_t tx_id;
} dboard_ids;
struct {
- uint8_t pps_source;
- uint8_t pps_polarity;
- uint8_t ref_source;
- uint8_t _pad;
+ _SINS_ uint8_t pps_source;
+ _SINS_ uint8_t pps_polarity;
+ _SINS_ uint8_t ref_source;
+ _SINS_ uint8_t _pad;
} clock_config;
struct {
- uint8_t bank;
- uint8_t _pad[3];
- uint16_t value;
- uint16_t mask;
+ _SINS_ uint8_t bank;
+ _SINS_ uint8_t _pad[3];
+ _SINS_ uint16_t value;
+ _SINS_ uint16_t mask;
} gpio_config;
struct {
- uint8_t bank;
- uint8_t _pad[3];
- uint16_t tx_value;
- uint16_t rx_value;
- uint16_t mask;
+ _SINS_ uint8_t bank;
+ _SINS_ uint8_t _pad[3];
+ _SINS_ uint16_t tx_value;
+ _SINS_ uint16_t rx_value;
+ _SINS_ uint16_t mask;
} atr_config;
struct {
- uint8_t dev;
- uint8_t latch;
- uint8_t push;
- uint8_t readback;
- uint8_t bytes;
- uint8_t data[sizeof(uint32_t)];
+ _SINS_ uint8_t dev;
+ _SINS_ uint8_t latch;
+ _SINS_ uint8_t push;
+ _SINS_ uint8_t readback;
+ _SINS_ uint8_t bytes;
+ _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)];
} spi_args;
struct {
- uint8_t addr;
- uint8_t bytes;
- uint8_t data[sizeof(uint32_t)];
+ _SINS_ uint8_t addr;
+ _SINS_ uint8_t bytes;
+ _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)];
} i2c_args;
struct {
- uint8_t dir;
- uint8_t which;
- uint8_t _pad[2];
- uint32_t value;
+ _SINS_ uint8_t dir;
+ _SINS_ uint8_t which;
+ _SINS_ uint8_t _pad[2];
+ _SINS_ uint32_t value;
} aux_args;
struct {
- uint32_t freq_word;
- uint32_t decim;
+ _SINS_ uint32_t freq_word;
+ _SINS_ uint32_t decim;
+ _SINS_ uint32_t scale_iq;
} ddc_args;
struct {
- uint8_t enabled;
- uint8_t _pad[3];
- uint32_t secs;
- uint32_t ticks;
+ _SINS_ uint8_t enabled;
+ _SINS_ uint8_t _pad[3];
+ _SINS_ uint32_t secs;
+ _SINS_ uint32_t ticks;
+ _SINS_ uint32_t samples;
} streaming;
struct {
- uint32_t freq_word;
- uint32_t interp;
- uint32_t scale_iq;
+ _SINS_ uint32_t freq_word;
+ _SINS_ uint32_t interp;
+ _SINS_ uint32_t scale_iq;
} duc_args;
+ struct {
+ _SINS_ uint32_t secs;
+ _SINS_ uint32_t ticks;
+ _SINS_ uint8_t now;
+ } time_args;
+ struct {
+ _SINS_ uint32_t rx_mux;
+ _SINS_ uint32_t tx_mux;
+ } mux_args;
} data;
} usrp2_ctrl_data_t;
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
new file mode 100644
index 000000000..dc8eea243
--- /dev/null
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -0,0 +1,258 @@
+//
+// 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 <complex>
+#include <algorithm>
+#include <boost/format.hpp>
+#include "usrp2_impl.hpp"
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace uhd::transport;
+namespace asio = boost::asio;
+
+/***********************************************************************
+ * Constants
+ **********************************************************************/
+typedef std::complex<float> fc32_t;
+typedef std::complex<boost::int16_t> sc16_t;
+
+static const float shorts_per_float = float(1 << 15);
+static const float floats_per_short = float(1.0/shorts_per_float);
+
+/***********************************************************************
+ * Helper Functions
+ **********************************************************************/
+void usrp2_impl::io_init(void){
+ //initially empty copy buffer
+ _rx_copy_buff = asio::buffer("", 0);
+
+ //send a small data packet so the usrp2 knows the udp source port
+ boost::uint32_t zero_data = 0;
+ _data_transport->send(asio::buffer(&zero_data, sizeof(zero_data)));
+}
+
+#define unrolled_loop(__i, __len, __inst) {\
+ size_t __i = 0; \
+ while(__i < (__len & ~0x7)){ \
+ __inst; __i++; __inst; __i++; \
+ __inst; __i++; __inst; __i++; \
+ __inst; __i++; __inst; __i++; \
+ __inst; __i++; __inst; __i++; \
+ } \
+ while(__i < __len){ \
+ __inst; __i++;\
+ } \
+}
+
+// set a boolean flag that indicates the endianess
+#ifdef HAVE_BIG_ENDIAN
+static const bool is_big_endian = true;
+#else
+static const bool is_big_endian = false;
+#endif
+
+static inline void host_floats_to_usrp2_items(
+ boost::uint32_t *usrp2_items,
+ const fc32_t *host_floats,
+ size_t num_samps
+){
+ unrolled_loop(i, num_samps,{
+ boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float);
+ boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float);
+ usrp2_items[i] = htonl((real << 16) | (imag << 0));
+ });
+}
+
+static inline void usrp2_items_to_host_floats(
+ fc32_t *host_floats,
+ const boost::uint32_t *usrp2_items,
+ size_t num_samps
+){
+ unrolled_loop(i, num_samps,{
+ boost::uint32_t item = ntohl(usrp2_items[i]);
+ boost::int16_t real = boost::uint16_t(item >> 16);
+ boost::int16_t imag = boost::uint16_t(item >> 0);
+ host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short));
+ });
+}
+
+static inline void host_items_to_usrp2_items(
+ boost::uint32_t *usrp2_items,
+ const boost::uint32_t *host_items,
+ size_t num_samps
+){
+ if (is_big_endian){
+ std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t));
+ }
+ else{
+ unrolled_loop(i, num_samps, usrp2_items[i] = htonl(host_items[i]));
+ }
+}
+
+static inline void usrp2_items_to_host_items(
+ boost::uint32_t *host_items,
+ const boost::uint32_t *usrp2_items,
+ size_t num_samps
+){
+ if (is_big_endian){
+ std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t));
+ }
+ else{
+ unrolled_loop(i, num_samps, host_items[i] = ntohl(usrp2_items[i]));
+ }
+}
+
+/***********************************************************************
+ * Receive Raw Data
+ **********************************************************************/
+void usrp2_impl::recv_raw(rx_metadata_t &metadata){
+ //do a receive
+ _rx_smart_buff = _data_transport->recv();
+
+ //unpack the vrt header
+ size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/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 = asio::buffer_cast<const boost::uint32_t *>(_rx_smart_buff->get());
+ 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
+ );
+ }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)
+ );
+}
+
+/***********************************************************************
+ * Send Data
+ **********************************************************************/
+size_t usrp2_impl::send(
+ const asio::const_buffer &buff,
+ const tx_metadata_t &metadata,
+ const std::string &type
+){
+ boost::uint32_t tx_mem[_mtu/sizeof(boost::uint32_t)];
+ boost::uint32_t *items = tx_mem + vrt::max_header_words32; //offset for data
+ size_t num_samps = _max_tx_samples_per_packet;
+
+ //calculate the number of samples to be copied
+ //and copy the samples into the send buffer
+ if (type == "32fc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps);
+ host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps);
+ }
+ else if (type == "16sc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps);
+ host_items_to_usrp2_items(items, asio::buffer_cast<const boost::uint32_t*>(buff), num_samps);
+ }
+ else{
+ throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type));
+ }
+
+ boost::uint32_t vrt_hdr[vrt::max_header_words32];
+ 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
+ vrt_hdr, //output
+ num_header_words32, //output
+ num_samps, //input
+ num_packet_words32, //output
+ packet_count //input
+ );
+
+ //copy in the vrt header (yes we left space)
+ items -= num_header_words32;
+ std::memcpy(items, vrt_hdr, num_header_words32*sizeof(boost::uint32_t));
+
+ //send and return number of samples
+ _data_transport->send(asio::buffer(items, num_packet_words32*sizeof(boost::uint32_t)));
+ return num_samps;
+}
+
+/***********************************************************************
+ * Receive Data
+ **********************************************************************/
+size_t usrp2_impl::recv(
+ const asio::mutable_buffer &buff,
+ rx_metadata_t &metadata,
+ const std::string &type
+){
+ //perform a receive if no rx data is waiting to be copied
+ if (asio::buffer_size(_rx_copy_buff) == 0){
+ recv_raw(metadata);
+ }
+ //otherwise flag the metadata to show that is is a fragment
+ else{
+ metadata = rx_metadata_t();
+ metadata.is_fragment = true;
+ }
+
+ //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 = bytes_to_copy/sizeof(boost::uint32_t);
+ const boost::uint32_t *items = asio::buffer_cast<const boost::uint32_t*>(_rx_copy_buff);
+
+ //calculate the number of samples to be copied
+ //and copy the samples from the recv buffer
+ if (type == "32fc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps);
+ usrp2_items_to_host_floats(asio::buffer_cast<fc32_t*>(buff), items, num_samps);
+ }
+ else if (type == "16sc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps);
+ usrp2_items_to_host_items(asio::buffer_cast<boost::uint32_t*>(buff), items, num_samps);
+ }
+ else{
+ throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type));
+ }
+
+ //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 cc73b229c..cbca8eec7 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -24,28 +24,38 @@ using namespace uhd;
* Helper Methods
**********************************************************************/
void usrp2_impl::mboard_init(void){
- _mboards[""] = wax_obj_proxy(
+ _mboards[""] = wax_obj_proxy::make(
boost::bind(&usrp2_impl::mboard_get, this, _1, _2),
boost::bind(&usrp2_impl::mboard_set, this, _1, _2)
);
+
+ //set the time on the usrp2 as close as possible to the system utc time
+ boost::posix_time::ptime now(boost::posix_time::microsec_clock::universal_time());
+ set_time_spec(time_spec_t(now, get_master_clock_freq()), true);
}
void usrp2_impl::init_clock_config(void){
+ //init the ref source clock config
+ _ref_source_dict = boost::assign::map_list_of
+ ("int", USRP2_REF_SOURCE_INT)
+ ("sma", USRP2_REF_SOURCE_SMA)
+ ("mimo", USRP2_REF_SOURCE_MIMO)
+ ;
+ _clock_config.ref_source = "int";
+
//init the pps source clock config
- _pps_source_dict["sma"] = USRP2_PPS_SOURCE_SMA;
- _pps_source_dict["mimo"] = USRP2_PPS_SOURCE_MIMO;
- _pps_source = "sma";
+ _pps_source_dict = boost::assign::map_list_of
+ ("sma", USRP2_PPS_SOURCE_SMA)
+ ("mimo", USRP2_PPS_SOURCE_MIMO)
+ ;
+ _clock_config.pps_source = "sma";
//init the pps polarity clock config
- _pps_polarity_dict["pos"] = USRP2_PPS_POLARITY_POS;
- _pps_polarity_dict["neg"] = USRP2_PPS_POLARITY_NEG;
- _pps_polarity = "neg";
-
- //init the ref source clock config
- _ref_source_dict["int"] = USRP2_REF_SOURCE_INT;
- _ref_source_dict["sma"] = USRP2_REF_SOURCE_SMA;
- _ref_source_dict["mimo"] = USRP2_REF_SOURCE_MIMO;
- _ref_source = "int";
+ _pps_polarity_dict = boost::assign::map_list_of
+ (clock_config_t::POLARITY_POS, USRP2_PPS_POLARITY_POS)
+ (clock_config_t::POLARITY_NEG, USRP2_PPS_POLARITY_NEG)
+ ;
+ _clock_config.pps_polarity = clock_config_t::POLARITY_NEG;
//update the clock config (sends a control packet)
update_clock_config();
@@ -55,15 +65,28 @@ void usrp2_impl::update_clock_config(void){
//setup the out data
usrp2_ctrl_data_t out_data;
out_data.id = htonl(USRP2_CTRL_ID_HERES_A_NEW_CLOCK_CONFIG_BRO);
- out_data.data.clock_config.pps_source = _pps_source_dict [_pps_source];
- out_data.data.clock_config.pps_polarity = _pps_polarity_dict[_pps_polarity];
- out_data.data.clock_config.ref_source = _ref_source_dict [_ref_source];
+ out_data.data.clock_config.ref_source = _ref_source_dict [_clock_config.ref_source];
+ out_data.data.clock_config.pps_source = _pps_source_dict [_clock_config.pps_source];
+ out_data.data.clock_config.pps_polarity = _pps_polarity_dict[_clock_config.pps_polarity];
//send and recv
usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THE_NEW_CLOCK_CONFIG_DUDE);
}
+void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO);
+ out_data.data.time_args.secs = htonl(time_spec.secs);
+ out_data.data.time_args.ticks = htonl(time_spec.ticks);
+ out_data.data.time_args.now = (now)? 1 : 0;
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE);
+}
+
/***********************************************************************
* MBoard Get Properties
**********************************************************************/
@@ -71,18 +94,55 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
wax::obj key; std::string name;
boost::tie(key, name) = extract_named_prop(key_);
+ //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 = ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);
+
+ //extract the address
+ val = reinterpret_cast<mac_addr_t*>(in_data.data.mac_addr)->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 = ctrl_send_and_recv(out_data);
+ 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();
+ return;
+ }
+ }
+
//handle the get request conditioned on the key
- switch(wax::cast<mboard_prop_t>(key)){
+ switch(key.as<mboard_prop_t>()){
case MBOARD_PROP_NAME:
val = std::string("usrp2 mboard");
return;
- case MBOARD_PROP_OTHERS:
- val = prop_names_t(); //empty other props
+ case MBOARD_PROP_OTHERS:{
+ prop_names_t others = boost::assign::list_of
+ ("mac-addr")
+ ("ip-addr")
+ ;
+ val = others;
+ }
return;
case MBOARD_PROP_RX_DBOARD:
- val = _rx_dboards[name].get_link();
+ ASSERT_THROW(_rx_dboards.has_key(name));
+ val = _rx_dboards[name]->get_link();
return;
case MBOARD_PROP_RX_DBOARD_NAMES:
@@ -90,25 +150,21 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
return;
case MBOARD_PROP_TX_DBOARD:
- val = _tx_dboards[name].get_link();
+ ASSERT_THROW(_tx_dboards.has_key(name));
+ val = _tx_dboards[name]->get_link();
return;
case MBOARD_PROP_TX_DBOARD_NAMES:
val = prop_names_t(_tx_dboards.get_keys());
return;
- case MBOARD_PROP_MTU:
- // FIXME we dont know the real MTU...
- // give them something to fragment about
- val = size_t(1500);
- return;
-
case MBOARD_PROP_CLOCK_RATE:
val = freq_t(get_master_clock_freq());
return;
case MBOARD_PROP_RX_DSP:
- val = _rx_dsps[name].get_link();
+ ASSERT_THROW(_rx_dsps.has_key(name));
+ val = _rx_dsps[name]->get_link();
return;
case MBOARD_PROP_RX_DSP_NAMES:
@@ -116,29 +172,22 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
return;
case MBOARD_PROP_TX_DSP:
- val = _tx_dsps[name].get_link();
+ ASSERT_THROW(_tx_dsps.has_key(name));
+ val = _tx_dsps[name]->get_link();
return;
case MBOARD_PROP_TX_DSP_NAMES:
val = prop_names_t(_tx_dsps.get_keys());
return;
- case MBOARD_PROP_PPS_SOURCE:
- val = _pps_source;
+ case MBOARD_PROP_CLOCK_CONFIG:
+ val = _clock_config;
return;
case MBOARD_PROP_PPS_SOURCE_NAMES:
val = prop_names_t(_pps_source_dict.get_keys());
return;
- case MBOARD_PROP_PPS_POLARITY:
- val = _pps_polarity;
- return;
-
- case MBOARD_PROP_REF_SOURCE:
- val = _ref_source;
- return;
-
case MBOARD_PROP_REF_SOURCE_NAMES:
val = prop_names_t(_ref_source_dict.get_keys());
return;
@@ -154,36 +203,58 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
* MBoard Set Properties
**********************************************************************/
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(val.as<std::string>());
+ std::memcpy(out_data.data.mac_addr, &mac_addr, sizeof(mac_addr_t));
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);
+ 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 = ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);
+ return;
+ }
+ }
+
//handle the get request conditioned on the key
- switch(wax::cast<mboard_prop_t>(key)){
+ switch(key.as<mboard_prop_t>()){
- case MBOARD_PROP_PPS_SOURCE:{
- std::string name = wax::cast<std::string>(val);
- ASSERT_THROW(_pps_source_dict.has_key(name));
- _pps_source = name; //shadow
+ case MBOARD_PROP_CLOCK_CONFIG:{
+ clock_config_t clock_config = val.as<clock_config_t>();
+ assert_has(_pps_source_dict.get_keys(), clock_config.pps_source, "usrp2 pps source");
+ assert_has(_ref_source_dict.get_keys(), clock_config.ref_source, "usrp2 ref source");
+ _clock_config = clock_config; //shadow
update_clock_config();
}
return;
- case MBOARD_PROP_PPS_POLARITY:{
- std::string name = wax::cast<std::string>(val);
- ASSERT_THROW(_pps_polarity_dict.has_key(name));
- _pps_polarity = name; //shadow
- update_clock_config();
- }
+ case MBOARD_PROP_TIME_NOW:{
+ set_time_spec(val.as<time_spec_t>(), true);
return;
+ }
- case MBOARD_PROP_REF_SOURCE:{
- std::string name = wax::cast<std::string>(val);
- ASSERT_THROW(_ref_source_dict.has_key(name));
- _ref_source = name; //shadow
- update_clock_config();
- }
+ case MBOARD_PROP_TIME_NEXT_PPS:{
+ set_time_spec(val.as<time_spec_t>(), false);
return;
+ }
case MBOARD_PROP_NAME:
case MBOARD_PROP_OTHERS:
- case MBOARD_PROP_MTU:
case MBOARD_PROP_CLOCK_RATE:
case MBOARD_PROP_RX_DSP:
case MBOARD_PROP_RX_DSP_NAMES:
@@ -195,8 +266,6 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){
case MBOARD_PROP_TX_DBOARD_NAMES:
case MBOARD_PROP_PPS_SOURCE_NAMES:
case MBOARD_PROP_REF_SOURCE_NAMES:
- case MBOARD_PROP_TIME_NOW:
- case MBOARD_PROP_TIME_NEXT_PPS:
throw std::runtime_error("Error: trying to set read-only property on usrp2 mboard");
}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 2b4e8fe39..85d73e83a 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -23,6 +23,12 @@
using namespace uhd;
using namespace uhd::usrp;
+using namespace uhd::transport;
+namespace asio = boost::asio;
+
+STATIC_BLOCK(register_usrp2_device){
+ device::register_device(&usrp2::discover, &usrp2::make);
+}
/***********************************************************************
* Discovery over the udp transport
@@ -30,40 +36,41 @@ using namespace uhd::usrp;
uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){
device_addrs_t usrp2_addrs;
+ if (not hint.has_key("addr")) return usrp2_addrs;
+
//create a udp transport to communicate
//TODO if an addr is not provided, search all interfaces?
std::string ctrl_port = boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT);
- uhd::transport::udp udp_transport(hint["addr"], ctrl_port, true);
+ udp_simple::sptr udp_transport = udp_simple::make_broadcast(
+ hint["addr"], ctrl_port
+ );
//send a hello control packet
usrp2_ctrl_data_t ctrl_data_out;
ctrl_data_out.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO);
- udp_transport.send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out)));
+ udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out)));
- //loop and recieve until the time is up
- size_t num_timeouts = 0;
+ //loop and recieve until the timeout
while(true){
- uhd::shared_iovec iov = udp_transport.recv();
- //std::cout << boost::asio::buffer_size(buff) << "\n";
- if (iov.len < sizeof(usrp2_ctrl_data_t)){
- //sleep a little so we dont burn cpu
- if (num_timeouts++ > 50) break;
- boost::this_thread::sleep(boost::posix_time::milliseconds(1));
- }else{
+ usrp2_ctrl_data_t ctrl_data_in;
+ size_t len = udp_transport->recv(asio::buffer(&ctrl_data_in, sizeof(ctrl_data_in)));
+ //std::cout << len << "\n";
+ if (len >= sizeof(usrp2_ctrl_data_t)){
//handle the received data
- const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<const usrp2_ctrl_data_t *>(iov.base);
- switch(ntohl(ctrl_data_in->id)){
+ switch(ntohl(ctrl_data_in.id)){
case USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_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));
+ boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in.data.ip_addr));
device_addr_t new_addr;
new_addr["name"] = "USRP2";
- new_addr["type"] = "udp";
+ new_addr["transport"] = "udp";
new_addr["addr"] = ip_addr.to_string();
usrp2_addrs.push_back(new_addr);
- break;
+ //dont break here, it will exit the while loop
+ //just continue on to the next loop iteration
}
}
+ if (len == 0) break; //timeout
}
return usrp2_addrs;
@@ -72,21 +79,19 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){
/***********************************************************************
* Make
**********************************************************************/
+template <class T> std::string num2str(T num){
+ return boost::lexical_cast<std::string>(num);
+}
+
device::sptr usrp2::make(const device_addr_t &device_addr){
//create a control transport
- uhd::transport::udp::sptr ctrl_transport(
- new uhd::transport::udp(
- device_addr["addr"],
- boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT)
- )
+ udp_simple::sptr ctrl_transport = udp_simple::make_connected(
+ device_addr["addr"], num2str(USRP2_UDP_CTRL_PORT)
);
//create a data transport
- uhd::transport::udp::sptr data_transport(
- new uhd::transport::udp(
- device_addr["addr"],
- boost::lexical_cast<std::string>(USRP2_UDP_DATA_PORT)
- )
+ udp_zero_copy::sptr data_transport = udp_zero_copy::make(
+ device_addr["addr"], num2str(USRP2_UDP_DATA_PORT)
);
//create the usrp2 implementation guts
@@ -99,8 +104,8 @@ device::sptr usrp2::make(const device_addr_t &device_addr){
* Structors
**********************************************************************/
usrp2_impl::usrp2_impl(
- uhd::transport::udp::sptr ctrl_transport,
- uhd::transport::udp::sptr data_transport
+ udp_simple::sptr ctrl_transport,
+ udp_zero_copy::sptr data_transport
){
_ctrl_transport = ctrl_transport;
_data_transport = data_transport;
@@ -121,9 +126,6 @@ usrp2_impl::usrp2_impl(
//init the mboard
mboard_init();
- //init the tx and rx dboards
- dboard_init();
-
//init the ddc
init_ddc_config();
@@ -132,6 +134,13 @@ usrp2_impl::usrp2_impl(
//initialize the clock configuration
init_clock_config();
+
+ //init the tx and rx dboards (do last)
+ dboard_init();
+
+ //init the send and recv io
+ io_init();
+
}
usrp2_impl::~usrp2_impl(void){
@@ -156,22 +165,15 @@ usrp2_ctrl_data_t usrp2_impl::ctrl_send_and_recv(const usrp2_ctrl_data_t &out_da
out_copy.seq = htonl(++_ctrl_seq_num);
_ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t)));
- //loop and recieve until the time is up
- size_t num_timeouts = 0;
+ //loop until we get the packet or timeout
while(true){
- uhd::shared_iovec iov = _ctrl_transport->recv();
- if (iov.len < sizeof(usrp2_ctrl_data_t)){
- //sleep a little so we dont burn cpu
- if (num_timeouts++ > 50) break;
- boost::this_thread::sleep(boost::posix_time::milliseconds(1));
- }else{
- //handle the received data
- usrp2_ctrl_data_t in_data = *reinterpret_cast<const usrp2_ctrl_data_t *>(iov.base);
- if (ntohl(in_data.seq) == _ctrl_seq_num){
- return in_data;
- }
- //didnt get seq, continue on...
+ usrp2_ctrl_data_t in_data;
+ size_t len = _ctrl_transport->recv(asio::buffer(&in_data, sizeof(in_data)));
+ if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(in_data.seq) == _ctrl_seq_num){
+ return in_data;
}
+ if (len == 0) break; //timeout
+ //didnt get seq or bad packet, continue looking...
}
throw std::runtime_error("usrp2 no control response");
}
@@ -184,32 +186,31 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){
boost::tie(key, name) = extract_named_prop(key_);
//handle the get request conditioned on the key
- switch(wax::cast<device_prop_t>(key)){
+ switch(key.as<device_prop_t>()){
case DEVICE_PROP_NAME:
val = std::string("usrp2 device");
return;
case DEVICE_PROP_MBOARD:
- val = _mboards[name].get_link();
+ ASSERT_THROW(_mboards.has_key(name));
+ val = _mboards[name]->get_link();
return;
case DEVICE_PROP_MBOARD_NAMES:
val = prop_names_t(_mboards.get_keys());
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;
+
}
}
void usrp2_impl::set(const wax::obj &, const wax::obj &){
throw std::runtime_error("Cannot set in usrp2 device");
}
-
-/***********************************************************************
- * IO Interface
- **********************************************************************/
-void usrp2_impl::send_raw(const std::vector<boost::asio::const_buffer> &){
- return;
-}
-
-uhd::shared_iovec usrp2_impl::recv_raw(void){
- throw std::runtime_error("not implemented");
-}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index 2545efd58..55ac0b192 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -15,19 +15,31 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#ifndef INCLUDED_USRP2_IMPL_HPP
+#define INCLUDED_USRP2_IMPL_HPP
+
#include <uhd/usrp/usrp2.hpp>
#include <uhd/dict.hpp>
-#include <uhd/props.hpp>
+#include <uhd/types.hpp>
#include <uhd/time_spec.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
-#include <uhd/transport/udp.hpp>
+#include <boost/assign/list_of.hpp>
+#include <uhd/transport/vrt.hpp>
+#include <uhd/transport/udp_simple.hpp>
+#include <uhd/transport/udp_zero_copy.hpp>
#include <uhd/usrp/dboard_manager.hpp>
#include "fw_common.h"
-#ifndef INCLUDED_USRP2_IMPL_HPP
-#define INCLUDED_USRP2_IMPL_HPP
+class usrp2_impl; //dummy class declaration
+
+/*!
+ * Make a usrp2 dboard interface.
+ * \param impl a pointer to the usrp2 impl object
+ * \return a sptr to a new dboard interface
+ */
+uhd::usrp::dboard_interface::sptr make_usrp2_dboard_interface(usrp2_impl *impl);
/*!
* Simple wax obj proxy class:
@@ -39,20 +51,25 @@ class wax_obj_proxy : public wax::obj{
public:
typedef boost::function<void(const wax::obj &, wax::obj &)> get_t;
typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t;
+ typedef boost::shared_ptr<wax_obj_proxy> sptr;
- wax_obj_proxy(void){
+ static sptr make(const get_t &get, const set_t &set){
+ return sptr(new wax_obj_proxy(get, set));
+ }
+
+ ~wax_obj_proxy(void){
/* NOP */
}
+private:
+ get_t _get;
+ set_t _set;
+
wax_obj_proxy(const get_t &get, const set_t &set){
_get = get;
_set = set;
};
- ~wax_obj_proxy(void){
- /* NOP */
- }
-
void get(const wax::obj &key, wax::obj &val){
return _get(key, val);
}
@@ -60,10 +77,6 @@ public:
void set(const wax::obj &key, const wax::obj &val){
return _set(key, val);
}
-
-private:
- get_t _get;
- set_t _set;
};
/*!
@@ -73,24 +86,18 @@ private:
*/
class usrp2_impl : public uhd::device{
public:
- typedef boost::shared_ptr<usrp2_impl> sptr;
-
/*!
* Create a new usrp2 impl base.
* \param ctrl_transport the udp transport for control
* \param data_transport the udp transport for data
*/
usrp2_impl(
- uhd::transport::udp::sptr ctrl_transport,
- uhd::transport::udp::sptr data_transport
+ uhd::transport::udp_simple::sptr ctrl_transport,
+ uhd::transport::udp_zero_copy::sptr data_transport
);
~usrp2_impl(void);
- //properties interface
- void get(const wax::obj &, wax::obj &);
- void set(const wax::obj &, const wax::obj &);
-
//performs a control transaction
usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &);
@@ -98,27 +105,51 @@ public:
double get_master_clock_freq(void);
//the io interface
- void send_raw(const std::vector<boost::asio::const_buffer> &);
- uhd::shared_iovec recv_raw(void);
+ size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const std::string &);
+ size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const std::string &);
private:
+ //device properties interface
+ void get(const wax::obj &, wax::obj &);
+ void set(const wax::obj &, const wax::obj &);
+
+ //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;
+ 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_tx_samples_per_packet =
+ (_mtu - _hdrs)/sizeof(boost::uint32_t) -
+ uhd::transport::vrt::max_header_words32
+ ;
+ uhd::transport::smart_buffer::sptr _rx_smart_buff;
+ boost::asio::const_buffer _rx_copy_buff;
+ void io_init(void);
+
//udp transports for control and data
- uhd::transport::udp::sptr _ctrl_transport;
- uhd::transport::udp::sptr _data_transport;
+ uhd::transport::udp_simple::sptr _ctrl_transport;
+ uhd::transport::udp_zero_copy::sptr _data_transport;
//private vars for dealing with send/recv control
- uint32_t _ctrl_seq_num;
+ boost::uint32_t _ctrl_seq_num;
boost::mutex _ctrl_mutex;
//methods and shadows for clock configuration
- std::string _pps_source, _pps_polarity, _ref_source;
+ uhd::clock_config_t _clock_config;
void init_clock_config(void);
void update_clock_config(void);
+ void set_time_spec(const uhd::time_spec_t &time_spec, bool now);
//mappings from clock config strings to over the wire enums
- uhd::dict<std::string, usrp2_pps_source_t> _pps_source_dict;
- uhd::dict<std::string, usrp2_pps_polarity_t> _pps_polarity_dict;
- uhd::dict<std::string, usrp2_ref_source_t> _ref_source_dict;
+ uhd::dict<std::string, usrp2_ref_source_t> _ref_source_dict;
+ uhd::dict<std::string, usrp2_pps_source_t> _pps_source_dict;
+ uhd::dict<uhd::clock_config_t::polarity_t, usrp2_pps_polarity_t> _pps_polarity_dict;
//rx and tx dboard methods and objects
uhd::usrp::dboard_manager::sptr _dboard_manager;
@@ -128,17 +159,20 @@ private:
void mboard_init(void);
void mboard_get(const wax::obj &, wax::obj &);
void mboard_set(const wax::obj &, const wax::obj &);
- uhd::dict<std::string, wax_obj_proxy> _mboards;
+ uhd::dict<std::string, wax_obj_proxy::sptr> _mboards;
//properties interface for rx dboard
void rx_dboard_get(const wax::obj &, wax::obj &);
void rx_dboard_set(const wax::obj &, const wax::obj &);
- uhd::dict<std::string, wax_obj_proxy> _rx_dboards;
+ uhd::dict<std::string, wax_obj_proxy::sptr> _rx_dboards;
+ uhd::prop_names_t _rx_subdevs_in_use;
//properties interface for tx dboard
void tx_dboard_get(const wax::obj &, wax::obj &);
void tx_dboard_set(const wax::obj &, const wax::obj &);
- uhd::dict<std::string, wax_obj_proxy> _tx_dboards;
+ uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dboards;
+ uhd::prop_names_t _tx_subdevs_in_use;
+ void update_mux_config(void);
//methods and shadows for the ddc dsp
std::vector<size_t> _allowed_decim_and_interp_rates;
@@ -159,12 +193,12 @@ private:
//properties interface for ddc
void ddc_get(const wax::obj &, wax::obj &);
void ddc_set(const wax::obj &, const wax::obj &);
- uhd::dict<std::string, wax_obj_proxy> _rx_dsps;
+ uhd::dict<std::string, wax_obj_proxy::sptr> _rx_dsps;
//properties interface for duc
void duc_get(const wax::obj &, wax::obj &);
void duc_set(const wax::obj &, const wax::obj &);
- uhd::dict<std::string, wax_obj_proxy> _tx_dsps;
+ uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dsps;
};
diff --git a/host/lib/wax.cpp b/host/lib/wax.cpp
index c08398c50..0e2e82a3a 100644
--- a/host/lib/wax.cpp
+++ b/host/lib/wax.cpp
@@ -36,7 +36,11 @@ public:
link_args_t(const wax::obj *obj_ptr) : _obj_ptr(obj_ptr){
/* NOP */
}
- wax::obj & operator()(void){
+ wax::obj & operator()(void) const{
+ //recursively resolve link args to get at original pointer
+ if (_obj_ptr->type() == typeid(link_args_t)){
+ return _obj_ptr->as<link_args_t>()();
+ }
return *const_cast<wax::obj *>(_obj_ptr);
}
private:
@@ -56,10 +60,10 @@ public:
proxy_args_t(const wax::obj *obj_ptr, const wax::obj &key) : _key(key){
_obj_link = obj_ptr->get_link();
}
- wax::obj & operator()(void){
- return wax::cast<link_args_t>(_obj_link)();
+ wax::obj & operator()(void) const{
+ return _obj_link.as<link_args_t>()();
}
- const wax::obj & key(void){
+ const wax::obj & key(void) const{
return _key;
}
private:
@@ -90,7 +94,7 @@ wax::obj wax::obj::operator[](const obj &key){
obj val = resolve();
//check if its a special link and call
if (val.type() == typeid(link_args_t)){
- return cast<link_args_t>(val)()[key];
+ return val.as<link_args_t>()()[key];
}
//unknown obj
throw std::runtime_error("cannot use [] on non wax::obj link");
diff --git a/host/test/CMakeLists.txt b/host/test/CMakeLists.txt
index 234b6f92c..1791d9082 100644
--- a/host/test/CMakeLists.txt
+++ b/host/test/CMakeLists.txt
@@ -15,14 +15,20 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-
+########################################################################
+# unit test suite
+########################################################################
ADD_EXECUTABLE(main_test
main_test.cpp
addr_test.cpp
gain_handler_test.cpp
+ vrt_test.cpp
wax_test.cpp
)
-
TARGET_LINK_LIBRARIES(main_test uhd)
-
ADD_TEST(test main_test)
+
+########################################################################
+# demo of a loadable module
+########################################################################
+ADD_LIBRARY(module_test MODULE module_test.cpp)
diff --git a/host/test/gain_handler_test.cpp b/host/test/gain_handler_test.cpp
index c81221aac..47acb30f0 100644
--- a/host/test/gain_handler_test.cpp
+++ b/host/test/gain_handler_test.cpp
@@ -17,33 +17,37 @@
#include <boost/test/unit_test.hpp>
#include <uhd/gain_handler.hpp>
+#include <uhd/types.hpp>
+#include <uhd/props.hpp>
#include <uhd/dict.hpp>
+#include <boost/bind.hpp>
#include <iostream>
using namespace uhd;
enum prop_t{
- PROP_GAIN,
- PROP_GAIN_MIN,
- PROP_GAIN_MAX,
- PROP_GAIN_STEP,
+ PROP_GAIN_VALUE,
+ PROP_GAIN_RANGE,
PROP_GAIN_NAMES
};
class gainful_obj : public wax::obj{
public:
gainful_obj(void){
- _gain_handler = gain_handler::sptr(new gain_handler(
- this, PROP_GAIN, PROP_GAIN_MIN, PROP_GAIN_MAX, PROP_GAIN_STEP, PROP_GAIN_NAMES
- ));
- _gains["g0"] = 0;
- _gains["g1"] = 0;
- _gains_min["g0"] = -10;
- _gains_min["g1"] = 0;
- _gains_max["g0"] = 0;
- _gains_max["g1"] = 100;
- _gains_step["g0"] = .1;
- _gains_step["g1"] = 1.5;
+ //initialize gain props struct
+ gain_handler::props_t gain_props;
+ gain_props.value = PROP_GAIN_VALUE;
+ gain_props.range = PROP_GAIN_RANGE;
+ gain_props.names = PROP_GAIN_NAMES;
+ //make a new gain handler
+ _gain_handler = gain_handler::make(
+ this->get_link(), gain_props,
+ boost::bind(&gain_handler::is_equal<prop_t>, _1, _2)
+ );
+ _gain_values["g0"] = 0;
+ _gain_values["g1"] = 0;
+ _gain_ranges["g0"] = gain_range_t(-10, 0, .1);
+ _gain_ranges["g1"] = gain_range_t(0, 100, 1.5);
}
~gainful_obj(void){}
@@ -56,25 +60,17 @@ private:
boost::tie(key, name) = extract_named_prop(key_);
//handle the get request conditioned on the key
- switch(wax::cast<prop_t>(key)){
- case PROP_GAIN:
- val = _gains[name];
+ switch(key.as<prop_t>()){
+ case PROP_GAIN_VALUE:
+ val = _gain_values[name];
return;
- case PROP_GAIN_MIN:
- val = _gains_min[name];
- return;
-
- case PROP_GAIN_MAX:
- val = _gains_max[name];
- return;
-
- case PROP_GAIN_STEP:
- val = _gains_step[name];
+ case PROP_GAIN_RANGE:
+ val = _gain_ranges[name];
return;
case PROP_GAIN_NAMES:
- val = prop_names_t(_gains.get_keys());
+ val = _gain_values.get_keys();
return;
}
}
@@ -86,24 +82,20 @@ private:
boost::tie(key, name) = extract_named_prop(key_);
//handle the get request conditioned on the key
- switch(wax::cast<prop_t>(key)){
- case PROP_GAIN:
- _gains[name] = wax::cast<gain_t>(val);
+ switch(key.as<prop_t>()){
+ case PROP_GAIN_VALUE:
+ _gain_values[name] = val.as<gain_t>();
return;
- case PROP_GAIN_MIN:
- case PROP_GAIN_MAX:
- case PROP_GAIN_STEP:
+ case PROP_GAIN_RANGE:
case PROP_GAIN_NAMES:
throw std::runtime_error("cannot set this property");
}
}
gain_handler::sptr _gain_handler;
- uhd::dict<std::string, gain_t> _gains;
- uhd::dict<std::string, gain_t> _gains_min;
- uhd::dict<std::string, gain_t> _gains_max;
- uhd::dict<std::string, gain_t> _gains_step;
+ uhd::dict<std::string, gain_t> _gain_values;
+ uhd::dict<std::string, gain_range_t> _gain_ranges;
};
@@ -112,17 +104,18 @@ BOOST_AUTO_TEST_CASE(test_gain_handler){
gainful_obj go0;
BOOST_CHECK_THROW(
- wax::cast<gain_t>(go0[named_prop_t(PROP_GAIN, "fail")]),
- std::invalid_argument
+ go0[named_prop_t(PROP_GAIN_VALUE, "fail")].as<gain_t>(),
+ std::exception
);
std::cout << "verifying the overall min, max, step" << std::endl;
- BOOST_CHECK_EQUAL(wax::cast<gain_t>(go0[PROP_GAIN_MIN]), gain_t(-10));
- BOOST_CHECK_EQUAL(wax::cast<gain_t>(go0[PROP_GAIN_MAX]), gain_t(100));
- BOOST_CHECK_EQUAL(wax::cast<gain_t>(go0[PROP_GAIN_STEP]), gain_t(1.5));
+ gain_range_t gain = go0[PROP_GAIN_RANGE].as<gain_range_t>();
+ BOOST_CHECK_EQUAL(gain.min, gain_t(-10));
+ BOOST_CHECK_EQUAL(gain.max, gain_t(100));
+ BOOST_CHECK_EQUAL(gain.step, gain_t(1.5));
std::cout << "verifying the overall gain" << std::endl;
- go0[named_prop_t(PROP_GAIN, "g0")] = gain_t(-5);
- go0[named_prop_t(PROP_GAIN, "g1")] = gain_t(30);
- BOOST_CHECK_EQUAL(wax::cast<gain_t>(go0[PROP_GAIN]), gain_t(25));
+ go0[named_prop_t(PROP_GAIN_VALUE, "g0")] = gain_t(-5);
+ go0[named_prop_t(PROP_GAIN_VALUE, "g1")] = gain_t(30);
+ BOOST_CHECK_EQUAL(go0[PROP_GAIN_VALUE].as<gain_t>(), gain_t(25));
}
diff --git a/host/lib/shared_iovec.cpp b/host/test/module_test.cpp
index 60062fbf0..71721ef90 100644
--- a/host/lib/shared_iovec.cpp
+++ b/host/test/module_test.cpp
@@ -15,14 +15,12 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <uhd/shared_iovec.hpp>
+#include <uhd/utils.hpp>
+#include <iostream>
-uhd::shared_iovec::shared_iovec(size_t len_){
- _shared_array = boost::shared_array<uint8_t>(new uint8_t[len_]);
- base = _shared_array.get();
- len = len_;
-}
-
-uhd::shared_iovec::~shared_iovec(void){
- /* NOP */
+STATIC_BLOCK(module_test){
+ std::cout << "---------------------------------------" << std::endl;
+ std::cout << "-- Good news, everyone!" << std::endl;
+ std::cout << "-- The test module has been loaded." << std::endl;
+ std::cout << "---------------------------------------" << std::endl;
}
diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp
new file mode 100644
index 000000000..40116e110
--- /dev/null
+++ b/host/test/vrt_test.cpp
@@ -0,0 +1,100 @@
+//
+// 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 <boost/test/unit_test.hpp>
+#include <uhd/transport/vrt.hpp>
+
+using namespace uhd::transport;
+
+static void pack_and_unpack(
+ const uhd::tx_metadata_t &metadata,
+ size_t num_payload_words32,
+ size_t packet_count
+){
+ boost::uint32_t header_buff[vrt::max_header_words32];
+ size_t num_header_words32;
+ size_t num_packet_words32;
+
+ //pack metadata into a vrt header
+ vrt::pack(
+ metadata, //input
+ header_buff, //output
+ num_header_words32, //output
+ num_payload_words32, //input
+ num_packet_words32, //output
+ packet_count //input
+ );
+
+ uhd::rx_metadata_t metadata_out;
+ size_t num_header_words32_out;
+ size_t num_payload_words32_out;
+ size_t packet_count_out;
+
+ //unpack the vrt header back into metadata
+ vrt::unpack(
+ metadata_out, //output
+ header_buff, //input
+ num_header_words32_out, //output
+ num_payload_words32_out, //output
+ num_packet_words32, //input
+ packet_count_out //output
+ );
+
+ //check the the unpacked metadata is the same
+ BOOST_CHECK_EQUAL(packet_count, packet_count_out);
+ BOOST_CHECK_EQUAL(num_header_words32, num_header_words32_out);
+ BOOST_CHECK_EQUAL(num_payload_words32, num_payload_words32_out);
+ BOOST_CHECK_EQUAL(metadata.has_stream_id, metadata_out.has_stream_id);
+ if (metadata.has_stream_id and metadata_out.has_stream_id){
+ BOOST_CHECK_EQUAL(metadata.stream_id, metadata_out.stream_id);
+ }
+ BOOST_CHECK_EQUAL(metadata.has_time_spec, metadata_out.has_time_spec);
+ if (metadata.has_time_spec and metadata_out.has_time_spec){
+ BOOST_CHECK_EQUAL(metadata.time_spec.secs, metadata_out.time_spec.secs);
+ BOOST_CHECK_EQUAL(metadata.time_spec.ticks, metadata_out.time_spec.ticks);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_with_none){
+ uhd::tx_metadata_t metadata;
+ pack_and_unpack(metadata, 300, 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_sid){
+ uhd::tx_metadata_t metadata;
+ metadata.has_stream_id = true;
+ metadata.stream_id = 6;
+ pack_and_unpack(metadata, 400, 2);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_time_spec){
+ uhd::tx_metadata_t metadata;
+ metadata.has_time_spec = true;
+ metadata.time_spec.secs = 7;
+ metadata.time_spec.ticks = 2000;
+ pack_and_unpack(metadata, 500, 3);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_sid_and_time_spec){
+ uhd::tx_metadata_t metadata;
+ metadata.has_stream_id = true;
+ metadata.stream_id = 2;
+ metadata.has_time_spec = true;
+ metadata.time_spec.secs = 5;
+ metadata.time_spec.ticks = 1000;
+ pack_and_unpack(metadata, 600, 4);
+}
diff --git a/host/test/wax_test.cpp b/host/test/wax_test.cpp
index e5e1adc25..cb3b12052 100644
--- a/host/test/wax_test.cpp
+++ b/host/test/wax_test.cpp
@@ -17,14 +17,15 @@
#include <boost/test/unit_test.hpp>
#include <uhd/wax.hpp>
+#include <iostream>
enum opt_a_t{OPTION_A_0, OPTION_A_1};
enum opt_b_t{OPTION_B_0, OPTION_B_1};
BOOST_AUTO_TEST_CASE(test_enums){
wax::obj opta = OPTION_A_0;
- BOOST_CHECK_THROW(wax::cast<opt_b_t>(opta), wax::bad_cast);
- BOOST_CHECK_EQUAL(wax::cast<opt_a_t>(opta), OPTION_A_0);
+ BOOST_CHECK_THROW(opta.as<opt_b_t>(), wax::bad_cast);
+ BOOST_CHECK_EQUAL(opta.as<opt_a_t>(), OPTION_A_0);
}
/***********************************************************************
@@ -48,14 +49,14 @@ public:
}
void get(const wax::obj &key, wax::obj &value){
if (d_subs.size() == 0){
- value = d_nums[wax::cast<size_t>(key)];
+ value = d_nums[key.as<size_t>()];
}else{
- value = d_subs[wax::cast<size_t>(key)].get_link();
+ value = d_subs[key.as<size_t>()].get_link();
}
}
void set(const wax::obj &key, const wax::obj &value){
if (d_subs.size() == 0){
- d_nums[wax::cast<size_t>(key)] = wax::cast<float>(value);
+ d_nums[key.as<size_t>()] = value.as<float>();
}else{
throw std::runtime_error("cant set to a wax demo with sub demos");
}
@@ -78,10 +79,10 @@ BOOST_AUTO_TEST_CASE(test_set_get){
for (size_t i = 0; i < 10; i++){
for (size_t j = 0; j < 10; j++){
for (size_t k = 0; k < 10; k++){
- float val = i * j * k + i + j + k;
+ float val = float(i * j * k + i + j + k);
//std::cout << i << " " << j << " " << k << std::endl;
wd[i][j][k] = val;
- BOOST_CHECK_EQUAL(val, wax::cast<float>(wd[i][j][k]));
+ BOOST_CHECK_EQUAL(val, wd[i][j][k].as<float>());
}
}
}
@@ -94,5 +95,5 @@ BOOST_AUTO_TEST_CASE(test_proxy){
std::cout << "assign proxy" << std::endl;
wax::obj a = p[size_t(0)];
- BOOST_CHECK_EQUAL(wax::cast<float>(a), float(5));
+ BOOST_CHECK_EQUAL(a.as<float>(), float(5));
}