diff options
Diffstat (limited to 'host/examples')
| -rw-r--r-- | host/examples/CMakeLists.txt | 47 | ||||
| -rw-r--r-- | host/examples/getopt/CMakeLists.txt | 24 | ||||
| -rw-r--r-- | host/examples/getopt/getopt.c | 70 | ||||
| -rw-r--r-- | host/examples/getopt/getopt.h | 19 | ||||
| -rw-r--r-- | host/examples/rx_samples_c.c | 291 | ||||
| -rw-r--r-- | host/examples/tx_samples_c.c | 241 | 
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; +}  | 
