From 30f87afcba71a07fbd28d51318e791448c28314e Mon Sep 17 00:00:00 2001
From: Nicholas Corgan <nick.corgan@ettus.com>
Date: Thu, 6 Aug 2015 10:42:23 -0700
Subject: uhd: C API wrapper

* multi_usrp, multi_usrp_clock, and associated classes accessible through C
* Added Doxygen documentation explaining structure and API
* Simple RX and TX streaming examples
* Unit tests for different parts of C interface and C++ error conversion
---
 host/examples/rx_samples_c.c | 291 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 291 insertions(+)
 create mode 100644 host/examples/rx_samples_c.c

(limited to 'host/examples/rx_samples_c.c')

diff --git a/host/examples/rx_samples_c.c b/host/examples/rx_samples_c.c
new file mode 100644
index 000000000..0be0d8afe
--- /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_usrp,
+        uhd_usrp_make(&usrp, device_args)
+    )
+
+    // Create RX streamer
+    uhd_rx_streamer_handle rx_streamer;
+    EXECUTE_OR_GOTO(free_rx_streamer,
+        uhd_rx_streamer_make(&rx_streamer)
+    )
+
+    // Create RX metadata
+    uhd_rx_metadata_handle md;
+    EXECUTE_OR_GOTO(free_rx_metadata,
+        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){
+            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;
+}
-- 
cgit v1.2.3