aboutsummaryrefslogtreecommitdiffstats
path: root/host/examples
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2022-04-14 16:28:27 +0200
committerAaron Rossetto <aaron.rossetto@ni.com>2022-06-10 13:24:05 -0500
commit76156b15b7fa5636281a4139c2c856da0a7b05c5 (patch)
tree28a697cc97a5b9570e926e80facc0a513705e557 /host/examples
parentf2043bc60bfe841bbb73b5f5dd38813592c9536b (diff)
downloaduhd-76156b15b7fa5636281a4139c2c856da0a7b05c5.tar.gz
uhd-76156b15b7fa5636281a4139c2c856da0a7b05c5.tar.bz2
uhd-76156b15b7fa5636281a4139c2c856da0a7b05c5.zip
examples: gpio: Refactor example
The example had organically grown and was getting hard to read, and also had some known issues. Summary of fixes: - Default GPIO bank and connector are now derived from the device. This allows this example to pass without throwing an exception on E3xx and X4xx series when using default arguments. - The bitbang test is moved into its own code section, to make the rest more readable. - We move all the streamer-related code into a helper struct - Some repetitive parts of the code are moved into their own functions - The argument --require-loopback is added, which will fail tests if GPIO pins are not correctly looped back externally - --list-banks is renamed to --list_banks for consistency
Diffstat (limited to 'host/examples')
-rw-r--r--host/examples/gpio.cpp654
1 files changed, 368 insertions, 286 deletions
diff --git a/host/examples/gpio.cpp b/host/examples/gpio.cpp
index 417234881..730cf905f 100644
--- a/host/examples/gpio.cpp
+++ b/host/examples/gpio.cpp
@@ -8,12 +8,12 @@
// Example for GPIO testing and bit banging.
//
-// This example was originally designed to test the 11 bit wide front panel
+// This example was originally designed to test the 12 bit wide front panel
// GPIO on the X300 series and has since been adapted to work with any GPIO
// bank on any USRP and provide optional bit banging. Please excuse the
// clutter. Also, there is no current way to detect the width of the
// specified GPIO bank, so the user must specify the width with the --bits
-// flag if more than 11 bits.
+// flag if more than 12 bits.
//
// GPIO Testing:
// For testing, GPIO bits are set as follows:
@@ -72,13 +72,13 @@
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/thread.hpp>
-#include <stdint.h>
-#include <stdlib.h>
#include <boost/format.hpp>
#include <boost/program_options.hpp>
#include <boost/tokenizer.hpp>
#include <chrono>
#include <csignal>
+#include <cstdint>
+#include <cstdlib>
#include <iostream>
#include <thread>
@@ -87,11 +87,11 @@ static const std::string GPIO_DEFAULT_OTW_FORMAT = "sc16";
static const double GPIO_DEFAULT_RX_RATE = 500e3;
static const double GPIO_DEFAULT_TX_RATE = 500e3;
static const double GPIO_DEFAULT_DWELL_TIME = 2.0;
-static const std::string GPIO_DEFAULT_GPIO = "FP0";
-static const size_t GPIO_DEFAULT_NUM_BITS = 11;
+static const size_t GPIO_DEFAULT_NUM_BITS = 12;
static const std::string GPIO_DEFAULT_CTRL = "0x0"; // all as user controlled
static const std::string GPIO_DEFAULT_DDR = "0x0"; // all as inputs
static const std::string GPIO_DEFAULT_OUT = "0x0";
+constexpr size_t GPIO_MIN_NUM_BITS = 5;
static inline uint32_t GPIO_BIT(const size_t x)
{
@@ -131,7 +131,7 @@ void output_reg_values(const std::string& bank,
for (const auto& attr : attrs) {
const uint32_t gpio_bits = uint32_t(usrp->get_gpio_attr(bank, attr));
std::cout << (boost::format("%10s:%s") % attr
- % to_bit_string(gpio_bits, num_bits))
+ % to_bit_string(gpio_bits, num_bits))
<< std::endl;
}
@@ -150,15 +150,207 @@ void output_reg_values(const std::string& bank,
}
}
+
+bool check_rb_values(const uint32_t rb,
+ uint32_t expected,
+ const uint32_t num_bits,
+ const uint32_t loopback_num_bits)
+{
+ if (loopback_num_bits) {
+ const uint32_t lb_mask = (1 << loopback_num_bits) - 1;
+ expected |= ((expected & lb_mask) << GPIO_MIN_NUM_BITS);
+ }
+ if ((rb & expected) != expected) {
+ std::cout << "fail:" << std::endl;
+ for (size_t bit = 0; bit < num_bits; bit++) {
+ if ((expected & GPIO_BIT(bit)) && ((rb & GPIO_BIT(bit)) == 0)) {
+ std::cout << "Bit " << bit << " should be set, but is not. ";
+ if (loopback_num_bits && bit >= GPIO_MIN_NUM_BITS) {
+ std::cout << "Are GPIO pins correctly looped back?";
+ }
+ std::cout << std::endl;
+ }
+ }
+ return false;
+ }
+ std::cout << "pass:" << std::endl;
+ return true;
+}
+
+
+void run_bitbang_test(uhd::usrp::multi_usrp::sptr usrp,
+ const std::string gpio_bank,
+ const std::string port,
+ const uint32_t ddr,
+ const uint32_t out,
+ const uint32_t mask,
+ const uint32_t num_bits,
+ const std::chrono::milliseconds dwell_time)
+{
+ // Set all pins to "GPIO", and DDR/OUT to whatever the user requested
+ usrp->set_gpio_attr(gpio_bank, "CTRL", 0, mask);
+ usrp->set_gpio_attr(gpio_bank, "DDR", ddr, mask);
+ usrp->set_gpio_attr(gpio_bank, "OUT", out, mask);
+
+ // print out initial state of GPIO
+ std::cout << "\nConfigured GPIO values:" << std::endl;
+ output_reg_values(gpio_bank, port, usrp, num_bits);
+ std::cout << std::endl;
+ std::signal(SIGINT, &sig_int_handler);
+
+ while (not stop_signal_called) {
+ // dwell and continuously read back GPIO values
+ auto stop_time = std::chrono::steady_clock::now() + dwell_time;
+ while (not stop_signal_called and std::chrono::steady_clock::now() < stop_time) {
+ std::cout << "\rREADBACK: "
+ << to_bit_string(
+ usrp->get_gpio_attr(gpio_bank, "READBACK"), num_bits);
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ std::cout << std::endl;
+ }
+}
+
+
+struct stream_helper_type
+{
+ stream_helper_type(uhd::usrp::multi_usrp::sptr usrp,
+ double rx_rate,
+ double tx_rate,
+ const std::string& cpu,
+ const std::string& otw,
+ const std::chrono::milliseconds dwell_time)
+ : rx_args(cpu, otw), tx_args(cpu, otw), dwell_time(dwell_time)
+ {
+ rx_cmd.stream_now = true;
+
+ if (usrp->get_rx_num_channels()) {
+ rx_stream = usrp->get_rx_stream(rx_args);
+ usrp->set_rx_rate(rx_rate);
+ }
+ if (usrp->get_tx_num_channels()) {
+ tx_stream = usrp->get_tx_stream(tx_args);
+ usrp->set_tx_rate(tx_rate);
+ }
+
+ const size_t rx_spp = rx_stream ? rx_stream->get_max_num_samps() : 0;
+ const size_t tx_spp = tx_stream ? tx_stream->get_max_num_samps() : 0;
+ nsamps_per_buff = std::max(rx_spp, tx_spp);
+
+ if (rx_stream) {
+ rx_buff.resize(nsamps_per_buff * uhd::convert::get_bytes_per_item(cpu));
+ for (size_t ch = 0; ch < rx_stream->get_num_channels(); ch++) {
+ rx_buffs.push_back(&rx_buff.front()); // same buffer for each channel
+ }
+ }
+ if (tx_stream) {
+ tx_buff.resize(nsamps_per_buff * uhd::convert::get_bytes_per_item(cpu));
+ for (size_t ch = 0; ch < tx_stream->get_num_channels(); ch++)
+ tx_buffs.push_back(&tx_buff.front()); // same buffer for each channel
+ }
+
+ tx_md.has_time_spec = false;
+ tx_md.start_of_burst = true;
+ }
+
+ void start_stream(bool tx, bool rx)
+ {
+ if (tx && rx) {
+ rx_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
+ rx_stream->issue_stream_cmd(rx_cmd);
+ tx_md.start_of_burst = true;
+ tx_md.end_of_burst = false;
+ auto stop_time = std::chrono::steady_clock::now() + dwell_time;
+ while (
+ not stop_signal_called and std::chrono::steady_clock::now() < stop_time) {
+ try {
+ tx_stream->send(tx_buffs, nsamps_per_buff, tx_md, timeout);
+ tx_md.start_of_burst = false;
+ rx_stream->recv(rx_buffs, nsamps_per_buff, rx_md, timeout);
+ } catch (...) {
+ }
+ }
+ return;
+ }
+
+ if (tx) {
+ auto stop_time = std::chrono::steady_clock::now() + dwell_time;
+ tx_md.start_of_burst = true;
+ tx_md.end_of_burst = false;
+ while (
+ not stop_signal_called and std::chrono::steady_clock::now() < stop_time) {
+ try {
+ tx_stream->send(tx_buffs, nsamps_per_buff, tx_md, timeout);
+ tx_md.start_of_burst = false;
+ } catch (...) {
+ }
+ }
+ }
+
+ if (rx) {
+ rx_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
+ rx_stream->issue_stream_cmd(rx_cmd);
+ auto stop_time = std::chrono::steady_clock::now() + dwell_time;
+ while (
+ not stop_signal_called and std::chrono::steady_clock::now() < stop_time) {
+ try {
+ rx_stream->recv(rx_buffs, nsamps_per_buff, rx_md, timeout);
+ } catch (...) {
+ }
+ }
+ }
+ }
+
+ void stop_stream(bool tx, bool rx)
+ {
+ if (tx) {
+ tx_md.end_of_burst = true;
+ try {
+ tx_stream->send(tx_buffs, nsamps_per_buff, tx_md, timeout);
+ } catch (...) {
+ }
+ }
+ if (rx) {
+ rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
+ // clear out any data left in the rx stream
+ try {
+ rx_stream->recv(rx_buffs, nsamps_per_buff, rx_md, timeout);
+ } catch (...) {
+ }
+ }
+ }
+
+ uhd::stream_args_t rx_args;
+ uhd::stream_args_t tx_args;
+ uhd::rx_streamer::sptr rx_stream;
+ uhd::tx_streamer::sptr tx_stream;
+ uhd::stream_cmd_t rx_cmd{uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS};
+
+ size_t nsamps_per_buff;
+ std::vector<char> rx_buff;
+ std::vector<char> tx_buff;
+ std::vector<void*> rx_buffs, tx_buffs;
+
+ uhd::rx_metadata_t rx_md;
+ uhd::tx_metadata_t tx_md;
+
+ double timeout = 0.01;
+
+ const std::chrono::milliseconds dwell_time;
+};
+
+
int UHD_SAFE_MAIN(int argc, char* argv[])
{
// variables to be set by po
std::string args;
std::string cpu, otw;
double rx_rate, tx_rate, dwell;
- std::string gpio;
+ // This is the argument for set_gpio_attr(), not the connector name:
+ std::string gpio_bank;
std::string port;
size_t num_bits;
+ uint32_t loopback_num_bits = 0;
std::string src_str;
std::string ctrl_str;
std::string ddr_str;
@@ -175,16 +367,17 @@ int UHD_SAFE_MAIN(int argc, char* argv[])
("tx_subdev_spec", po::value<std::string>(&tx_subdev_spec)->default_value(""), "A:0, B:0, or A:0 B:0")
("rx_subdev_spec", po::value<std::string>(&rx_subdev_spec)->default_value(""), "A:0, B:0, or A:0 B:0")
("repeat", "repeat loop until Ctrl-C is pressed")
- ("list-banks", "print list of banks before running tests")
+ ("list_banks", "print list of banks before running tests")
("cpu", po::value<std::string>(&cpu)->default_value(GPIO_DEFAULT_CPU_FORMAT), "cpu data format")
("otw", po::value<std::string>(&otw)->default_value(GPIO_DEFAULT_OTW_FORMAT), "over the wire data format")
("rx_rate", po::value<double>(&rx_rate)->default_value(GPIO_DEFAULT_RX_RATE), "rx sample rate")
("tx_rate", po::value<double>(&tx_rate)->default_value(GPIO_DEFAULT_TX_RATE), "tx sample rate")
("dwell", po::value<double>(&dwell)->default_value(GPIO_DEFAULT_DWELL_TIME), "dwell time in seconds for each test case")
- ("bank", po::value<std::string>(&gpio)->default_value(GPIO_DEFAULT_GPIO), "name of gpio bank")
- ("port", po::value<std::string>(&port)->default_value(""), "name of gpio port. If not specified, defaults to the GPIO bank")
+ ("bank", po::value<std::string>(&gpio_bank)->default_value(""), "name of gpio bank (defaults to first bank in list)")
+ ("port", po::value<std::string>(&port)->default_value(""), "name of gpio port (source bank). If not specified, defaults to the first bank")
("bits", po::value<size_t>(&num_bits)->default_value(GPIO_DEFAULT_NUM_BITS), "number of bits in gpio bank")
("bitbang", "single test case where user sets values for CTRL, DDR, and OUT registers")
+ ("check_loopback", "check that lower half of pins is looped back onto upper half")
("src", po::value<std::string>(&src_str), "GPIO SRC reg value")
("ddr", po::value<std::string>(&ddr_str)->default_value(GPIO_DEFAULT_DDR), "GPIO DDR reg value")
("out", po::value<std::string>(&out_str)->default_value(GPIO_DEFAULT_OUT), "GPIO OUT reg value")
@@ -194,48 +387,74 @@ int UHD_SAFE_MAIN(int argc, char* argv[])
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
+ /*** Sanity-check arguments **********************************************/
// print the help message
if (vm.count("help")) {
- std::cout << boost::format("gpio %s") % desc << std::endl;
- return ~0;
+ std::cout << "gpio " << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+ if (vm.count("check_loopback")) {
+ // For a proper test, we need at least 5 pins (4xATR + 1xGPIO). That
+ // means we also want at *most* 5 pins to be looped back for this test.
+ if (num_bits <= GPIO_MIN_NUM_BITS) {
+ loopback_num_bits = 0;
+ } else {
+ loopback_num_bits = std::min(GPIO_MIN_NUM_BITS, num_bits - GPIO_MIN_NUM_BITS);
+ }
+ std::cout << "Checking external GPIO loopback! Expecting the following external "
+ "connections: "
+ << std::endl;
+ for (size_t gpio = 0; gpio + loopback_num_bits < num_bits; ++gpio) {
+ std::cout << "GPIO " << gpio << " --> " << gpio + loopback_num_bits
+ << std::endl;
+ }
}
+ const auto dwell_time = std::chrono::milliseconds(static_cast<int64_t>(dwell * 1000));
+
+ /*** Set up USRP device and GPIO banks ************************************/
+ std::cout << std::endl;
+ std::cout << "Creating the usrp device with: " << args << "..." << std::endl;
+ auto usrp = uhd::usrp::multi_usrp::make(args);
+ std::cout << "Using Device: " << usrp->get_pp_string() << std::endl;
// Handle if the port is unspecified
if (port.empty()) {
- port = gpio;
+ port = usrp->get_gpio_src_banks(0).front();
}
+ if (gpio_bank.empty()) {
+ gpio_bank = usrp->get_gpio_banks(0).front();
+ }
+ std::cout << "Using GPIO connector: " << port << std::endl;
- // create a usrp device
- std::cout << std::endl;
- std::cout << boost::format("Creating the usrp device with: %s...") % args
- << std::endl;
- uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
- std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
-
- if (vm.count("list-banks")) {
+ if (vm.count("list_banks")) {
std::cout << "Available GPIO banks: " << std::endl;
auto banks = usrp->get_gpio_banks(0);
for (auto& bank : banks) {
std::cout << "* " << bank << std::endl;
}
}
- std::cout << "Using GPIO bank: " << gpio << std::endl;
-
+ std::cout << "Using GPIO bank: " << gpio_bank << std::endl;
// subdev spec
if (!tx_subdev_spec.empty())
usrp->set_tx_subdev_spec(tx_subdev_spec);
if (!rx_subdev_spec.empty())
usrp->set_rx_subdev_spec(rx_subdev_spec);
- std::cout << boost::format(" rx_subdev_spec: %s")
- % usrp->get_rx_subdev_spec(0).to_string()
+ std::cout << " rx_subdev_spec: " << usrp->get_rx_subdev_spec(0).to_string()
<< std::endl;
- std::cout << boost::format(" tx_subdev_spec: %s")
- % usrp->get_tx_subdev_spec(0).to_string()
+ std::cout << " tx_subdev_spec: " << usrp->get_tx_subdev_spec(0).to_string()
<< std::endl;
+ // set GPIO driver source
+ if (vm.count("src")) {
+ std::vector<std::string> gpio_src;
+ typedef boost::char_separator<char> separator;
+ boost::tokenizer<separator> tokens(src_str, separator(" "));
+ std::copy(tokens.begin(), tokens.end(), std::back_inserter(gpio_src));
+ usrp->set_gpio_src(port, gpio_src);
+ }
// print out initial unconfigured state of GPIO
std::cout << "Initial GPIO values:" << std::endl;
- output_reg_values(gpio, port, usrp, num_bits);
+ output_reg_values(gpio_bank, port, usrp, num_bits);
// configure GPIO registers
uint32_t ddr = strtoul(ddr_str.c_str(), NULL, 0);
@@ -247,299 +466,162 @@ int UHD_SAFE_MAIN(int argc, char* argv[])
uint32_t atr_duplex = 0;
uint32_t mask = (1 << num_bits) - 1;
- if (!vm.count("bitbang")) {
- // set up GPIO outputs:
- // GPIO[0] = ATR output 1 at idle
- ctrl |= GPIO_BIT(0);
- atr_idle |= GPIO_BIT(0);
- ddr |= GPIO_BIT(0);
-
- // GPIO[1] = ATR output 1 during RX
- ctrl |= GPIO_BIT(1);
- ddr |= GPIO_BIT(1);
- atr_rx |= GPIO_BIT(1);
-
- // GPIO[2] = ATR output 1 during TX
- ctrl |= GPIO_BIT(2);
- ddr |= GPIO_BIT(2);
- atr_tx |= GPIO_BIT(2);
-
- // GPIO[3] = ATR output 1 during full duplex
- ctrl |= GPIO_BIT(3);
- ddr |= GPIO_BIT(3);
- atr_duplex |= GPIO_BIT(3);
-
- // GPIO[4] = output
- ddr |= GPIO_BIT(4);
+ // The bitbang test is its own thing
+ if (vm.count("bitbang")) {
+ run_bitbang_test(usrp, gpio_bank, port, ddr, out, mask, num_bits, dwell_time);
+ return EXIT_SUCCESS;
}
- // set GPIO driver source
- if (vm.count("src")) {
- std::vector<std::string> gpio_src;
- typedef boost::char_separator<char> separator;
- boost::tokenizer<separator> tokens(src_str, separator(" "));
- std::copy(tokens.begin(), tokens.end(), std::back_inserter(gpio_src));
- usrp->set_gpio_src(port, gpio_src);
- }
+ // set up GPIO outputs:
+ // GPIO[0] = ATR output 1 at idle
+ ctrl |= GPIO_BIT(0);
+ atr_idle |= GPIO_BIT(0);
+ ddr |= GPIO_BIT(0);
+
+ // GPIO[1] = ATR output 1 during RX
+ ctrl |= GPIO_BIT(1);
+ ddr |= GPIO_BIT(1);
+ atr_rx |= GPIO_BIT(1);
+
+ // GPIO[2] = ATR output 1 during TX
+ ctrl |= GPIO_BIT(2);
+ ddr |= GPIO_BIT(2);
+ atr_tx |= GPIO_BIT(2);
+
+ // GPIO[3] = ATR output 1 during full duplex
+ ctrl |= GPIO_BIT(3);
+ ddr |= GPIO_BIT(3);
+ atr_duplex |= GPIO_BIT(3);
+
+ // GPIO[4] = output
+ ddr |= GPIO_BIT(4);
// set data direction register (DDR)
- usrp->set_gpio_attr(gpio, "DDR", ddr, mask);
+ usrp->set_gpio_attr(gpio_bank, "DDR", ddr, mask);
// set control register
- usrp->set_gpio_attr(gpio, "CTRL", ctrl, mask);
+ usrp->set_gpio_attr(gpio_bank, "CTRL", ctrl, mask);
// set output values (OUT)
- usrp->set_gpio_attr(gpio, "OUT", out, mask);
+ usrp->set_gpio_attr(gpio_bank, "OUT", out, mask);
// set ATR registers
- usrp->set_gpio_attr(gpio, "ATR_0X", atr_idle, mask);
- usrp->set_gpio_attr(gpio, "ATR_RX", atr_rx, mask);
- usrp->set_gpio_attr(gpio, "ATR_TX", atr_tx, mask);
- usrp->set_gpio_attr(gpio, "ATR_XX", atr_duplex, mask);
+ usrp->set_gpio_attr(gpio_bank, "ATR_0X", atr_idle, mask);
+ usrp->set_gpio_attr(gpio_bank, "ATR_RX", atr_rx, mask);
+ usrp->set_gpio_attr(gpio_bank, "ATR_TX", atr_tx, mask);
+ usrp->set_gpio_attr(gpio_bank, "ATR_XX", atr_duplex, mask);
// print out initial state of FP GPIO
std::cout << "\nConfigured GPIO values:" << std::endl;
- output_reg_values(gpio, port, usrp, num_bits);
+ output_reg_values(gpio_bank, port, usrp, num_bits);
std::cout << std::endl;
// set up streams
- uhd::stream_args_t rx_args(cpu, otw);
- uhd::stream_args_t tx_args(cpu, otw);
- uhd::rx_streamer::sptr rx_stream;
- uhd::tx_streamer::sptr tx_stream;
- uhd::stream_cmd_t rx_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
- rx_cmd.stream_now = true;
- if (usrp->get_rx_num_channels()) {
- rx_stream = usrp->get_rx_stream(rx_args);
- usrp->set_rx_rate(rx_rate);
- }
- if (usrp->get_tx_num_channels()) {
- tx_stream = usrp->get_tx_stream(tx_args);
- usrp->set_tx_rate(tx_rate);
- }
-
- // set up buffers for tx and rx
- const size_t rx_spp = rx_stream ? rx_stream->get_max_num_samps() : 0;
- const size_t tx_spp = tx_stream ? tx_stream->get_max_num_samps() : 0;
- const size_t nsamps_per_buff = std::max(rx_spp, tx_spp);
- std::vector<char> rx_buff(nsamps_per_buff * uhd::convert::get_bytes_per_item(cpu));
- std::vector<char> tx_buff(nsamps_per_buff * uhd::convert::get_bytes_per_item(cpu));
- std::vector<void*> rx_buffs, tx_buffs;
- if (rx_stream) {
- for (size_t ch = 0; ch < rx_stream->get_num_channels(); ch++) {
- rx_buffs.push_back(&rx_buff.front()); // same buffer for each channel
- }
- }
- if (tx_stream) {
- for (size_t ch = 0; ch < tx_stream->get_num_channels(); ch++)
- tx_buffs.push_back(&tx_buff.front()); // same buffer for each channel
- }
-
- uhd::rx_metadata_t rx_md;
- uhd::tx_metadata_t tx_md;
- tx_md.has_time_spec = false;
- tx_md.start_of_burst = true;
- double timeout = 0.01;
- auto dwell_time = std::chrono::milliseconds(static_cast<int64_t>(dwell * 1000));
+ stream_helper_type stream_helper(usrp, rx_rate, tx_rate, cpu, otw, dwell_time);
- int loop = 0;
- uint32_t rb, expected;
+ int loop = 0;
+ int failures = 0;
+ bool tests_failed = false;
// register signal handler
std::signal(SIGINT, &sig_int_handler);
- if (!vm.count("bitbang")) {
- // Test the mask parameter of the multi_usrp::set_gpio_attr API
- // We only need to test once with no dwell time
- std::cout << "\nTesting mask..." << std::flush;
- // send a value of all 1's to the DDR with a mask for only upper most bit
- usrp->set_gpio_attr(gpio, "DDR", ~0, GPIO_BIT(num_bits - 1));
- // upper most bit should now be 1, but all the other bits should be unchanged
- rb = usrp->get_gpio_attr(gpio, "DDR") & mask;
- expected = ddr | GPIO_BIT(num_bits - 1);
- if (rb == expected)
- std::cout << "pass:" << std::endl;
- else
- std::cout << "fail:" << std::endl;
- output_reg_values(gpio, port, usrp, num_bits);
- // restore DDR value
- usrp->set_gpio_attr(gpio, "DDR", ddr, mask);
- }
-
+ // Test the mask parameter of the multi_usrp::set_gpio_attr API
+ // We only need to test once with no dwell time
+ std::cout << "\nTesting mask..." << std::flush;
+ // send a value of all 1's to the DDR with a mask for only upper most bit
+ usrp->set_gpio_attr(gpio_bank, "DDR", ~0, GPIO_BIT(num_bits - 1));
+ // upper most bit should now be 1, but all the other bits should be unchanged
+ failures += int(!check_rb_values(usrp->get_gpio_attr(gpio_bank, "DDR") & mask,
+ ddr | GPIO_BIT(num_bits - 1),
+ num_bits, 0));
+ output_reg_values(gpio_bank, port, usrp, num_bits);
+ // restore DDR value
+ usrp->set_gpio_attr(gpio_bank, "DDR", ddr, mask);
+
+ /*************************************************************************/
+ /* Setup complete, start running test */
+ /*************************************************************************/
while (not stop_signal_called) {
- int failures = 0;
-
if (vm.count("repeat"))
std::cout << "Press Ctrl + C to quit..." << std::endl;
- if (vm.count("bitbang")) {
- // dwell and continuously read back GPIO values
- auto stop_time = std::chrono::steady_clock::now() + dwell_time;
- while (
- not stop_signal_called and std::chrono::steady_clock::now() < stop_time) {
- rb = usrp->get_gpio_attr(gpio, "READBACK");
- std::cout << "\rREADBACK: " << to_bit_string(rb, num_bits);
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- }
- std::cout << std::endl;
- } else {
- // test user controlled GPIO and ATR idle by setting bit 4 high for 1 second
- std::cout << "\nTesting user controlled GPIO and ATR idle output..."
- << std::flush;
- usrp->set_gpio_attr(gpio, "OUT", GPIO_BIT(4), GPIO_BIT(4));
- auto stop_time = std::chrono::steady_clock::now() + dwell_time;
- while (
- not stop_signal_called and std::chrono::steady_clock::now() < stop_time) {
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- }
- rb = usrp->get_gpio_attr(gpio, "READBACK");
- expected = GPIO_BIT(4) | GPIO_BIT(0);
- if ((rb & expected) != expected) {
- ++failures;
- std::cout << "fail:" << std::endl;
- if ((rb & GPIO_BIT(0)) == 0)
- std::cout << "Bit 0 should be set, but is not" << std::endl;
- if ((rb & GPIO_BIT(4)) == 0)
- std::cout << "Bit 4 should be set, but is not" << std::endl;
- } else {
- std::cout << "pass:" << std::endl;
- }
- output_reg_values(gpio, port, usrp, num_bits);
- usrp->set_gpio_attr(gpio, "OUT", 0, GPIO_BIT(4));
- if (stop_signal_called)
- break;
-
- if (rx_stream) {
- // test ATR RX by receiving for 1 second
- std::cout << "\nTesting ATR RX output..." << std::flush;
- rx_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
- rx_stream->issue_stream_cmd(rx_cmd);
- stop_time = std::chrono::steady_clock::now() + dwell_time;
- while (not stop_signal_called
- and std::chrono::steady_clock::now() < stop_time) {
- try {
- rx_stream->recv(rx_buffs, nsamps_per_buff, rx_md, timeout);
- } catch (...) {
- }
- }
- rb = usrp->get_gpio_attr(gpio, "READBACK");
- expected = GPIO_BIT(1);
- if ((rb & expected) != expected) {
- ++failures;
- std::cout << "fail:" << std::endl;
- std::cout << "Bit 1 should be set, but is not" << std::endl;
- } else {
- std::cout << "pass:" << std::endl;
- }
- output_reg_values(gpio, port, usrp, num_bits);
- rx_stream->issue_stream_cmd(
- uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
- // clear out any data left in the rx stream
- try {
- rx_stream->recv(rx_buffs, nsamps_per_buff, rx_md, timeout);
- } catch (...) {
- }
- }
- if (stop_signal_called)
- break;
-
- if (tx_stream) {
- // test ATR TX by transmitting for 1 second
- std::cout << "\nTesting ATR TX output..." << std::flush;
- stop_time = std::chrono::steady_clock::now() + dwell_time;
- tx_md.start_of_burst = true;
- tx_md.end_of_burst = false;
- while (not stop_signal_called
- and std::chrono::steady_clock::now() < stop_time) {
- try {
- tx_stream->send(tx_buffs, nsamps_per_buff, tx_md, timeout);
- tx_md.start_of_burst = false;
- } catch (...) {
- }
- }
- rb = usrp->get_gpio_attr(gpio, "READBACK");
- expected = GPIO_BIT(2);
- if ((rb & expected) != expected) {
- ++failures;
- std::cout << "fail:" << std::endl;
- std::cout << "Bit 2 should be set, but is not" << std::endl;
- } else {
- std::cout << "pass:" << std::endl;
- }
- output_reg_values(gpio, port, usrp, num_bits);
- tx_md.end_of_burst = true;
- try {
- tx_stream->send(tx_buffs, nsamps_per_buff, tx_md, timeout);
- } catch (...) {
- }
- }
- if (stop_signal_called)
- break;
-
- if (rx_stream and tx_stream) {
- // test ATR full duplex by transmitting and receiving
- std::cout << "\nTesting ATR full duplex output..." << std::flush;
- rx_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
- rx_stream->issue_stream_cmd(rx_cmd);
- tx_md.start_of_burst = true;
- tx_md.end_of_burst = false;
- stop_time = std::chrono::steady_clock::now() + dwell_time;
- while (not stop_signal_called
- and std::chrono::steady_clock::now() < stop_time) {
- try {
- tx_stream->send(tx_buffs, nsamps_per_buff, tx_md, timeout);
- tx_md.start_of_burst = false;
- rx_stream->recv(rx_buffs, nsamps_per_buff, rx_md, timeout);
- } catch (...) {
- }
- }
-
- // Read GPIO
- rb = usrp->get_gpio_attr(gpio, "READBACK");
+ /*** Test 1: User-controlled GPIO + ATR idle *************************/
+ std::cout << "\nTesting user controlled GPIO and ATR idle output..."
+ << std::flush;
+ usrp->set_gpio_attr(gpio_bank, "OUT", GPIO_BIT(4), GPIO_BIT(4));
+ auto stop_time = std::chrono::steady_clock::now() + dwell_time;
+ while (not stop_signal_called and std::chrono::steady_clock::now() < stop_time) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
+ failures += int(!check_rb_values(usrp->get_gpio_attr(gpio_bank, "READBACK"),
+ GPIO_BIT(4) | GPIO_BIT(0),
+ num_bits, loopback_num_bits));
+ output_reg_values(gpio_bank, port, usrp, num_bits);
+ usrp->set_gpio_attr(gpio_bank, "OUT", 0, GPIO_BIT(4));
+ if (stop_signal_called)
+ break;
- // Stop streaming
- rx_stream->issue_stream_cmd(
- uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
- tx_md.end_of_burst = true;
- try {
- tx_stream->send(tx_buffs, nsamps_per_buff, tx_md, timeout);
- } catch (...) {
- }
+ /*** Test 2: ATR RX **************************************************/
+ if (stream_helper.rx_stream) {
+ // test ATR RX by receiving for 1 second
+ std::cout << "\nTesting ATR RX output..." << std::flush;
+ stream_helper.start_stream(false, true);
+ failures += int(!check_rb_values(usrp->get_gpio_attr(gpio_bank, "READBACK"),
+ GPIO_BIT(1),
+ num_bits, loopback_num_bits));
+ output_reg_values(gpio_bank, port, usrp, num_bits);
+ stream_helper.stop_stream(false, true);
+ }
+ if (stop_signal_called)
+ break;
- // clear out any data left in the rx stream
- try {
- rx_stream->recv(rx_buffs, nsamps_per_buff, rx_md, timeout);
- } catch (...) {
- }
+ /*** Test 3: ATR TX **************************************************/
+ if (stream_helper.tx_stream) {
+ // test ATR TX by transmitting for 1 second
+ std::cout << "\nTesting ATR TX output..." << std::flush;
+ stream_helper.start_stream(true, false);
+ failures += int(!check_rb_values(usrp->get_gpio_attr(gpio_bank, "READBACK"),
+ GPIO_BIT(2),
+ num_bits, loopback_num_bits));
+ output_reg_values(gpio_bank, port, usrp, num_bits);
+ stream_helper.stop_stream(true, false);
+ }
+ if (stop_signal_called)
+ break;
- // Analyze results
- expected = GPIO_BIT(3);
- if ((rb & expected) != expected) {
- ++failures;
- std::cout << "fail:" << std::endl;
- std::cout << "Bit 3 should be set, but is not" << std::endl;
- } else {
- std::cout << "pass:" << std::endl;
- }
- output_reg_values(gpio, port, usrp, num_bits);
- }
+ /*** Test 4: ATR FDX *************************************************/
+ if (stream_helper.rx_stream and stream_helper.tx_stream) {
+ // test ATR full duplex by transmitting and receiving
+ std::cout << "\nTesting ATR full duplex output..." << std::flush;
+ stream_helper.start_stream(true, true);
+ failures += int(!check_rb_values(usrp->get_gpio_attr(gpio_bank, "READBACK"),
+ GPIO_BIT(3),
+ num_bits, loopback_num_bits));
+ stream_helper.stop_stream(true, true);
+ output_reg_values(gpio_bank, port, usrp, num_bits);
+ }
- std::cout << std::endl;
- if (failures)
- std::cout << failures << " tests failed" << std::endl;
- else
- std::cout << "All tests passed!" << std::endl;
+ std::cout << std::endl;
+ if (failures) {
+ tests_failed = true;
+ std::cout << failures << " tests failed" << std::endl;
+ } else {
+ std::cout << "All tests passed!" << std::endl;
}
- if (!vm.count("repeat"))
+ if (!vm.count("repeat")) {
break;
+ }
+ failures = 0;
- if (not stop_signal_called)
- std::cout << (boost::format("\nLoop %d completed") % ++loop) << std::endl;
+ if (not stop_signal_called) {
+ std::cout << "\nLoop " << ++loop << " completed" << std::endl;
+ }
}
// finished
std::cout << std::endl << "Done!" << std::endl << std::endl;
- return EXIT_SUCCESS;
+ return int(tests_failed);
}