aboutsummaryrefslogtreecommitdiffstats
path: root/host/utils
diff options
context:
space:
mode:
Diffstat (limited to 'host/utils')
-rw-r--r--host/utils/CMakeLists.txt31
-rw-r--r--host/utils/cdecode.c80
-rw-r--r--host/utils/cdecode.h28
-rw-r--r--host/utils/converter_benchmark.cpp433
-rw-r--r--host/utils/converter_benchmark.py193
-rw-r--r--host/utils/fx2_init_eeprom.cpp31
-rw-r--r--host/utils/query_gpsdo_sensors.cpp121
-rw-r--r--host/utils/uhd_config_info.cpp89
8 files changed, 856 insertions, 150 deletions
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt
index 28fecc895..bf8d88799 100644
--- a/host/utils/CMakeLists.txt
+++ b/host/utils/CMakeLists.txt
@@ -19,6 +19,7 @@
# Utilities that get installed into the runtime path
########################################################################
SET(util_runtime_sources
+ uhd_config_info.cpp
uhd_find_devices.cpp
uhd_usrp_probe.cpp
uhd_image_loader.cpp
@@ -30,7 +31,7 @@ SET(util_runtime_sources
SET(x3xx_burner_sources
usrp_x3xx_fpga_burner.cpp
- cdecode.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../lib/usrp/x300/cdecode.c
)
find_package(UDev)
@@ -48,18 +49,25 @@ FOREACH(util_source ${util_runtime_sources})
UHD_INSTALL(TARGETS ${util_name} RUNTIME DESTINATION ${RUNTIME_DIR} COMPONENT utilities)
ENDFOREACH(util_source)
-ADD_EXECUTABLE(usrp_x3xx_fpga_burner ${x3xx_burner_sources})
-TARGET_LINK_LIBRARIES(usrp_x3xx_fpga_burner uhd ${Boost_LIBRARIES})
-UHD_INSTALL(TARGETS usrp_x3xx_fpga_burner RUNTIME DESTINATION ${RUNTIME_DIR} COMPONENT utilities)
+IF(ENABLE_X300)
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/x300)
+ ADD_EXECUTABLE(usrp_x3xx_fpga_burner ${x3xx_burner_sources})
+ TARGET_LINK_LIBRARIES(usrp_x3xx_fpga_burner uhd ${Boost_LIBRARIES})
+ UHD_INSTALL(TARGETS usrp_x3xx_fpga_burner RUNTIME DESTINATION ${RUNTIME_DIR} COMPONENT utilities)
+ENDIF(ENABLE_X300)
########################################################################
# Utilities that get installed into the share path
########################################################################
SET(util_share_sources
+ converter_benchmark.cpp
query_gpsdo_sensors.cpp
usrp_burn_db_eeprom.cpp
usrp_burn_mb_eeprom.cpp
)
+SET(util_share_sources_py
+ converter_benchmark.py
+)
IF(ENABLE_USB)
LIST(APPEND util_share_sources
fx2_init_eeprom.cpp
@@ -108,9 +116,20 @@ FOREACH(util_source ${util_share_sources})
TARGET_LINK_LIBRARIES(${util_name} uhd ${Boost_LIBRARIES})
UHD_INSTALL(TARGETS ${util_name} RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities)
ENDFOREACH(util_source)
+FOREACH(util_source ${util_share_sources_py})
+ UHD_INSTALL(PROGRAMS
+ ${CMAKE_CURRENT_SOURCE_DIR}/${util_source}
+ DESTINATION ${PKG_LIB_DIR}/utils
+ COMPONENT utilities
+ )
+ENDFOREACH(util_source)
-UHD_INSTALL(TARGETS usrp_n2xx_simple_net_burner RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities)
-UHD_INSTALL(TARGETS usrp_x3xx_fpga_burner RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities)
+IF(ENABLE_USRP2)
+ UHD_INSTALL(TARGETS usrp_n2xx_simple_net_burner RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities)
+ENDIF(ENABLE_USRP2)
+IF(ENABLE_X300)
+ UHD_INSTALL(TARGETS usrp_x3xx_fpga_burner RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities)
+ENDIF(ENABLE_X300)
#UHD images downloader configuration
CONFIGURE_FILE(
diff --git a/host/utils/cdecode.c b/host/utils/cdecode.c
deleted file mode 100644
index 1d09cbe22..000000000
--- a/host/utils/cdecode.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-cdecoder.c - c source to a base64 decoding algorithm implementation
-
-This is part of the libb64 project, and has been placed in the public domain.
-For details, see http://sourceforge.net/projects/libb64
-*/
-
-#include "cdecode.h"
-
-int base64_decode_value(char value_in){
- static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
- static const char decoding_size = sizeof(decoding);
- value_in -= 43;
- if ((signed char)value_in < 0 || value_in > decoding_size) return -1;
- return decoding[(int)value_in];
-}
-
-void base64_init_decodestate(base64_decodestate* state_in){
- state_in->step = step_a;
- state_in->plainchar = 0;
-}
-
-size_t base64_decode_block(const char* code_in, const size_t length_in, char* plaintext_out, base64_decodestate* state_in){
- const char* codechar = code_in;
- char* plainchar = plaintext_out;
- char fragment;
-
- *plainchar = state_in->plainchar;
-
- switch (state_in->step){
- while (1){
- case step_a:
- do{
- if (codechar == code_in+length_in){
- state_in->step = step_a;
- state_in->plainchar = *plainchar;
- return plainchar - plaintext_out;
- }
- fragment = (char)base64_decode_value(*codechar++);
- } while ((signed char)fragment < 0);
- *plainchar = (fragment & 0x03f) << 2;
-
- case step_b:
- do{
- if (codechar == code_in+length_in){
- state_in->step = step_b;
- state_in->plainchar = *plainchar;
- return plainchar - plaintext_out;
- }
- fragment = (char)base64_decode_value(*codechar++);
- } while ((signed char)fragment < 0);
- *plainchar++ |= (fragment & 0x030) >> 4;
- *plainchar = (fragment & 0x00f) << 4;
- case step_c:
- do{
- if (codechar == code_in+length_in)
- {
- state_in->step = step_c;
- state_in->plainchar = *plainchar;
- return plainchar - plaintext_out;
- }
- fragment = (char)base64_decode_value(*codechar++);
- } while ((signed char)fragment < 0);
- *plainchar++ |= (fragment & 0x03c) >> 2;
- *plainchar = (fragment & 0x003) << 6;
- case step_d:
- do{
- if (codechar == code_in+length_in){
- state_in->step = step_d;
- state_in->plainchar = *plainchar;
- return plainchar - plaintext_out;
- }
- fragment = (char)base64_decode_value(*codechar++);
- } while ((signed char)fragment < 0);
- *plainchar++ |= (fragment & 0x03f);
- }
- }
- /* control should not reach here */
- return plainchar - plaintext_out;
-}
diff --git a/host/utils/cdecode.h b/host/utils/cdecode.h
deleted file mode 100644
index e1eee301f..000000000
--- a/host/utils/cdecode.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
-cdecode.h - c header for a base64 decoding algorithm
-
-This is part of the libb64 project, and has been placed in the public domain.
-For details, see http://sourceforge.net/projects/libb64
-*/
-
-#ifndef BASE64_CDECODE_H
-#define BASE64_CDECODE_H
-
-#include <stddef.h>
-
-typedef enum{
- step_a, step_b, step_c, step_d
-} base64_decodestep;
-
-typedef struct{
- base64_decodestep step;
- char plainchar;
-} base64_decodestate;
-
-void base64_init_decodestate(base64_decodestate* state_in);
-
-int base64_decode_value(char value_in);
-
-size_t base64_decode_block(const char* code_in, const size_t length_in, char* plaintext_out, base64_decodestate* state_in);
-
-#endif /* BASE64_CDECODE_H */
diff --git a/host/utils/converter_benchmark.cpp b/host/utils/converter_benchmark.cpp
new file mode 100644
index 000000000..0f38e8518
--- /dev/null
+++ b/host/utils/converter_benchmark.cpp
@@ -0,0 +1,433 @@
+//
+// Copyright 2015 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/safe_main.hpp>
+#include <uhd/types/dict.hpp>
+#include <uhd/convert.hpp>
+#include <uhd/exception.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <boost/timer.hpp>
+#include <boost/algorithm/string.hpp>
+#include <iostream>
+#include <iomanip>
+#include <map>
+#include <complex>
+
+namespace po = boost::program_options;
+using namespace uhd::convert;
+
+enum buf_init_t {
+ RANDOM, INC
+};
+
+// Convert `sc16_item32_le' -> `sc16'
+// Finds the first _ in format and returns the string
+// until then. Returns the entire string if no _ is found.
+std::string format_to_type(const std::string &format)
+{
+ std::string ret_val = "";
+ for (size_t i = 0; i < format.length(); i++) {
+ if (format[i] == '_') {
+ return ret_val;
+ }
+ ret_val.append(1, format[i]);
+ }
+
+ return ret_val;
+}
+
+void configure_conv(
+ converter::sptr conv,
+ const std::string &in_type,
+ const std::string &out_type
+) {
+ if (in_type == "sc16") {
+ if (out_type == "fc32") {
+ std::cout << "Setting scalar to 32767." << std::endl;
+ conv->set_scalar(32767.);
+ return;
+ }
+ }
+
+ if (in_type == "fc32") {
+ if (out_type == "sc16") {
+ std::cout << "Setting scalar to 32767." << std::endl;
+ conv->set_scalar(32767.);
+ return;
+ }
+ }
+
+ std::cout << "No configuration required." << std::endl;
+}
+
+template <typename T>
+void init_random_vector_complex_float(std::vector<char> &buf_ptr, const size_t n_items)
+{
+ std::complex<T> * const buf = reinterpret_cast<std::complex<T> * const>(&buf_ptr[0]);
+ for (size_t i = 0; i < n_items; i++) {
+ buf[i] = std::complex<T>(
+ T((std::rand()/double(RAND_MAX/2)) - 1),
+ T((std::rand()/double(RAND_MAX/2)) - 1)
+ );
+ }
+}
+
+template <typename T>
+void init_random_vector_complex_int(std::vector<char> &buf_ptr, const size_t n_items)
+{
+ std::complex<T> * const buf = reinterpret_cast<std::complex<T> * const>(&buf_ptr[0]);
+ for (size_t i = 0; i < n_items; i++) {
+ buf[i] = std::complex<T>(T(std::rand()), T(std::rand()));
+ }
+}
+
+template <typename T>
+void init_random_vector_real_int(std::vector<char> &buf_ptr, size_t n_items)
+{
+ T * const buf = reinterpret_cast<T * const>(&buf_ptr[0]);
+ for (size_t i = 0; i < n_items; i++) {
+ buf[i] = T(std::rand());
+ }
+}
+
+// Fill a buffer with increasing numbers
+template <typename T>
+void init_inc_vector(std::vector<char> &buf_ptr, size_t n_items)
+{
+ T * const buf = reinterpret_cast<T * const>(&buf_ptr[0]);
+ for (size_t i = 0; i < n_items; i++) {
+ buf[i] = T(i);
+ }
+}
+
+void init_buffers(
+ std::vector< std::vector<char> > &buf,
+ const std::string &type,
+ size_t bytes_per_item,
+ buf_init_t buf_seed_mode
+) {
+ if (buf.empty()) {
+ return;
+ }
+ size_t n_items = buf[0].size() / bytes_per_item;
+
+ /// Fill with incrementing integers
+ if (buf_seed_mode == INC) {
+ for (size_t i = 0; i < buf.size(); i++) {
+ if (type == "sc8") {
+ init_inc_vector< std::complex<boost::int8_t> >(buf[i], n_items);
+ } else if (type == "sc16") {
+ init_inc_vector< std::complex<boost::int16_t> >(buf[i], n_items);
+ } else if (type == "sc32") {
+ init_inc_vector< std::complex<boost::int32_t> >(buf[i], n_items);
+ } else if (type == "fc32") {
+ init_inc_vector< std::complex<float> >(buf[i], n_items);
+ } else if (type == "fc64") {
+ init_inc_vector< std::complex<double> >(buf[i], n_items);
+ } else if (type == "s8") {
+ init_inc_vector< boost::int8_t >(buf[i], n_items);
+ } else if (type == "s16") {
+ init_inc_vector< boost::int16_t >(buf[i], n_items);
+ } else if (type == "item32") {
+ init_inc_vector< boost::uint32_t >(buf[i], n_items);
+ init_random_vector_real_int<boost::uint32_t>(buf[i], n_items);
+ } else {
+ throw uhd::runtime_error(str(
+ boost::format("Cannot handle data type: %s") % type
+ ));
+ }
+ }
+
+ return;
+ }
+
+ assert(buf_seed_mode == RANDOM);
+
+ /// Fill with random data
+ for (size_t i = 0; i < buf.size(); i++) {
+ if (type == "sc8") {
+ init_random_vector_complex_int<boost::int8_t>(buf[i], n_items);
+ } else if (type == "sc16") {
+ init_random_vector_complex_int<boost::int16_t>(buf[i], n_items);
+ } else if (type == "sc32") {
+ init_random_vector_complex_int<boost::int32_t>(buf[i], n_items);
+ } else if (type == "fc32") {
+ init_random_vector_complex_float<float>(buf[i], n_items);
+ } else if (type == "fc64") {
+ init_random_vector_complex_float<double>(buf[i], n_items);
+ } else if (type == "s8") {
+ init_random_vector_real_int<boost::int8_t>(buf[i], n_items);
+ } else if (type == "s16") {
+ init_random_vector_real_int<boost::int16_t>(buf[i], n_items);
+ } else if (type == "item32") {
+ init_random_vector_real_int<boost::uint32_t>(buf[i], n_items);
+ } else {
+ throw uhd::runtime_error(str(
+ boost::format("Cannot handle data type: %s") % type
+ ));
+ }
+ }
+}
+
+// Returns time elapsed
+double run_benchmark(
+ converter::sptr conv,
+ const std::vector<const void *> &input_buf_refs,
+ const std::vector<void *> &output_buf_refs,
+ size_t n_items,
+ size_t iterations
+) {
+ boost::timer benchmark_timer;
+ for (size_t i = 0; i < iterations; i++) {
+ conv->conv(input_buf_refs, output_buf_refs, n_items);
+ }
+ return benchmark_timer.elapsed();
+}
+
+template <typename T>
+std::string void_ptr_to_hexstring(const void *v_ptr, size_t index)
+{
+ const T *ptr = reinterpret_cast<const T *>(v_ptr);
+ return str(boost::format("%X") % ptr[index]);
+}
+
+std::string item_to_hexstring(
+ const void *v_ptr,
+ size_t index,
+ const std::string &type
+) {
+ if (type == "fc32") {
+ return void_ptr_to_hexstring<uint64_t>(v_ptr, index);
+ }
+ else if (type == "sc16" || type == "item32") {
+ return void_ptr_to_hexstring<uint32_t>(v_ptr, index);
+ }
+ else if (type == "sc8" || type == "s16") {
+ return void_ptr_to_hexstring<uint16_t>(v_ptr, index);
+ }
+ else if (type == "u8") {
+ return void_ptr_to_hexstring<uint8_t>(v_ptr, index);
+ }
+ else {
+ return str(boost::format("<unhandled data type: %s>") % type);
+ }
+}
+
+std::string item_to_string(
+ const void *v_ptr,
+ size_t index,
+ const std::string &type,
+ const bool print_hex
+) {
+ if (print_hex) {
+ return item_to_hexstring(v_ptr, index, type);
+ }
+
+ if (type == "sc16") {
+ const std::complex<boost::int16_t> *ptr = reinterpret_cast<const std::complex<boost::int16_t> *>(v_ptr);
+ return boost::lexical_cast<std::string>(ptr[index]);
+ }
+ else if (type == "sc8") {
+ const std::complex<boost::int8_t> *ptr = reinterpret_cast<const std::complex<boost::int8_t> *>(v_ptr);
+ return boost::lexical_cast<std::string>(ptr[index]);
+ }
+ else if (type == "fc32") {
+ const std::complex<float> *ptr = reinterpret_cast<const std::complex<float> *>(v_ptr);
+ return boost::lexical_cast<std::string>(ptr[index]);
+ }
+ else if (type == "item32") {
+ const boost::uint32_t *ptr = reinterpret_cast<const boost::uint32_t *>(v_ptr);
+ return boost::lexical_cast<std::string>(ptr[index]);
+ }
+ else if (type == "s16") {
+ const boost::int16_t *ptr = reinterpret_cast<const boost::int16_t *>(v_ptr);
+ return boost::lexical_cast<std::string>(ptr[index]);
+ }
+ else {
+ return str(boost::format("<unhandled data type: %s>") % type);
+ }
+}
+
+int UHD_SAFE_MAIN(int argc, char *argv[])
+{
+ std::string in_format, out_format;
+ std::string priorities;
+ std::string seed_mode;
+ priority_type prio = -1, max_prio;
+ size_t iterations, n_samples;
+ size_t n_inputs, n_outputs;
+ buf_init_t buf_seed_mode = RANDOM;
+
+ /// Command line arguments
+ po::options_description desc("Converter benchmark options:");
+ desc.add_options()
+ ("help", "help message")
+ ("in", po::value<std::string>(&in_format), "Input format (e.g. 'sc16')")
+ ("out", po::value<std::string>(&out_format), "Output format (e.g. 'sc16')")
+ ("samples", po::value<size_t>(&n_samples)->default_value(1000000), "Number of samples per iteration")
+ ("iterations", po::value<size_t>(&iterations)->default_value(10000), "Number of iterations per benchmark")
+ ("priorities", po::value<std::string>(&priorities)->default_value("default"), "Converter priorities. Can be 'default', 'all', or a comma-separated list of priorities.")
+ ("max-prio", po::value<priority_type>(&max_prio)->default_value(4), "Largest available priority (advanced feature)")
+ ("n-inputs", po::value<size_t>(&n_inputs)->default_value(1), "Number of input vectors")
+ ("n-outputs", po::value<size_t>(&n_outputs)->default_value(1), "Number of output vectors")
+ ("debug-converter", "Skip benchmark and print conversion results. Implies iterations==1 and will only run on a single converter.")
+ ("seed-mode", po::value<std::string>(&seed_mode)->default_value("random"), "How to initialize the data: random, incremental")
+ ("hex", "When using debug mode, dump memory in hex")
+ ;
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ //print the help message
+ if (vm.count("help")){
+ std::cout << boost::format("UHD Converter Benchmark Tool %s") % desc << std::endl << std::endl;
+ std::cout << " Use this to benchmark or debug converters." << std::endl
+ << " When using as a benchmark tool, it will output the execution time\n"
+ " for every conversion run in CSV format to stdout. Every line between\n"
+ " the output delimiters {{{ }}} is of the format: <PRIO>,<TIME IN MILLISECONDS>\n"
+ " When using for converter debugging, every line is formatted as\n"
+ " <INPUT_VALUE>,<OUTPUT_VALUE>\n" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ // Parse more arguments
+ if (seed_mode == "incremental") {
+ buf_seed_mode = INC;
+ } else if (seed_mode == "random") {
+ buf_seed_mode = RANDOM;
+ } else {
+ std::cout << "Invalid argument: --seed-mode must be either 'incremental' or 'random'." << std::endl;
+ }
+
+ bool debug_mode = bool(vm.count("debug-converter"));
+ if (debug_mode) {
+ iterations = 1;
+ }
+
+ /// Create the converter(s) //////////////////////////////////////////////
+ id_type converter_id;
+ converter_id.input_format = in_format;
+ converter_id.output_format = out_format;
+ converter_id.num_inputs = n_inputs;
+ converter_id.num_outputs = n_outputs;
+ std::cout << "Requested converter format: " << converter_id.to_string()
+ << std::endl;
+ uhd::dict<priority_type, converter::sptr> conv_list;
+ if (priorities == "default" or priorities.empty()) {
+ try {
+ conv_list[prio] = get_converter(converter_id, prio)(); // Can throw a uhd::key_error
+ } catch(const uhd::key_error &e) {
+ std::cout << "No converters found." << std::endl;
+ return EXIT_FAILURE;
+ }
+ } else if (priorities == "all") {
+ for (priority_type i = 0; i < max_prio; i++) {
+ try {
+ // get_converter() returns a factory function, execute that immediately:
+ converter::sptr conv_for_prio = get_converter(converter_id, i)(); // Can throw a uhd::key_error
+ conv_list[i] = conv_for_prio;
+ } catch (...) {
+ continue;
+ }
+ }
+ } else { // Assume that priorities contains a list of prios (e.g. 0,2,3)
+ std::vector<std::string> prios_in_list;
+ boost::split(
+ prios_in_list,
+ priorities,
+ boost::is_any_of(","), // Split at ,
+ boost::token_compress_on // Avoid empty results
+ );
+ BOOST_FOREACH(const std::string &this_prio, prios_in_list) {
+ size_t prio_index = boost::lexical_cast<size_t>(this_prio);
+ converter::sptr conv_for_prio = get_converter(converter_id, prio_index)(); // Can throw a uhd::key_error
+ conv_list[prio_index] = conv_for_prio;
+ }
+ }
+ std::cout << "Found " << conv_list.size() << " converter(s)." << std::endl;
+
+ /// Create input and output buffers ///////////////////////////////////////
+ // First, convert the types to plain types (e.g. sc16_item32_le -> sc16)
+ const std::string in_type = format_to_type(in_format);
+ const std::string out_type = format_to_type(out_format);
+ const size_t in_size = get_bytes_per_item(in_type);
+ const size_t out_size = get_bytes_per_item(out_type);
+ // Create the buffers and fill them with random data & zeros, respectively
+ std::vector< std::vector<char> > input_buffers(n_inputs, std::vector<char>(in_size * n_samples, 0));
+ std::vector< std::vector<char> > output_buffers(n_outputs, std::vector<char>(out_size * n_samples, 0));
+ init_buffers(input_buffers, in_type, in_size, buf_seed_mode);
+ // Create ref vectors for the converter:
+ std::vector<const void *> input_buf_refs(n_inputs);
+ std::vector<void *> output_buf_refs(n_outputs);
+ for (size_t i = 0; i < n_inputs; i++) {
+ input_buf_refs[i] = reinterpret_cast<const void *>(&input_buffers[i][0]);
+ }
+ for (size_t i = 0; i < n_outputs; i++) {
+ output_buf_refs[i] = reinterpret_cast<void *>(&output_buffers[i][0]);
+ }
+
+ /// Final configurations to the converter:
+ std::cout << "Configuring converters:" << std::endl;
+ BOOST_FOREACH(priority_type prio_i, conv_list.keys()) {
+ std::cout << "* [" << prio_i << "]: ";
+ configure_conv(conv_list[prio_i], in_type, out_type);
+ }
+
+ /// Run the benchmark for every converter ////////////////////////////////
+ std::cout << "{{{" << std::endl;
+ if (not debug_mode) {
+ std::cout << "prio,duration_ms,avg_duration_ms,n_samples,iterations" << std::endl;
+ BOOST_FOREACH(priority_type prio_i, conv_list.keys()) {
+ double duration = run_benchmark(
+ conv_list[prio_i],
+ input_buf_refs,
+ output_buf_refs,
+ n_samples,
+ iterations
+ );
+ std::cout << boost::format("%i,%d,%d,%d,%d")
+ % prio_i
+ % (duration * 1000)
+ % (duration * 1000.0 / iterations)
+ % n_samples
+ % iterations
+ << std::endl;
+ }
+ }
+
+ /// Or run debug mode, which runs one conversion and prints the results ////
+ if (debug_mode) {
+ // Only run on the first converter:
+ run_benchmark(
+ conv_list[conv_list.keys().at(0)],
+ input_buf_refs,
+ output_buf_refs,
+ n_samples,
+ iterations
+ );
+ for (size_t i = 0; i < n_samples; i++) {
+ std::cout << item_to_string(input_buf_refs[0], i, in_type, vm.count("hex"))
+ << ";"
+ << item_to_string(reinterpret_cast< const void * >(output_buf_refs[0]), i, out_type, vm.count("hex"))
+ << std::endl;
+ }
+ }
+ std::cout << "}}}" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/host/utils/converter_benchmark.py b/host/utils/converter_benchmark.py
new file mode 100644
index 000000000..c3cab8753
--- /dev/null
+++ b/host/utils/converter_benchmark.py
@@ -0,0 +1,193 @@
+#!/usr/bin/env python
+#
+# Copyright 2015 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/>.
+#
+"""
+Wrap the converter_benchmark tool and produce prettier results.
+"""
+
+from __future__ import print_function
+import argparse
+import csv
+import subprocess
+
+INTRO_SETUP = {
+ 'n_samples': {
+ 'title': 'Samples per iteration',
+ },
+ 'iterations': {
+ 'title': 'Number of iterations'
+ },
+}
+
+TABLE_SETUP = {
+ 'prio': {
+ 'title': 'Priority',
+ },
+ 'duration_ms': {
+ 'title': 'Total Duration (ms)',
+ },
+ 'avg_duration_ms': {
+ 'title': 'Avg. Duration (ms)',
+ },
+}
+
+def run_benchmark(args):
+ """ Run the tool with the given arguments, return the section in the {{{ }}} brackets """
+ call_args = ['./converter_benchmark',]
+ for k, v in args.__dict__.iteritems():
+ k = k.replace('_', '-')
+ if v is None:
+ continue
+ if k in ('debug-converter', 'hex'):
+ if v:
+ call_args.append('--{0}'.format(k))
+ continue
+ call_args.append('--{0}'.format(k))
+ call_args.append(str(v))
+ print(call_args)
+ try:
+ output = subprocess.check_output(call_args)
+ except subprocess.CalledProcessError as ex:
+ print(ex.output)
+ exit(ex.returncode)
+ header_out, csv_output = output.split('{{{', 1)
+ csv_output = csv_output.split('}}}', 1)
+ assert len(csv_output) == 2 and csv_output[1].strip() == ''
+ return header_out, csv_output[0]
+
+def print_stats_table(args, csv_output):
+ """
+ Print stats.
+ """
+ reader = csv.reader(csv_output.strip().split('\n'), delimiter=',')
+ title_row = reader.next()
+ row_widths = [0,] * len(TABLE_SETUP)
+ for idx, row in enumerate(reader):
+ if idx == 0:
+ # Print intro:
+ for k, v in INTRO_SETUP.iteritems():
+ print("{title}: {value}".format(
+ title=v['title'],
+ value=row[title_row.index(k)],
+ ))
+ print("")
+ # Print table header
+ for idx, item in enumerate(TABLE_SETUP):
+ print(" {title} ".format(title=TABLE_SETUP[item]['title']), end='')
+ row_widths[idx] = len(TABLE_SETUP[item]['title'])
+ if idx < len(TABLE_SETUP) - 1:
+ print("|", end='')
+ print("")
+ for idx, item in enumerate(TABLE_SETUP):
+ print("-" * (row_widths[idx] + 2), end='')
+ if idx < len(TABLE_SETUP) - 1:
+ print("+", end='')
+ print("")
+ # Print actual row data
+ for idx, item in enumerate(TABLE_SETUP):
+ format_str = " {{item:>{n}}} ".format(n=row_widths[idx])
+ print(format_str.format(item=row[title_row.index(item)]), end='')
+ if idx < len(TABLE_SETUP) - 1:
+ print("|", end='')
+ print("")
+
+def print_debug_table(args, csv_output):
+ """
+ Print debug output.
+ """
+ reader = csv.reader(csv_output.strip().split('\n'), delimiter=';')
+ print_widths_hex = {
+ 'u8': 2,
+ 'sc16': 8,
+ 'fc32': 16,
+ 's16': 4,
+ }
+ if args.hex:
+ format_str = "{{0[0]:0>{n_in}}} => {{0[1]:0>{n_out}}}".format(
+ n_in=print_widths_hex[getattr(args, 'in').split('_', 1)[0]],
+ n_out=print_widths_hex[args.out.split('_', 1)[0]]
+ )
+ else:
+ format_str = "{0[0]}\t=>\t{0[1]}"
+ for row in reader:
+ print(format_str.format(row))
+
+def setup_argparse():
+ """ Configure arg parser. """
+ parser = argparse.ArgumentParser(
+ description="UHD Converter Benchmark + Debugging Utility.",
+ )
+ parser.add_argument(
+ "-i", "--in", required=True,
+ help="Input format (e.g. 'sc16')"
+ )
+ parser.add_argument(
+ "-o", "--out", required=True,
+ help="Output format (e.g. 'sc16')"
+ )
+ parser.add_argument(
+ "-s", "--samples", type=int,
+ help="Number of samples per iteration"
+ )
+ parser.add_argument(
+ "-N", "--iterations", type=int,
+ help="Number of iterations per benchmark",
+ )
+ parser.add_argument(
+ "-p", "--priorities",
+ help="Converter priorities. Can be 'default', 'all', or a comma-separated list of priorities.",
+ )
+ parser.add_argument(
+ "--max-prio", type=int,
+ help="Largest available priority (advanced feature)",
+ )
+ parser.add_argument(
+ "--n-inputs", type=int,
+ help="Number of input vectors",
+ )
+ parser.add_argument(
+ "--n-outputs", type=int,
+ help="Number of output vectors",
+ )
+ parser.add_argument(
+ "--seed-mode", choices=('random', 'incremental'),
+ help="How to initialize the data: random, incremental",
+ )
+ parser.add_argument(
+ "--debug-converter", action='store_true',
+ help="Skip benchmark and print conversion results. Implies iterations==1 and will only run on a single converter.",
+ )
+ parser.add_argument(
+ "--hex", action='store_true',
+ help="In debug mode, display data as hex values.",
+ )
+ return parser
+
+def main():
+ """ Go, go, go! """
+ args = setup_argparse().parse_args()
+ print("Running converter benchmark...")
+ header_out, csv_output = run_benchmark(args)
+ print(header_out)
+ if args.debug_converter:
+ print_debug_table(args, csv_output)
+ else:
+ print_stats_table(args, csv_output)
+
+if __name__ == "__main__":
+ main()
+
diff --git a/host/utils/fx2_init_eeprom.cpp b/host/utils/fx2_init_eeprom.cpp
index 5711b73e0..cf7fb2de2 100644
--- a/host/utils/fx2_init_eeprom.cpp
+++ b/host/utils/fx2_init_eeprom.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010,2014 Ettus Research LLC
+// Copyright 2010,2014,2016 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -20,8 +20,17 @@
#include <uhd/property_tree.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
+#include <boost/algorithm/string/predicate.hpp>
#include <iostream>
-#include <cstdlib>
+//#include <cstdlib>
+#ifdef UHD_PLATFORM_LINUX
+#include <fstream>
+#include <unistd.h> // syscall constants
+#include <fcntl.h> // O_NONBLOCK
+#include <sys/syscall.h>
+#include <cerrno>
+#include <cstring> // for std::strerror
+#endif //UHD_PLATFORM_LINUX
const std::string FX2_VENDOR_ID("0x04b4");
const std::string FX2_PRODUCT_ID("0x8613");
@@ -49,10 +58,22 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
return EXIT_FAILURE;
}
- //cant find a uninitialized usrp with this mystery module in the way...
- if (std::system("/sbin/rmmod usbtest") != 0){
- std::cerr << "Did not rmmod usbtest, this may be ok..." << std::endl;
+#ifdef UHD_PLATFORM_LINUX
+ //can't find an uninitialized usrp with this mystery usbtest in the way...
+ std::string module("usbtest");
+ std::ifstream modules("/proc/modules");
+ bool module_found = false;
+ std::string module_line;
+ while(std::getline(modules, module_line) && (!module_found)) {
+ module_found = boost::starts_with(module_line, module);
}
+ if(module_found) {
+ std::cout << boost::format("Found the '%s' module. Unloading it.\n" ) % module;
+ int fail = syscall(__NR_delete_module, module.c_str(), O_NONBLOCK);
+ if(fail)
+ std::cerr << ( boost::format("Removing the '%s' module failed with error '%s'.\n") % module % std::strerror(errno) );
+ }
+#endif //UHD_PLATFORM_LINUX
//load the options into the address
uhd::device_addr_t device_addr;
diff --git a/host/utils/query_gpsdo_sensors.cpp b/host/utils/query_gpsdo_sensors.cpp
index 3b98a634c..4c17c6044 100644
--- a/host/utils/query_gpsdo_sensors.cpp
+++ b/host/utils/query_gpsdo_sensors.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2012,2014 Ettus Research LLC
+// Copyright 2012,2014,2015 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -38,7 +38,6 @@ void print_notes(void) {
std::cout << boost::format("**************************************Helpful Notes on Clock/PPS Selection**************************************\n");
std::cout << boost::format("As you can see, the default 10 MHz Reference and 1 PPS signals are now from the GPSDO.\n");
std::cout << boost::format("If you would like to use the internal reference(TCXO) in other applications, you must configure that explicitly.\n");
- std::cout << boost::format("You can no longer select the external SMAs for 10 MHz or 1 PPS signaling.\n");
std::cout << boost::format("****************************************************************************************************************\n");
}
@@ -51,7 +50,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
po::options_description desc("Allowed options");
desc.add_options()
("help", "help message")
- ("args", po::value<std::string>(&args)->default_value(""), "Specify a single USRP.")
+ ("args", po::value<std::string>(&args)->default_value(""), "Device address arguments specifying a single USRP")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
@@ -59,8 +58,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//Print the help message
if (vm.count("help")) {
- std::cout << boost::format("Query GPSDO Sensors %s") % desc << std::endl;
- return EXIT_FAILURE;
+ std::cout << boost::format("Query GPSDO Sensors, try to lock the reference oscillator to the GPS disciplined clock, and set the device time to GPS time")
+ << std::endl
+ << std::endl
+ << desc;
+ return EXIT_FAILURE;
}
//Create a USRP device
@@ -68,9 +70,6 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
std::cout << boost::format("Using Device: %s\n") % usrp->get_pp_string();
- print_notes();
-
-
//Verify GPS sensors are present (i.e. EEPROM has been burnt)
std::vector<std::string> sensor_names = usrp->get_mboard_sensor_names(0);
@@ -82,38 +81,96 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
exit(EXIT_FAILURE);
}
+ // Explicitly set time source to gpsdo
+ boost::this_thread::sleep(boost::posix_time::seconds(1));
+ try {
+ usrp->set_time_source("gpsdo");
+ } catch (uhd::value_error &e) {
+ std::cout << "could not set the time source to \"gpsdo\"; error was:" <<std::endl;
+ std::cout << e.what() << std::endl;
+ std::cout << "trying \"external\"..." <<std::endl;
+ try {
+ usrp->set_time_source("external");
+ } catch (uhd::value_error &e) {
+ std::cout << "\"external\" failed, too." << std::endl;
+ }
+ }
+ std::cout<< std::endl << "Time source is now " << usrp->get_time_source(0) << std::endl;
+
//Check for GPS lock
uhd::sensor_value_t gps_locked = usrp->get_mboard_sensor("gps_locked",0);
if(not gps_locked.to_bool()) {
- std::cout << boost::format("\nGPS does not have lock. Wait a few minutes and try again.\n");
- std::cout << boost::format("NMEA strings and device time may not be accurate until lock is achieved.\n\n");
- } else
- std::cout << boost::format("GPS Locked\n");
+ std::cout << boost::format("\nGPS does not have lock. Wait a few minutes and try again.\n");
+ std::cout << boost::format("NMEA strings and device time may not be accurate until lock is achieved.\n\n");
+ } else {
+ std::cout << boost::format("GPS Locked");
+ }
+
+ std::cout << "\nSetting the reference clock source to \"gpsdo\"...\n";
+ try {
+ usrp->set_clock_source("gpsdo");
+ } catch (uhd::value_error &e) {
+ std::cout << "could not set the clock source to \"gpsdo\"; error was:" <<std::endl;
+ std::cout << e.what() << std::endl;
+ std::cout << "trying \"external\"..." <<std::endl;
+ try{
+ usrp->set_clock_source("external");
+ } catch (uhd::value_error &e) {
+ std::cout << "\"external\" failed, too." << std::endl;
+ }
+ }
+ std::cout<< std::endl << "Clock source is now " << usrp->get_clock_source(0) << std::endl;
+
+ print_notes();
+
//Check for 10 MHz lock
if(std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end()) {
- uhd::sensor_value_t gps_locked = usrp->get_mboard_sensor("ref_locked",0);
- if(not gps_locked.to_bool()) {
- std::cout << boost::format("USRP NOT Locked to GPSDO 10 MHz Reference.\n");
- std::cout << boost::format("Double check installation instructions (N2X0/E1X0 only): https://www.ettus.com/content/files/gpsdo-kit_4.pdf\n\n");
- } else
- std::cout << boost::format("USRP Locked to GPSDO 10 MHz Reference.\n");
- }else
- std::cout << boost::format("ref_locked sensor not present on this board.\n");
-
- // Explicitly set time source to gpsdo
- usrp->set_time_source("gpsdo");
+ uhd::sensor_value_t gps_locked = usrp->get_mboard_sensor("ref_locked",0);
+ if(not gps_locked.to_bool()) {
+ std::cout << boost::format("USRP NOT Locked to GPSDO 10 MHz Reference.\n");
+ std::cout << boost::format("Double check installation instructions (N2X0/E1X0 only): https://www.ettus.com/content/files/gpsdo-kit_4.pdf\n\n");
+ std::cout << boost::format("Locking the internal reference to the GPSDO might take a second to reach stability. Retrying in 10 s...\n\n");
+ boost::this_thread::sleep(boost::posix_time::seconds(10));
+ }
+ if(usrp->get_mboard_sensor("ref_locked",0).to_bool()) {
+ std::cout << boost::format("USRP Locked to GPSDO 10 MHz Reference.\n");
+ }
+ } else {
+ std::cout << boost::format("ref_locked sensor not present on this board.\n");
+ }
//Check PPS and compare UHD device time to GPS time
boost::this_thread::sleep(boost::posix_time::seconds(1));
uhd::sensor_value_t gps_time = usrp->get_mboard_sensor("gps_time");
- const time_t pc_clock_time = time(NULL);
- const uhd::time_spec_t last_pps_time = usrp->get_time_last_pps();
+ uhd::time_spec_t last_pps_time = usrp->get_time_last_pps();
+
+ //we only care about the full seconds
+ signed gps_seconds = gps_time.to_int();
+ long long pps_seconds = last_pps_time.to_ticks(1.0);
+
+ if(pps_seconds != gps_seconds) {
+ std::cout << boost::format("\nGPS and UHD Device time are NOT aligned;\nlast_pps: %ld vs gps: %ld. Trying to set the device time to GPS time...")
+ % pps_seconds % gps_seconds
+ << std::endl;
+ //full next after next second
+ uhd::time_spec_t next_pps_time(gps_seconds + 2.0);
+ //instruct the USRP to wait for the next PPS edge, then set the new time on the following PPS
+ usrp->set_time_unknown_pps(next_pps_time);
+ //allow some time to make sure the PPS has come…
+ boost::this_thread::sleep(boost::posix_time::seconds(1.1));
+ //…then ask
+ gps_seconds = usrp->get_mboard_sensor("gps_time").to_int();
+ pps_seconds = usrp->get_time_last_pps().to_ticks(1.0);
+ }
- if (last_pps_time.to_ticks(1.0) == gps_time.to_int()) {
+ std::cout << boost::format("last_pps: %ld vs gps: %ld.")
+ % pps_seconds % gps_seconds
+ << std::endl;
+ if (pps_seconds == gps_seconds) {
std::cout << boost::format("GPS and UHD Device time are aligned.\n");
} else {
- std::cout << boost::format("\nGPS and UHD Device time are NOT aligned last_pps: %ld vs gps: %ld. Try re-running the program. Double check 1 PPS connection from GPSDO.\n\n") % last_pps_time.to_ticks(1.0) % gps_time.to_int() << std::endl;
+ std::cout << boost::format("Could not align UHD Device time to GPS time. Giving up.\n");
}
//print NMEA strings
@@ -121,12 +178,14 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::sensor_value_t gga_string = usrp->get_mboard_sensor("gps_gpgga");
uhd::sensor_value_t rmc_string = usrp->get_mboard_sensor("gps_gprmc");
std::cout << boost::format("Printing available NMEA strings:\n");
- std::cout << boost::format("%s\n%s\n%s\n") % gga_string.to_pp_string() % rmc_string.to_pp_string() % gps_time.to_pp_string();
- } catch (std::exception &) {
+ std::cout << boost::format("%s\n%s\n") % gga_string.to_pp_string() % rmc_string.to_pp_string();
+ } catch (uhd::lookup_error &e) {
std::cout << "NMEA strings not implemented for this device." << std::endl;
}
- std::cout << boost::format("UHD Device time: %.0f seconds\n") % (last_pps_time.get_real_secs());
- std::cout << boost::format("PC Clock time: %.0f seconds\n") % pc_clock_time;
+ std::cout << boost::format("GPS Epoch time at last PPS: %.5f seconds\n") % usrp->get_mboard_sensor("gps_time").to_real();
+ std::cout << boost::format("UHD Device time last PPS: %.5f seconds\n") % (usrp->get_time_last_pps().get_real_secs());
+ std::cout << boost::format("UHD Device time right now: %.5f seconds\n") % (usrp->get_time_now().get_real_secs());
+ std::cout << boost::format("PC Clock time: %.5f seconds\n") % time(NULL);
//finished
std::cout << boost::format("\nDone!\n\n");
diff --git a/host/utils/uhd_config_info.cpp b/host/utils/uhd_config_info.cpp
new file mode 100644
index 000000000..4279c325d
--- /dev/null
+++ b/host/utils/uhd_config_info.cpp
@@ -0,0 +1,89 @@
+//
+// Copyright 2015 National Instruments Corp.
+//
+// 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/build_info.hpp>
+#include <uhd/version.hpp>
+#include <uhd/utils/safe_main.hpp>
+
+#include <boost/format.hpp>
+#include <boost/program_options.hpp>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char* argv[]) {
+ // Program Options
+ po::options_description desc("Allowed Options");
+ desc.add_options()
+ ("build-date", "Print build date")
+ ("c-compiler", "Print C compiler")
+ ("cxx-compiler", "Print C++ compiler")
+ ("c-flags", "Print C compiler flags")
+ ("cxx-flags", "Print C++ compiler flags")
+ ("enabled-components", "Print built-time enabled components")
+ ("install-prefix", "Print install prefix")
+ ("libusb-version", "Print libusb version")
+ ("print-all", "Print everything")
+ ("version", "Print this UHD build's version")
+ ("help", "Print help message")
+ ;
+
+ 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") > 0) {
+ std::cout << boost::format("UHD Config Info - %s") % desc << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ bool print_all = (vm.count("print-all") > 0);
+
+ if(vm.count("version") > 0 or print_all) {
+ std::cout << "UHD " << uhd::get_version_string() << std::endl;
+ }
+ if(vm.count("build-date") > 0 or print_all) {
+ std::cout << "Build date: " << uhd::build_info::build_date() << std::endl;
+ }
+ if(vm.count("c-compiler") > 0 or print_all) {
+ std::cout << "C compiler: " << uhd::build_info::c_compiler() << std::endl;
+ }
+ if(vm.count("cxx-compiler") > 0 or print_all) {
+ std::cout << "C++ compiler: " << uhd::build_info::cxx_compiler() << std::endl;
+ }
+ if(vm.count("c-flags") > 0 or print_all) {
+ std::cout << "C flags: " << uhd::build_info::c_flags() << std::endl;
+ }
+ if(vm.count("cxx-flags") > 0 or print_all) {
+ std::cout << "C++ flags: " << uhd::build_info::cxx_flags() << std::endl;
+ }
+ if(vm.count("enabled-components") > 0 or print_all) {
+ std::cout << "Enabled components: " << uhd::build_info::enabled_components() << std::endl;
+ }
+ if(vm.count("install-prefix") > 0 or print_all) {
+ std::cout << "Install prefix: " << uhd::build_info::install_prefix() << std::endl;
+ }
+ if(vm.count("boost-version") > 0 or print_all) {
+ std::cout << "Boost version: " << uhd::build_info::boost_version() << std::endl;
+ }
+ if(vm.count("libusb-version") > 0 or print_all) {
+ std::string _libusb_version = uhd::build_info::libusb_version();
+ std::cout << "Libusb version: " << (_libusb_version.empty() ? "N/A" : _libusb_version) << std::endl;
+ }
+
+ return EXIT_SUCCESS;
+}