aboutsummaryrefslogtreecommitdiffstats
path: root/host/examples
diff options
context:
space:
mode:
Diffstat (limited to 'host/examples')
-rw-r--r--host/examples/CMakeLists.txt47
-rw-r--r--host/examples/getopt/CMakeLists.txt24
-rw-r--r--host/examples/getopt/getopt.c70
-rw-r--r--host/examples/getopt/getopt.h19
-rw-r--r--host/examples/rx_samples_c.c291
-rw-r--r--host/examples/tx_samples_c.c241
6 files changed, 691 insertions, 1 deletions
diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt
index 92947d86c..43e0db9c0 100644
--- a/host/examples/CMakeLists.txt
+++ b/host/examples/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2010-2014 Ettus Research LLC
+# Copyright 2010-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
@@ -61,3 +61,48 @@ IF(CURSES_FOUND)
TARGET_LINK_LIBRARIES(rx_ascii_art_dft uhd ${CURSES_LIBRARIES} ${Boost_LIBRARIES})
UHD_INSTALL(TARGETS rx_ascii_art_dft RUNTIME DESTINATION ${PKG_LIB_DIR}/examples COMPONENT examples)
ENDIF(CURSES_FOUND)
+
+########################################################################
+# Examples using C API
+########################################################################
+IF(ENABLE_C_API)
+ #
+ # Check if this particular C99 feature is available with this compiler
+ #
+ INCLUDE(CheckCSourceCompiles)
+ CHECK_C_SOURCE_COMPILES("
+ typedef struct {
+ int bar;
+ int baz;
+ } foo;
+
+ int main()
+ {
+ foo wat = {
+ .bar = 1,
+ .baz = 2
+ };
+
+ return 0;
+ }
+ " HAVE_C99_STRUCTDECL)
+
+ IF(HAVE_C99_STRUCTDECL)
+ ADD_SUBDIRECTORY(getopt)
+ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/getopt)
+
+ SET(C_API_EXAMPLES
+ rx_samples_c
+ tx_samples_c
+ )
+
+ FOREACH(example ${C_API_EXAMPLES})
+ ADD_EXECUTABLE(${example} ${example}.c)
+ TARGET_LINK_LIBRARIES(${example} uhd getopt)
+ IF(UNIX)
+ TARGET_LINK_LIBRARIES(${example} m)
+ ENDIF(UNIX)
+ UHD_INSTALL(TARGETS ${example} RUNTIME DESTINATION ${PKG_LIB_DIR}/examples COMPONENT examples)
+ ENDFOREACH(example ${C_API_EXAMPLES})
+ ENDIF(HAVE_C99_STRUCTDECL)
+ENDIF(ENABLE_C_API)
diff --git a/host/examples/getopt/CMakeLists.txt b/host/examples/getopt/CMakeLists.txt
new file mode 100644
index 000000000..46ad1460c
--- /dev/null
+++ b/host/examples/getopt/CMakeLists.txt
@@ -0,0 +1,24 @@
+#
+# 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/>.
+#
+
+########################################################################
+# getopt library for C examples since MSVC does not include it
+########################################################################
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIRECTORY})
+ADD_LIBRARY(getopt STATIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/getopt.c
+)
diff --git a/host/examples/getopt/getopt.c b/host/examples/getopt/getopt.c
new file mode 100644
index 000000000..e571ff9c8
--- /dev/null
+++ b/host/examples/getopt/getopt.c
@@ -0,0 +1,70 @@
+/*
+ * This file was copied from the following newsgroup posting:
+ *
+ * Newsgroups: mod.std.unix
+ * Subject: public domain AT&T getopt source
+ * Date: 3 Nov 85 19:34:15 GMT
+ *
+ * Here's something you've all been waiting for: the AT&T public domain
+ * source for getopt(3). It is the code which was given out at the 1985
+ * UNIFORUM conference in Dallas. I obtained it by electronic mail
+ * directly from AT&T. The people there assure me that it is indeed
+ * in the public domain.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#define ERR(szz,czz) if(opterr){fprintf(stderr,"%s%s%c\n",argv[0],szz,czz);}
+
+int opterr = 1;
+int optind = 1;
+int optopt;
+char *optarg;
+
+int
+getopt(int argc, char **argv, char *opts)
+{
+ static int sp;
+ int c;
+ char *cp;
+
+ sp = 1;
+
+ if (sp == 1) {
+ if (optind >= argc ||
+ argv[optind][0] != '-' || argv[optind][1] == '\0')
+ return (EOF);
+ else if (strcmp(argv[optind], "--") == 0) {
+ optind++;
+ return (EOF);
+ }
+ }
+ optopt = c = argv[optind][sp];
+ if (c == ':' || (cp = strchr(opts, c)) == NULL) {
+ ERR(": illegal option -- ", c);
+ if (argv[optind][++sp] == '\0') {
+ optind++;
+ sp = 1;
+ }
+ return ('?');
+ }
+ if (*++cp == ':') {
+ if (argv[optind][sp + 1] != '\0')
+ optarg = &argv[optind++][sp + 1];
+ else if (++optind >= argc) {
+ ERR(": option requires an argument -- ", c);
+ sp = 1;
+ return ('?');
+ } else
+ optarg = argv[optind++];
+ sp = 1;
+ } else {
+ if (argv[optind][++sp] == '\0') {
+ sp = 1;
+ optind++;
+ }
+ optarg = NULL;
+ }
+ return (c);
+}
diff --git a/host/examples/getopt/getopt.h b/host/examples/getopt/getopt.h
new file mode 100644
index 000000000..ada96ecf0
--- /dev/null
+++ b/host/examples/getopt/getopt.h
@@ -0,0 +1,19 @@
+/*
+ * This header is for a function released into the public domain
+ * by AT&T in 1985. See the newsgroup posting:
+ *
+ * Newsgroups: mod.std.unix
+ * Subject: public domain AT&T getopt source
+ * Date: 3 Nov 85 19:34:15 GMT
+ */
+#ifndef _GETOPT_H_
+#define _GETOPT_H_
+
+extern int optarr;
+extern int optind;
+extern int optopt;
+extern char* optarg;
+
+int getopt(int argc, char **argv, char *opts);
+
+#endif /* _GETOPT_H_ */
diff --git a/host/examples/rx_samples_c.c b/host/examples/rx_samples_c.c
new file mode 100644
index 000000000..b5882b79b
--- /dev/null
+++ b/host/examples/rx_samples_c.c
@@ -0,0 +1,291 @@
+/*
+ * 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.h>
+
+#include "getopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define EXECUTE_OR_GOTO(label, ...) \
+ if(__VA_ARGS__){ \
+ return_code = EXIT_FAILURE; \
+ goto label; \
+ }
+
+void print_help(void){
+ fprintf(stderr, "rx_samples_c - A simple RX example using UHD's C API\n\n"
+
+ "Options:\n"
+ " -a (device args)\n"
+ " -f (frequency in Hz)\n"
+ " -r (sample rate in Hz)\n"
+ " -g (gain)\n"
+ " -n (number of samples to receive)\n"
+ " -o (output filename, default = \"out.dat\")\n"
+ " -v (enable verbose prints)\n"
+ " -h (print this help message)\n");
+};
+
+int main(int argc, char* argv[])
+{
+ if(uhd_set_thread_priority(uhd_default_thread_priority, true)){
+ fprintf(stderr, "Unable to set thread priority. Continuing anyway.\n");
+ }
+
+ int option = 0;
+ double freq = 500e6;
+ double rate = 1e6;
+ double gain = 5.0;
+ char* device_args = "";
+ size_t channel = 0;
+ char* filename = "out.dat";
+ size_t n_samples = 1000000;
+ bool verbose = false;
+ int return_code = EXIT_SUCCESS;
+ bool custom_filename = false;
+ char error_string[512];
+
+ // Process options
+ while((option = getopt(argc, argv, "a:f:r:g:n:o:vh")) != -1){
+ switch(option){
+ case 'a':
+ device_args = strdup(optarg);
+ break;
+
+ case 'f':
+ freq = atof(optarg);
+ break;
+
+ case 'r':
+ rate = atof(optarg);
+ break;
+
+ case 'g':
+ gain = atof(optarg);
+ break;
+
+ case 'n':
+ n_samples = atoi(optarg);
+ break;
+
+ case 'o':
+ filename = strdup(optarg);
+ custom_filename = true;
+ break;
+
+ case 'v':
+ verbose = true;
+ break;
+
+ case 'h':
+ print_help();
+ goto free_option_strings;
+
+ default:
+ print_help();
+ return_code = EXIT_FAILURE;
+ goto free_option_strings;
+ }
+ }
+
+ // Create USRP
+ uhd_usrp_handle usrp;
+ fprintf(stderr, "Creating USRP with args \"%s\"...\n", device_args);
+ EXECUTE_OR_GOTO(free_option_strings,
+ uhd_usrp_make(&usrp, device_args)
+ )
+
+ // Create RX streamer
+ uhd_rx_streamer_handle rx_streamer;
+ EXECUTE_OR_GOTO(free_usrp,
+ uhd_rx_streamer_make(&rx_streamer)
+ )
+
+ // Create RX metadata
+ uhd_rx_metadata_handle md;
+ EXECUTE_OR_GOTO(free_rx_streamer,
+ uhd_rx_metadata_make(&md)
+ )
+
+ // Create other necessary structs
+ uhd_tune_request_t tune_request = {
+ .target_freq = freq,
+ .rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO,
+ .dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO,
+ };
+ uhd_tune_result_t tune_result;
+
+ uhd_stream_args_t stream_args = {
+ .cpu_format = "fc32",
+ .otw_format = "sc16",
+ .args = "",
+ .channel_list = &channel,
+ .n_channels = 1
+ };
+
+ uhd_stream_cmd_t stream_cmd = {
+ .stream_mode = UHD_STREAM_MODE_NUM_SAMPS_AND_DONE,
+ .num_samps = n_samples,
+ .stream_now = true
+ };
+
+ size_t samps_per_buff;
+ float *buff = NULL;
+ void **buffs_ptr = NULL;
+ FILE *fp = NULL;
+ size_t num_acc_samps = 0;
+
+ // Set rate
+ fprintf(stderr, "Setting RX Rate: %f...\n", rate);
+ EXECUTE_OR_GOTO(free_rx_metadata,
+ uhd_usrp_set_rx_rate(usrp, rate, channel)
+ )
+
+ // See what rate actually is
+ EXECUTE_OR_GOTO(free_rx_metadata,
+ uhd_usrp_get_rx_rate(usrp, channel, &rate)
+ )
+ fprintf(stderr, "Actual RX Rate: %f...\n", rate);
+
+ // Set gain
+ fprintf(stderr, "Setting RX Gain: %f dB...\n", gain);
+ EXECUTE_OR_GOTO(free_rx_metadata,
+ uhd_usrp_set_rx_gain(usrp, gain, channel, "")
+ )
+
+ // See what gain actually is
+ EXECUTE_OR_GOTO(free_rx_metadata,
+ uhd_usrp_get_rx_gain(usrp, channel, "", &gain)
+ )
+ fprintf(stderr, "Actual RX Gain: %f...\n", gain);
+
+ // Set frequency
+ fprintf(stderr, "Setting RX frequency: %f MHz...\n", freq/1e6);
+ EXECUTE_OR_GOTO(free_rx_metadata,
+ uhd_usrp_set_rx_freq(usrp, &tune_request, channel, &tune_result)
+ )
+
+ // See what frequency actually is
+ EXECUTE_OR_GOTO(free_rx_metadata,
+ uhd_usrp_get_rx_freq(usrp, channel, &freq)
+ )
+ fprintf(stderr, "Actual RX frequency: %f MHz...\n", freq / 1e6);
+
+ // Set up streamer
+ stream_args.channel_list = &channel;
+ EXECUTE_OR_GOTO(free_rx_streamer,
+ uhd_usrp_get_rx_stream(usrp, &stream_args, rx_streamer)
+ )
+
+ // Set up buffer
+ EXECUTE_OR_GOTO(free_rx_streamer,
+ uhd_rx_streamer_max_num_samps(rx_streamer, &samps_per_buff)
+ )
+ fprintf(stderr, "Buffer size in samples: %zu\n", samps_per_buff);
+ buff = malloc(samps_per_buff * 2 * sizeof(float));
+ buffs_ptr = (void**)&buff;
+
+ // Issue stream command
+ fprintf(stderr, "Issuing stream command.\n");
+ EXECUTE_OR_GOTO(free_buffer,
+ uhd_rx_streamer_issue_stream_cmd(rx_streamer, &stream_cmd)
+ )
+
+ // Set up file output
+ fp = fopen(filename, "wb");
+
+ // Actual streaming
+ while (num_acc_samps < n_samples) {
+ size_t num_rx_samps = 0;
+ EXECUTE_OR_GOTO(close_file,
+ uhd_rx_streamer_recv(rx_streamer, buffs_ptr, samps_per_buff, md, 3.0, false, &num_rx_samps)
+ )
+
+ uhd_rx_metadata_error_code_t error_code;
+ EXECUTE_OR_GOTO(close_file,
+ uhd_rx_metadata_error_code(md, &error_code)
+ )
+ if(return_code != UHD_RX_METADATA_ERROR_CODE_NONE){
+ fprintf(stderr, "Error code 0x%x was returned during streaming. Aborting.\n", return_code);
+ goto close_file;
+ }
+
+ // Handle data
+ fwrite(buff, sizeof(float) * 2, num_rx_samps, fp);
+ if (verbose) {
+ time_t full_secs;
+ double frac_secs;
+ uhd_rx_metadata_time_spec(md, &full_secs, &frac_secs);
+ fprintf(stderr, "Received packet: %zu samples, %zu full secs, %f frac secs\n",
+ num_rx_samps,
+ full_secs,
+ frac_secs);
+ }
+
+ num_acc_samps += num_rx_samps;
+ }
+
+ // Cleanup
+ close_file:
+ fclose(fp);
+
+ free_buffer:
+ if(buff){
+ if(verbose){
+ fprintf(stderr, "Freeing buffer.\n");
+ }
+ free(buff);
+ }
+ buff = NULL;
+ buffs_ptr = NULL;
+
+ free_rx_streamer:
+ if(verbose){
+ fprintf(stderr, "Cleaning up RX streamer.\n");
+ }
+ uhd_rx_streamer_free(&rx_streamer);
+
+ free_rx_metadata:
+ if(verbose){
+ fprintf(stderr, "Cleaning up RX metadata.\n");
+ }
+ uhd_rx_metadata_free(&md);
+
+ free_usrp:
+ if(verbose){
+ fprintf(stderr, "Cleaning up USRP.\n");
+ }
+ if(return_code != EXIT_SUCCESS && usrp != NULL){
+ uhd_usrp_last_error(usrp, error_string, 512);
+ fprintf(stderr, "USRP reported the following error: %s\n", error_string);
+ }
+ uhd_usrp_free(&usrp);
+
+ free_option_strings:
+ if(strcmp(device_args,"")){
+ free(device_args);
+ }
+ if(custom_filename){
+ free(filename);
+ }
+
+ fprintf(stderr, (return_code ? "Failure\n" : "Success\n"));
+ return return_code;
+}
diff --git a/host/examples/tx_samples_c.c b/host/examples/tx_samples_c.c
new file mode 100644
index 000000000..3035297fd
--- /dev/null
+++ b/host/examples/tx_samples_c.c
@@ -0,0 +1,241 @@
+/*
+ * 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.h>
+
+#include "getopt.h"
+
+#include <math.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define EXECUTE_OR_GOTO(label, ...) \
+ if(__VA_ARGS__){ \
+ return_code = EXIT_FAILURE; \
+ goto label; \
+ }
+
+void print_help(void){
+ fprintf(stderr, "tx_samples_c - A simple TX example using UHD's C API\n\n"
+
+ "Options:\n"
+ " -a (device args)\n"
+ " -f (frequency in Hz)\n"
+ " -r (sample rate in Hz)\n"
+ " -g (gain)\n"
+ " -v (enable verbose prints)\n"
+ " -h (print this help message)\n");
+}
+
+bool stop_signal_called = false;
+
+void sigint_handler(int code){
+ (void)code;
+ stop_signal_called = true;
+}
+
+int main(int argc, char* argv[]){
+ int option = 0;
+ double freq = 2e9;
+ double rate = 1e6;
+ double gain = 0;
+ char* device_args = "";
+ size_t channel = 0;
+ bool verbose = false;
+ int return_code = EXIT_SUCCESS;
+ char error_string[512];
+
+ // Process options
+ while((option = getopt(argc, argv, "a:f:r:g:vh")) != -1){
+ switch(option){
+ case 'a':
+ device_args = strdup(optarg);
+ break;
+
+ case 'f':
+ freq = atof(optarg);
+ break;
+
+ case 'r':
+ rate = atof(optarg);
+ break;
+
+ case 'g':
+ gain = atof(optarg);
+ break;
+
+ case 'v':
+ verbose = true;
+ break;
+
+ case 'h':
+ print_help();
+ goto free_option_strings;
+
+ default:
+ print_help();
+ return_code = EXIT_FAILURE;
+ goto free_option_strings;
+ }
+ }
+
+ if(uhd_set_thread_priority(uhd_default_thread_priority, true)){
+ fprintf(stderr, "Unable to set thread priority. Continuing anyway.\n");
+ }
+
+ // Create USRP
+ uhd_usrp_handle usrp;
+ fprintf(stderr, "Creating USRP with args \"%s\"...\n", device_args);
+ EXECUTE_OR_GOTO(free_option_strings,
+ uhd_usrp_make(&usrp, device_args)
+ )
+
+ // Create TX streamer
+ uhd_tx_streamer_handle tx_streamer;
+ EXECUTE_OR_GOTO(free_usrp,
+ uhd_tx_streamer_make(&tx_streamer)
+ )
+
+ // Create TX metadata
+ uhd_tx_metadata_handle md;
+ EXECUTE_OR_GOTO(free_tx_streamer,
+ uhd_tx_metadata_make(&md, false, 0.0, 0.1, true, false)
+ )
+
+ // Create other necessary structs
+ uhd_tune_request_t tune_request = {
+ .target_freq = freq,
+ .rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO,
+ .dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO
+ };
+ uhd_tune_result_t tune_result;
+
+ uhd_stream_args_t stream_args = {
+ .cpu_format = "fc32",
+ .otw_format = "sc16",
+ .args = "",
+ .channel_list = &channel,
+ .n_channels = 1
+ };
+
+ size_t samps_per_buff;
+ float* buff = NULL;
+ const void** buffs_ptr = NULL;
+
+ // Set rate
+ fprintf(stderr, "Setting TX Rate: %f...\n", rate);
+ EXECUTE_OR_GOTO(free_tx_metadata,
+ uhd_usrp_set_tx_rate(usrp, rate, channel)
+ )
+
+ // See what rate actually is
+ EXECUTE_OR_GOTO(free_tx_metadata,
+ uhd_usrp_get_tx_rate(usrp, channel, &rate)
+ )
+ fprintf(stderr, "Actual TX Rate: %f...\n\n", rate);
+
+ // Set gain
+ fprintf(stderr, "Setting TX Gain: %f db...\n", gain);
+ EXECUTE_OR_GOTO(free_tx_metadata,
+ uhd_usrp_set_tx_gain(usrp, gain, 0, "")
+ )
+
+ // See what gain actually is
+ EXECUTE_OR_GOTO(free_tx_metadata,
+ uhd_usrp_get_tx_gain(usrp, channel, "", &gain)
+ )
+ fprintf(stderr, "Actual TX Gain: %f...\n", gain);
+
+ // Set frequency
+ fprintf(stderr, "Setting TX frequency: %f MHz...\n", freq / 1e6);
+ EXECUTE_OR_GOTO(free_tx_metadata,
+ uhd_usrp_set_tx_freq(usrp, &tune_request, channel, &tune_result)
+ )
+
+ // See what frequency actually is
+ EXECUTE_OR_GOTO(free_tx_metadata,
+ uhd_usrp_get_tx_freq(usrp, channel, &freq)
+ )
+ fprintf(stderr, "Actual TX frequency: %f MHz...\n", freq / 1e6);
+
+ // Set up streamer
+ stream_args.channel_list = &channel;
+ EXECUTE_OR_GOTO(free_tx_streamer,
+ uhd_usrp_get_tx_stream(usrp, &stream_args, tx_streamer)
+ )
+
+ // Set up buffer
+ EXECUTE_OR_GOTO(free_tx_streamer,
+ uhd_tx_streamer_max_num_samps(tx_streamer, &samps_per_buff)
+ )
+ fprintf(stderr, "Buffer size in samples: %zu\n", samps_per_buff);
+ buff = malloc(samps_per_buff * 2 * sizeof(float));
+ buffs_ptr = (const void**)&buff;
+ size_t i = 0;
+ for(i = 0; i < (samps_per_buff*2); i+=2){
+ buff[i] = 0.1;
+ buff[i+1] = 0;
+ }
+
+ // Ctrl+C will exit loop
+ signal(SIGINT, &sigint_handler);
+ fprintf(stderr, "Press Ctrl+C to stop streaming...\n");
+
+ // Actual streaming
+ size_t num_samps_sent = 0;
+ while(!stop_signal_called){
+ EXECUTE_OR_GOTO(free_tx_streamer,
+ uhd_tx_streamer_send(tx_streamer, buffs_ptr, samps_per_buff, md, 0.1, &num_samps_sent)
+ )
+ if(verbose){
+ fprintf(stderr, "Sent %zu samples\n", num_samps_sent);
+ }
+ }
+
+ free_tx_streamer:
+ if(verbose){
+ fprintf(stderr, "Cleaning up TX streamer.\n");
+ }
+ uhd_tx_streamer_free(&tx_streamer);
+
+ free_tx_metadata:
+ if(verbose){
+ fprintf(stderr, "Cleaning up TX metadata.\n");
+ }
+ uhd_tx_metadata_free(&md);
+
+ free_usrp:
+ if(verbose){
+ fprintf(stderr, "Cleaning up USRP.\n");
+ }
+ if(return_code != EXIT_SUCCESS && usrp != NULL){
+ uhd_usrp_last_error(usrp, error_string, 512);
+ fprintf(stderr, "USRP reported the following error: %s\n", error_string);
+ }
+ uhd_usrp_free(&usrp);
+
+ free_option_strings:
+ if(strcmp(device_args,"")){
+ free(device_args);
+ }
+
+ fprintf(stderr, (return_code ? "Failure\n" : "Success\n"));
+
+ return return_code;
+}