diff options
author | Nicholas Corgan <nick.corgan@ettus.com> | 2015-08-06 10:42:23 -0700 |
---|---|---|
committer | Nicholas Corgan <nick.corgan@ettus.com> | 2015-08-06 10:42:23 -0700 |
commit | 30f87afcba71a07fbd28d51318e791448c28314e (patch) | |
tree | 11393add7fde99950a252577882211845fe75d1d | |
parent | b08352f267730ea417ec345cd90833a6746a1114 (diff) | |
download | uhd-30f87afcba71a07fbd28d51318e791448c28314e.tar.gz uhd-30f87afcba71a07fbd28d51318e791448c28314e.tar.bz2 uhd-30f87afcba71a07fbd28d51318e791448c28314e.zip |
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
58 files changed, 9230 insertions, 25 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 2f59bada4..89447c12c 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -277,6 +277,7 @@ SET(UHD_IMAGES_DOWNLOAD_SRC "uhd-images_003.009.git-269-gb6ad4c05.zip") # Register top level components ######################################################################## LIBUHD_REGISTER_COMPONENT("LibUHD" ENABLE_LIBUHD ON "Boost_FOUND;HAVE_PYTHON_PLAT_MIN_VERSION;HAVE_PYTHON_MODULE_MAKO" OFF) +LIBUHD_REGISTER_COMPONENT("LibUHD - C API" ENABLE_C_API ON "ENABLE_LIBUHD" OFF) LIBUHD_REGISTER_COMPONENT("Examples" ENABLE_EXAMPLES ON "ENABLE_LIBUHD" OFF) LIBUHD_REGISTER_COMPONENT("Utils" ENABLE_UTILS ON "ENABLE_LIBUHD" OFF) LIBUHD_REGISTER_COMPONENT("Tests" ENABLE_TESTS ON "ENABLE_LIBUHD" OFF) diff --git a/host/cmake/msvc/stdbool.h b/host/cmake/msvc/stdbool.h new file mode 100644 index 000000000..3a91eea37 --- /dev/null +++ b/host/cmake/msvc/stdbool.h @@ -0,0 +1,33 @@ +// +// 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/>. +// + +#ifndef INCLUDED_MSC_STDBOOL_H +#define INCLUDED_MSC_STDBOOL_H + +#ifndef _MSC_VER +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif + +#ifndef __cplusplus + +#define bool int +#define true 1 +#define false 0 + +#endif + +#endif /* INCLUDED_MSC_STDBOOL_H */ diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt index 79488e373..3ad2ef37c 100644 --- a/host/docs/CMakeLists.txt +++ b/host/docs/CMakeLists.txt @@ -74,7 +74,7 @@ ENDIF(LIBUHDDEV_PKG) IF(ENABLE_DOXYGEN) SET(ENABLE_MANUAL_OR_DOXYGEN true) #make doxygen directory depend on the header files - FILE(GLOB_RECURSE header_files ${CMAKE_SOURCE_DIR}/include/*.hpp) + FILE(GLOB_RECURSE header_files ${CMAKE_SOURCE_DIR}/include/*.h*) SET(DOXYGEN_DEPENDENCIES ${DOXYGEN_DEPENDENCIES} ${header_files}) IF(ENABLE_DOXYGEN_FULL) SET(DOXYGEN_INPUT_DIRS "${DOXYGEN_INPUT_DIRS} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/lib") diff --git a/host/docs/c_api.dox b/host/docs/c_api.dox new file mode 100644 index 000000000..5b5790f21 --- /dev/null +++ b/host/docs/c_api.dox @@ -0,0 +1,86 @@ +/*! \page page_c_api UHD - C API + +\tableofcontents + +\section c_api_intro Introduction + +Alongside its C++ API, UHD provides a C API wrapper for the uhd::usrp::multi_usrp and +uhd::usrp_clock::multi_usrp_clock classes, as well as their associated classes and +structs. Other important UHD functions are also included in this API. To use this +API, simply: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c} +#include <uhd.h> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +...and all UHD C-level structs and functions will be available to you. The sections below +give more detail on the key features of the C API. + +\subsection c_api_handles C-Level Handles + +Most of the UHD classes that can be accessed on the C level are done so through handles, +which internally store the C++ representation and allow access to internal values +through helper functions. + +All handles have associated *_make() and *_free() functions. After creating a handle, it must +be passed through its make() function before it can be used in your program. Before the program +terminates, you must pass the handle into its free() function, or your program will have a memory +leak. The example below shows the proper usage of an RX metadata handle over the course of its +lifetime, from instantiation to destruction. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +uhd_rx_metadata_handle md; +uhd_rx_metadata_make(&md); + +// Streaming here puts useful information into metadata +time_t full_secs; +double frac_secs; +uhd_rx_metadata_time_spec(md, &full_secs, &frac_secs); + +uhd_rx_metadata_free(&md); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Again, make sure to pass your handle into a make() function before using it, or you will +run into undefined behavior. Also be careful not to use the handle after passing it into +a free() function, or your program will segfault. + +\subsection c_api_errorcode Error Codes + +As C cannot handle C++ runtime exceptions, UHD's C wrapper functions catch all exceptions +and translate them into error codes, which are returned by each function. Any output variables +are passed in as pointers into the function, which will set them internally. + +Each uhd::runtime_error has a corresponding ::uhd_error value. Separate error codes indicate +that a boost::exception or std::exception has been thrown, and any other exceptions are +indicated by a catch-all ::UHD_ERROR_UNKNOWN code. + +All UHD C-level handles store the string representation of the last C++ exception thrown internally. +These handles have corresponding *_get_last_error() functions that will place the error string into a +supplied string buffer. + +For example, if a USRP device's handle throws an exception internally, the following code can access +its error info: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +char err_msg[256]; +uhd_usrp_handle usrp; +double gain; +// USRP configuration done here +uhd_error error_code = uhd_usrp_get_rx_gain(usrp, 0, "", &gain); +if(error_code){ + uhd_usrp_get_last_error(usrp, err_msg, 256); + fprintf(stderr, "Error code %d: %s\n", error_code, err_msg); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +All error codes can be found in <uhd/error.h>. + +\subsection c_api_examples Example Code + +UHD provides two examples that demonstrate the typical use case of the C API: RX and TX streaming. +The <b>rx_samples_c</b> example is a simplified C version of <b>rx_samples_to_file</b>, +and the <b>tx_samples_c</b> example is a simplified C version of <b>tx_waveforms</b>. These examples +can be easily adapted or serve as a starting point for your own UHD C applications. + +*/ +// vim:ft=doxygen: diff --git a/host/docs/coding.dox b/host/docs/coding.dox index 32dbe944a..6a15098d7 100644 --- a/host/docs/coding.dox +++ b/host/docs/coding.dox @@ -16,6 +16,11 @@ The Multi-USRP-Clock class provides a high-level interface to a single clock device or set of clock devices, from which the time can be queried. See the documentation for uhd::usrp_clock::multi_usrp_clock. +\subsection coding_api_hilevelc High-Level: The C API + +Both USRP and clock devices can be interacted with using a C API wrapper included +by default in all UHD builds. More information can be found \subpage page_c_api "here". + \subsection coding_api_lowlevel Low-Level: The device API A device is an abstraction for hardware that is connected to the host 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..2321a0d94 --- /dev/null +++ b/host/examples/getopt/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# 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 + ${CMAKE_CURRENT_SOURCE_DIR}/getopt1.c +) diff --git a/host/examples/getopt/getopt.c b/host/examples/getopt/getopt.c new file mode 100644 index 000000000..ad9ec2f9b --- /dev/null +++ b/host/examples/getopt/getopt.c @@ -0,0 +1,1056 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. + Ditto for AIX 3.2 and <stdlib.h>. */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include <stdio.h> + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include <gnu-versions.h> +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include <stdlib.h> +# include <unistd.h> +#endif /* GNU C library. */ + +#ifdef VMS +# include <unixlib.h> +# if HAVE_STRING_H - 0 +# include <string.h> +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. */ +# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC +# include <libintl.h> +# ifndef _ +# define _(msgid) gettext (msgid) +# endif +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include <string.h> +# define my_index strchr +#else + +#include <string.h> + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +#ifdef _MSC_VER +// DDK will complain if you don't use the stdlib defined getenv +#include <stdlib.h> +#else +extern char *getenv (); +#endif +#endif + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Stored original parameters. + XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ +extern int __libc_argc; +extern char **__libc_argv; + +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +# ifdef USE_NONOPTION_FLAGS +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; +# endif + +# ifdef USE_NONOPTION_FLAGS +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +# else +# define SWAP_FLAGS(ch1, ch2) +# endif +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + if (posixly_correct == NULL + && argc == __libc_argc && argv == __libc_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + int print_errors = opterr; + if (optstring[0] == ':') + print_errors = 0; + + if (argc < 1) + return -1; + + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#if defined _LIBC && defined USE_NONOPTION_FLAGS +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else if (long_only + || pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (print_errors) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + } + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (print_errors) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (print_errors) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p != NULL && p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/host/examples/getopt/getopt.h b/host/examples/getopt/getopt.h new file mode 100644 index 000000000..a1b8dd665 --- /dev/null +++ b/host/examples/getopt/getopt.h @@ -0,0 +1,180 @@ +/* Declarations for getopt. + Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _GETOPT_H + +#ifndef __need_getopt +# define _GETOPT_H 1 +#endif + +/* If __GNU_LIBRARY__ is not already defined, either we are being used + standalone, or this is the first header included in the source file. + If we are being used with glibc, we need to include <features.h>, but + that does not exist if we are standalone. So: if __GNU_LIBRARY__ is + not defined, include <ctype.h>, which will pull in <features.h> for us + if it's from glibc. (Why ctype.h? It's guaranteed to exist and it + doesn't flood the namespace with stuff the way some other headers do.) */ +#if !defined __GNU_LIBRARY__ +# include <ctype.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +#ifndef __need_getopt +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +# if (defined __STDC__ && __STDC__) || defined __cplusplus + const char *name; +# else + char *name; +# endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +#endif /* need getopt */ + + +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +#if (defined __STDC__ && __STDC__) || defined __cplusplus +# ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int __argc, char *const *__argv, const char *__shortopts); +# else /* not __GNU_LIBRARY__ */ +extern int getopt (); +# endif /* __GNU_LIBRARY__ */ + +# ifndef __need_getopt +extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, + const struct option *__longopts, int *__longind); +extern int getopt_long_only (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only); +# endif +#else /* not __STDC__ */ +extern int getopt (); +# ifndef __need_getopt +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +# endif +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +/* Make sure we later can get all the definitions and declarations. */ +#undef __need_getopt + +#endif /* getopt.h */ diff --git a/host/examples/getopt/getopt1.c b/host/examples/getopt/getopt1.c new file mode 100644 index 000000000..22a7efbdd --- /dev/null +++ b/host/examples/getopt/getopt1.c @@ -0,0 +1,188 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "getopt.h" + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include <stdio.h> + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include <gnu-versions.h> +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include <stdlib.h> +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include <stdio.h> + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ 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; +} diff --git a/host/examples/tx_samples_c.c b/host/examples/tx_samples_c.c new file mode 100644 index 000000000..5a4b79005 --- /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_usrp, + uhd_usrp_make(&usrp, device_args) + ) + + // Create TX streamer + uhd_tx_streamer_handle tx_streamer; + EXECUTE_OR_GOTO(free_tx_streamer, + uhd_tx_streamer_make(&tx_streamer) + ) + + // Create TX metadata + uhd_tx_metadata_handle md; + EXECUTE_OR_GOTO(free_tx_metadata, + 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){ + 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" : "Success")); + + return return_code; +} diff --git a/host/include/CMakeLists.txt b/host/include/CMakeLists.txt index 780213918..8b1e6bc05 100644 --- a/host/include/CMakeLists.txt +++ b/host/include/CMakeLists.txt @@ -20,4 +20,11 @@ CONFIGURE_FILE( ${CMAKE_CURRENT_BINARY_DIR}/config.h ) +IF(ENABLE_C_API) + UHD_INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/uhd.h + DESTINATION ${INCLUDE_DIR} + COMPONENT headers + ) +ENDIF(ENABLE_C_API) + ADD_SUBDIRECTORY(uhd) diff --git a/host/include/uhd.h b/host/include/uhd.h new file mode 100644 index 000000000..0ecafa88a --- /dev/null +++ b/host/include/uhd.h @@ -0,0 +1,40 @@ +/* + * 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/>. + */ + +#ifndef INCLUDED_UHD_H +#define INCLUDED_UHD_H + +#include <uhd/config.h> +#include <uhd/error.h> + +#include <uhd/types/metadata.h> +#include <uhd/types/ranges.h> +#include <uhd/types/sensors.h> +#include <uhd/types/tune_request.h> +#include <uhd/types/tune_result.h> +#include <uhd/types/usrp_info.h> + +#include <uhd/usrp/dboard_eeprom.h> +#include <uhd/usrp/mboard_eeprom.h> +#include <uhd/usrp/subdev_spec.h> +#include <uhd/usrp/usrp.h> + +#include <uhd/usrp_clock/usrp_clock.h> + +#include <uhd/utils/thread_priority.h> + +#endif /* INCLUDED_UHD_H */ diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index f6123aa90..083ec4951 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2011,2013-2014 Ettus Research LLC +# Copyright 2010-2011,2013-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 @@ -40,3 +40,12 @@ UHD_INSTALL(FILES DESTINATION ${INCLUDE_DIR}/uhd COMPONENT headers ) + +IF(ENABLE_C_API) + UHD_INSTALL(FILES + config.h + error.h + DESTINATION ${INCLUDE_DIR}/uhd + COMPONENT headers + ) +ENDIF(ENABLE_C_API) diff --git a/host/include/uhd/config.h b/host/include/uhd/config.h new file mode 100644 index 000000000..1d6cefcc0 --- /dev/null +++ b/host/include/uhd/config.h @@ -0,0 +1,82 @@ +// +// 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/>. +// + +#ifndef INCLUDED_UHD_CONFIG_H +#define INCLUDED_UHD_CONFIG_H + +#ifdef _MSC_VER +// Bring in "and", "or", and "not" +#include <iso646.h> + +// Define ssize_t +#include <stddef.h> +typedef ptrdiff_t ssize_t; + +#endif /* _MSC_VER */ + +// Define cross-platform macros +#if defined(_MSC_VER) + #define UHD_EXPORT __declspec(dllexport) + #define UHD_IMPORT __declspec(dllimport) + #define UHD_INLINE __forceinline + #define UHD_DEPRECATED __declspec(deprecated) + #define UHD_ALIGNED(x) __declspec(align(x)) + #define UHD_UNUSED(x) x +#elif defined(__MINGW32__) + #define UHD_EXPORT __declspec(dllexport) + #define UHD_IMPORT __declspec(dllimport) + #define UHD_INLINE inline + #define UHD_DEPRECATED __declspec(deprecated) + #define UHD_ALIGNED(x) __declspec(align(x)) + #define UHD_UNUSED(x) x __attribute__((unused)) +#elif defined(__GNUG__) && __GNUG__ >= 4 + #define UHD_EXPORT __attribute__((visibility("default"))) + #define UHD_IMPORT __attribute__((visibility("default"))) + #define UHD_INLINE inline __attribute__((always_inline)) + #define UHD_DEPRECATED __attribute__((deprecated)) + #define UHD_ALIGNED(x) __attribute__((aligned(x))) + #define UHD_UNUSED(x) x __attribute__((unused)) +#else + #define UHD_EXPORT + #define UHD_IMPORT + #define UHD_INLINE inline + #define UHD_DEPRECATED + #define UHD_ALIGNED(x) + #define UHD_UNUSED(x) x +#endif + +// API declaration macro +#ifdef UHD_DLL_EXPORTS + #define UHD_API UHD_EXPORT +#else + #define UHD_API UHD_IMPORT +#endif // UHD_DLL_EXPORTS + +// Platform defines for conditional code: +// Taken from boost/config/select_platform_config.hpp, +// However, we define macros, not strings, for platforms. +#if defined(linux) || defined(__linux) || defined(__linux__) + #define UHD_PLATFORM_LINUX +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #define UHD_PLATFORM_WIN32 +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) + #define UHD_PLATFORM_MACOS +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + #define UHD_PLATFORM_BSD +#endif + +#endif /* INCLUDED_UHD_CONFIG_H */ diff --git a/host/include/uhd/error.h b/host/include/uhd/error.h new file mode 100644 index 000000000..845d741dc --- /dev/null +++ b/host/include/uhd/error.h @@ -0,0 +1,136 @@ +/* + * 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/>. + */ + +#ifndef INCLUDED_UHD_ERROR_H +#define INCLUDED_UHD_ERROR_H + +//! UHD error codes +/*! + * Each error code corresponds to a specific uhd::exception, with + * extra codes corresponding to a boost::exception, std::exception, + * and a catch-all for everything else. When an internal C++ function + * throws an exception, UHD converts it to one of these error codes + * to return on the C level. + */ +typedef enum { + + //! No error thrown. + UHD_ERROR_NONE = 0, + //! Invalid device arguments. + UHD_ERROR_INVALID_DEVICE = 1, + + //! See uhd::index_error. + UHD_ERROR_INDEX = 10, + //! See uhd::key_error. + UHD_ERROR_KEY = 11, + + //! See uhd::not_implemented_error. + UHD_ERROR_NOT_IMPLEMENTED = 20, + //! See uhd::usb_error. + UHD_ERROR_USB = 21, + + //! See uhd::io_error. + UHD_ERROR_IO = 30, + //! See uhd::os_error. + UHD_ERROR_OS = 31, + + //! See uhd::assertion_error. + UHD_ERROR_ASSERTION = 40, + //! See uhd::lookup_error. + UHD_ERROR_LOOKUP = 41, + //! See uhd::type_error. + UHD_ERROR_TYPE = 42, + //! See uhd::value_error. + UHD_ERROR_VALUE = 43, + //! See uhd::runtime_error. + UHD_ERROR_RUNTIME = 44, + //! See uhd::environment_error. + UHD_ERROR_ENVIRONMENT = 45, + //! See uhd::system_error. + UHD_ERROR_SYSTEM = 46, + //! See uhd::exception. + UHD_ERROR_EXCEPT = 47, + + //! A boost::exception was thrown. + UHD_ERROR_BOOSTEXCEPT = 60, + + //! A std::exception was thrown. + UHD_ERROR_STDEXCEPT = 70, + + //! An unknown error was thrown. + UHD_ERROR_UNKNOWN = 100 +} uhd_error; + +#ifdef __cplusplus +#include <uhd/config.hpp> +#include <uhd/exception.hpp> + +#include <boost/exception/diagnostic_information.hpp> + +UHD_API uhd_error error_from_uhd_exception(const uhd::exception* e); + +/*! + * This macro runs the given C++ code, and if there are any exceptions + * thrown, they are caught and converted to the corresponding UHD error + * code. + */ +#define UHD_SAFE_C(...) \ + try{ __VA_ARGS__ } \ + catch (const uhd::exception &e) { \ + return error_from_uhd_exception(&e); \ + } \ + catch (const boost::exception&) { \ + return UHD_ERROR_BOOSTEXCEPT; \ + } \ + catch (const std::exception&) { \ + return UHD_ERROR_STDEXCEPT; \ + } \ + catch (...) { \ + return UHD_ERROR_UNKNOWN; \ + } \ + return UHD_ERROR_NONE; + +/*! + * This macro runs the given C++ code, and if there are any exceptions + * thrown, they are caught and converted to the corresponding UHD error + * code. The error message is also saved into the given handle. + */ +#define UHD_SAFE_C_SAVE_ERROR(h, ...) \ + h->last_error.clear(); \ + try{ __VA_ARGS__ } \ + catch (const uhd::exception &e) { \ + h->last_error = e.what(); \ + return error_from_uhd_exception(&e); \ + } \ + catch (const boost::exception &e) { \ + h->last_error = boost::diagnostic_information(e); \ + return UHD_ERROR_BOOSTEXCEPT; \ + } \ + catch (const std::exception &e) { \ + h->last_error = e.what(); \ + return UHD_ERROR_STDEXCEPT; \ + } \ + catch (...) { \ + h->last_error = "Unrecognized exception caught."; \ + return UHD_ERROR_UNKNOWN; \ + } \ + h->last_error = "None"; \ + return UHD_ERROR_NONE; + +#endif + +#endif /* INCLUDED_UHD_ERROR_H */ diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index 2a25df35f..140b5c710 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -42,3 +42,16 @@ UHD_INSTALL(FILES DESTINATION ${INCLUDE_DIR}/uhd/types COMPONENT headers ) + +IF(ENABLE_C_API) + UHD_INSTALL(FILES + metadata.h + ranges.h + sensors.h + tune_request.h + tune_result.h + usrp_info.h + DESTINATION ${INCLUDE_DIR}/uhd/types + COMPONENT headers + ) +ENDIF(ENABLE_C_API) diff --git a/host/include/uhd/types/metadata.h b/host/include/uhd/types/metadata.h new file mode 100644 index 000000000..0cdbc6a72 --- /dev/null +++ b/host/include/uhd/types/metadata.h @@ -0,0 +1,364 @@ +/* + * Copyright 2015 Ettus Research + * + * 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/>. + */ + +#ifndef INCLUDED_UHD_TYPES_METADATA_H +#define INCLUDED_UHD_TYPES_METADATA_H + +#include <uhd/config.h> +#include <uhd/error.h> + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <time.h> + +#ifdef __cplusplus +#include <uhd/types/metadata.hpp> +#include <string> + +struct uhd_rx_metadata_t { + uhd::rx_metadata_t rx_metadata_cpp; + std::string last_error; +}; + +struct uhd_tx_metadata_t { + uhd::tx_metadata_t tx_metadata_cpp; + std::string last_error; +}; + +struct uhd_async_metadata_t { + uhd::async_metadata_t async_metadata_cpp; + std::string last_error; +}; + +extern "C" { +#else +struct uhd_rx_metadata_t; +struct uhd_tx_metadata_t; +struct uhd_async_metadata_t; +#endif + +//! RX metadata interface for describing sent IF data. +/*! + * See uhd::rx_metadata_t for details. + * + * NOTE: Using this handle before calling uhd_rx_metadata_make() will + * result in undefined behavior. + */ +typedef struct uhd_rx_metadata_t* uhd_rx_metadata_handle; + +//! TX metadata interface for describing received IF data. +/*! + * See uhd::tx_metadata_t for details. + * + * NOTE: Using this handle before calling uhd_tx_metadata_make() will + * result in undefined behavior. + */ +typedef struct uhd_tx_metadata_t* uhd_tx_metadata_handle; + +//! Interface for describing transmit-related events. +/*! + * See uhd::async_metadata_t for details. + * + * NOTE: Using this handle before calling uhd_async_metadata_make() will + * result in undefined behavior. + */ +typedef struct uhd_async_metadata_t* uhd_async_metadata_handle; + +//! Error condition on a receive call +/*! + * See uhd::rx_metadata_t::error_code_t for more details. + */ +typedef enum { + //! No error code associated with this metadata + UHD_RX_METADATA_ERROR_CODE_NONE = 0x0, + //! No packet received, implementation timed out + UHD_RX_METADATA_ERROR_CODE_TIMEOUT = 0x1, + //! A stream command was issued in the past + UHD_RX_METADATA_ERROR_CODE_LATE_COMMAND = 0x2, + //! Expected another stream command + UHD_RX_METADATA_ERROR_CODE_BROKEN_CHAIN = 0x4, + //! Overflow or sequence error + UHD_RX_METADATA_ERROR_CODE_OVERFLOW = 0x8, + //! Multi-channel alignment failed + UHD_RX_METADATA_ERROR_CODE_ALIGNMENT = 0xC, + //! The packet could not be parsed + UHD_RX_METADATA_ERROR_CODE_BAD_PACKET = 0xF +} uhd_rx_metadata_error_code_t; + + +//! Create a new RX metadata handle +UHD_API uhd_error uhd_rx_metadata_make( + uhd_rx_metadata_handle* handle +); + +//! Free an RX metadata handle +/*! + * Using a handle after freeing it here will result in a segmentation fault. + */ +UHD_API uhd_error uhd_rx_metadata_free( + uhd_rx_metadata_handle* handle +); + +//! Has time specification? +UHD_API uhd_error uhd_rx_metadata_has_time_spec( + uhd_rx_metadata_handle h, + bool *result_out +); + +//! Time of first sample +UHD_API uhd_error uhd_rx_metadata_time_spec( + uhd_rx_metadata_handle h, + time_t *full_secs_out, + double *frac_secs_out +); + +//! Fragmentation flag +UHD_API uhd_error uhd_rx_metadata_more_fragments( + uhd_rx_metadata_handle h, + bool *result_out +); + +//! Fragmentation offset +UHD_API uhd_error uhd_rx_metadata_fragment_offset( + uhd_rx_metadata_handle h, + size_t *fragment_offset_out +); + +//! Start of burst? +UHD_API uhd_error uhd_rx_metadata_start_of_burst( + uhd_rx_metadata_handle h, + bool *result_out +); + +//! End of burst? +UHD_API uhd_error uhd_rx_metadata_end_of_burst( + uhd_rx_metadata_handle h, + bool *result_out +); + +//! Result out of sequence? +UHD_API uhd_error uhd_rx_metadata_out_of_sequence( + uhd_rx_metadata_handle h, + bool *result_out +); + +//! Return a pretty-print representation of this metadata. +/*! + * NOTE: This function will overwrite any string in the given buffer + * before inserting the pp_string. + * + * \param h metadata handle + * \param pp_string_out string buffer for pp_string + * \param buffer length + */ +UHD_API uhd_error uhd_rx_metadata_to_pp_string( + uhd_rx_metadata_handle h, + char* pp_string_out, + size_t strbuffer_len +); + +//! Get the last error state of the RX metadata object. +UHD_API uhd_error uhd_rx_metadata_error_code( + uhd_rx_metadata_handle h, + uhd_rx_metadata_error_code_t *error_code_out +); + +//! Get a string representation of the last error state of the RX metadata object. +/*! + * NOTES: + * <ul> + * <li>This is different from the error that can be retrieved with + * uhd_rx_metadata_last_error. See uhd::rx_metadata_t::strerror() for details.</li> + * <li>This function will overwrite any string in the given buffer before + * inserting the error string.</li> + * </ul> + * + * \param h metadata handle + * \param strerror_out string buffer for strerror + * \param buffer length + */ +UHD_API uhd_error uhd_rx_metadata_strerror( + uhd_rx_metadata_handle h, + char* strerror_out, + size_t strbuffer_len +); + +//! Get the last error logged by the RX metadata object. +/*! + * NOTES: + * <ul> + * <li>This is different from the error that can be retrieved with + * uhd_rx_metadata_strerror(). See <uhd/error.h> for details.</li> + * <li>This function will overwrite any string in the given buffer before + * inserting the error string.</li> + * </ul> + * + * \param h metadata handle + * \param error_out string buffer for error + * \param buffer length + */ +UHD_API uhd_error uhd_rx_metadata_last_error( + uhd_rx_metadata_handle h, + char* error_out, + size_t strbuffer_len +); + +//! Create a new TX metadata handle +UHD_API uhd_error uhd_tx_metadata_make( + uhd_tx_metadata_handle* handle, + bool has_time_spec, + time_t full_secs, + double frac_secs, + bool start_of_burst, + bool end_of_burst +); + + +//! Free an TX metadata handle +/*! + * Using a handle after freeing it here will result in a segmentation fault. + */ +UHD_API uhd_error uhd_tx_metadata_free( + uhd_tx_metadata_handle* handle +); + +//! Has time specification? +UHD_API uhd_error uhd_tx_metadata_has_time_spec( + uhd_tx_metadata_handle h, + bool *result_out +); + +//! Get time specification +UHD_API uhd_error uhd_tx_metadata_time_spec( + uhd_tx_metadata_handle h, + time_t *full_secs_out, + double *frac_secs_out +); + +//! Start of burst? +UHD_API uhd_error uhd_tx_metadata_start_of_burst( + uhd_tx_metadata_handle h, + bool *result_out +); + +//! End of burst? +UHD_API uhd_error uhd_tx_metadata_end_of_burst( + uhd_tx_metadata_handle h, + bool *result_out +); + +//! Get the last error logged by the TX metadata object. +/*! + * NOTE: This function will overwrite any string in the given buffer before + * inserting the error string. + * + * \param h metadata handle + * \param error_out string buffer for error + * \param buffer length + */ +UHD_API uhd_error uhd_tx_metadata_last_error( + uhd_tx_metadata_handle h, + char* error_out, + size_t strbuffer_len +); + +//! The type of event for a receive async message call. +/*! + * See uhd::async_metadata_t::event_code_t for more details. + */ +typedef enum { + //! A burst was successfully transmitted. + UHD_ASYNC_METADATA_EVENT_CODE_BURST_ACK = 0x1, + //! An internal send buffer has emptied. + UHD_ASYNC_METADATA_EVENT_CODE_UNDERFLOW = 0x2, + //! Packet loss error between host and device. + UHD_ASYNC_METADATA_EVENT_CODE_SEQ_ERROR = 0x4, + //! Packet had time that was late. + UHD_ASYNC_METADATA_EVENT_CODE_TIME_ERROR = 0x8, + //! Underflow occurred inside a packet. + UHD_ASYNC_METADATA_EVENT_CODE_UNDERFLOW_IN_PACKET = 0x10, + //! Packet loss within a burst. + UHD_ASYNC_METADATA_EVENT_CODE_SEQ_ERROR_IN_BURST = 0x20, + //! Some kind of custom user payload. + UHD_ASYNC_METADATA_EVENT_CODE_USER_PAYLOAD = 0x40 +} uhd_async_metadata_event_code_t; + +//! Create a new async metadata handle +UHD_API uhd_error uhd_async_metadata_make( + uhd_async_metadata_handle* handle +); + +//! Free an async metadata handle +/*! + * Using a handle after freeing it will result in a segmentation fault. + */ +UHD_API uhd_error uhd_async_metadata_free( + uhd_async_metadata_handle* handle +); + +//! Channel number in a MIMO configuration +UHD_API uhd_error uhd_async_metadata_channel( + uhd_async_metadata_handle h, + size_t *channel_out +); + +//! Has time specification? +UHD_API uhd_error uhd_async_metadata_has_time_spec( + uhd_async_metadata_handle h, + bool *result_out +); + +//! Get time specification +UHD_API uhd_error uhd_async_metadata_time_spec( + uhd_async_metadata_handle h, + time_t *full_secs_out, + double *frac_secs_out +); + +//! Get last event code +UHD_API uhd_error uhd_async_metadata_event_code( + uhd_async_metadata_handle h, + uhd_async_metadata_event_code_t *event_code_out +); + +//! Get payload from custom FPGA fabric +UHD_API uhd_error uhd_async_metadata_user_payload( + uhd_async_metadata_handle h, + uint32_t user_payload_out[4] +); + +//! Get the last error logged by the async metadata object. +/*! + * NOTE: This function will overwrite any string in the given buffer before + * inserting the error string. + * + * \param h metadata handle + * \param error_out string buffer for error + * \param buffer length + */ +UHD_API uhd_error uhd_async_metadata_last_error( + uhd_async_metadata_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_TYPES_METADATA_H */ diff --git a/host/include/uhd/types/ranges.h b/host/include/uhd/types/ranges.h new file mode 100644 index 000000000..ca80c9141 --- /dev/null +++ b/host/include/uhd/types/ranges.h @@ -0,0 +1,154 @@ +// +// 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/>. +// + +#ifndef INCLUDED_UHD_TYPES_RANGES_H +#define INCLUDED_UHD_TYPES_RANGES_H + +#include <uhd/config.h> +#include <uhd/error.h> + +#include <stdbool.h> +#include <stdlib.h> + +//! Range of floating-point values +typedef struct { + //! First value + double start; + //! Last value + double stop; + //! Granularity + double step; +} uhd_range_t; + +#ifdef __cplusplus +#include <uhd/types/ranges.hpp> +#include <string> + +struct uhd_meta_range_t { + uhd::meta_range_t meta_range_cpp; + std::string last_error; +}; + +extern "C" { +#else +struct uhd_meta_range_t; +#endif + +//! C-level interface for dealing with a list of ranges +/*! + * See uhd::meta_range_t for more details. + */ +typedef struct uhd_meta_range_t* uhd_meta_range_handle; + +//! Get a string representation of the given range +UHD_API uhd_error uhd_range_to_pp_string( + const uhd_range_t *range, + char* pp_string_out, + size_t strbuffer_len +); + +//! Create a meta range handle +/*! + * NOTE: Using a uhd_meta_range_handle before passing it into this function will + * result in undefined behavior. + */ +UHD_API uhd_error uhd_meta_range_make( + uhd_meta_range_handle* h +); + +//! Destroy a meta range handle +/*! + * NOTE: Using a uhd_meta_range_handle after passing it into this function will + * result in a segmentation fault. + */ +UHD_API uhd_error uhd_meta_range_free( + uhd_meta_range_handle* h +); + +//! Get the overall start value for the given meta range +UHD_API uhd_error uhd_meta_range_start( + uhd_meta_range_handle h, + double *start_out +); + +//! Get the overall stop value for the given meta range +UHD_API uhd_error uhd_meta_range_stop( + uhd_meta_range_handle h, + double *stop_out +); + +//! Get the overall step value for the given meta range +UHD_API uhd_error uhd_meta_range_step( + uhd_meta_range_handle h, + double *step_out +); + +//! Clip the given value to a possible value in the given range +UHD_API uhd_error uhd_meta_range_clip( + uhd_meta_range_handle h, + double value, + bool clip_step, + double *result_out +); + +//! Get the number of ranges in the given meta range +UHD_API uhd_error uhd_meta_range_size( + uhd_meta_range_handle h, + size_t *size_out +); + +//! Add a range to the given meta range +UHD_API uhd_error uhd_meta_range_push_back( + uhd_meta_range_handle h, + const uhd_range_t *range +); + +//! Get the range at the given index +UHD_API uhd_error uhd_meta_range_at( + uhd_meta_range_handle h, + size_t num, + uhd_range_t *range_out +); + +//! Get a string representation of the given meta range +UHD_API uhd_error uhd_meta_range_to_pp_string( + uhd_meta_range_handle h, + char* pp_string_out, + size_t strbuffer_len +); + +//! Get the last error recorded by the underlying meta range +UHD_API uhd_error uhd_meta_range_last_error( + uhd_meta_range_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} + +UHD_API uhd::range_t uhd_range_c_to_cpp( + const uhd_range_t *range_c +); + +UHD_API void uhd_range_cpp_to_c( + const uhd::range_t &range_cpp, + uhd_range_t *range_c +); +#endif + +#endif /* INCLUDED_UHD_TYPES_RANGES_H */ diff --git a/host/include/uhd/types/sensors.h b/host/include/uhd/types/sensors.h new file mode 100644 index 000000000..c0037c9f6 --- /dev/null +++ b/host/include/uhd/types/sensors.h @@ -0,0 +1,231 @@ +// +// 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/>. +// + +#ifndef INCLUDED_UHD_TYPES_SENSORS_H +#define INCLUDED_UHD_TYPES_SENSORS_H + +#include <uhd/config.h> +#include <uhd/error.h> + +#ifdef __cplusplus +#include <uhd/types/sensors.hpp> +#include <string> + +struct uhd_sensor_value_t { + // No default constructor, so we need a pointer + uhd::sensor_value_t* sensor_value_cpp; + std::string last_error; +}; +extern "C" { +#else +struct uhd_sensor_value_t; +#endif + +//! C-level interface for a UHD sensor +/*! + * See uhd::sensor_value_t for more details. + * + * NOTE: Using a handle before calling a make function will result in undefined behavior. + */ +typedef struct uhd_sensor_value_t* uhd_sensor_value_handle; + +//! Sensor value types +typedef enum { + UHD_SENSOR_VALUE_BOOLEAN = 98, + UHD_SENSOR_VALUE_INTEGER = 105, + UHD_SENSOR_VALUE_REALNUM = 114, + UHD_SENSOR_VALUE_STRING = 115 +} uhd_sensor_value_data_type_t; + +//! Make a UHD sensor from a boolean. +/*! + * \param h the sensor handle in which to place sensor + * \param name sensor name + * \param value sensor value + * \param utrue string representing "true" + * \param ufalse string representing "false" + * \returns UHD error code + */ +UHD_API uhd_error uhd_sensor_value_make_from_bool( + uhd_sensor_value_handle* h, + const char* name, + bool value, + const char* utrue, + const char* ufalse +); + +//! Make a UHD sensor from an integer. +/*! + * \param h the sensor value in which to place sensor + * \param name sensor name + * \param value sensor value + * \param unit sensor unit + * \param formatter printf-style format string for value string + * \returns UHD error code + */ +UHD_API uhd_error uhd_sensor_value_make_from_int( + uhd_sensor_value_handle* h, + const char* name, + int value, + const char* unit, + const char* formatter +); + +//! Make a UHD sensor from a real number. +/*! + * \param h the sensor value in which to place sensor + * \param name sensor name + * \param value sensor value + * \param unit sensor unit + * \param formatter printf-style format string for value string + * \returns UHD error code + */ +UHD_API uhd_error uhd_sensor_value_make_from_realnum( + uhd_sensor_value_handle* h, + const char* name, + double value, + const char* unit, + const char* formatter +); + +//! Make a UHD sensor from a string. +/*! + * \param h the sensor value in which to place sensor + * \param name sensor name + * \param value sensor value + * \param unit sensor unit + * \returns UHD error code + */ +UHD_API uhd_error uhd_sensor_value_make_from_string( + uhd_sensor_value_handle* h, + const char* name, + const char* value, + const char* unit +); + +//! Free the given sensor handle. +/*! + * Attempting to use the handle after calling this handle will + * result in a segmentation fault. + */ +UHD_API uhd_error uhd_sensor_value_free( + uhd_sensor_value_handle* h +); + +//! Get the sensor's value as a boolean. +UHD_API uhd_error uhd_sensor_value_to_bool( + uhd_sensor_value_handle h, + bool *value_out +); + +//! Get the sensor's value as an integer. +UHD_API uhd_error uhd_sensor_value_to_int( + uhd_sensor_value_handle h, + int *value_out +); + +//! Get the sensor's value as a real number. +UHD_API uhd_error uhd_sensor_value_to_realnum( + uhd_sensor_value_handle h, + double *value_out +); + +//! Get the sensor's name. +/*! + * NOTE: This function will overwrite any string in the given + * buffer before inserting the sensor name. + * + * \param h sensor handle + * \param name_out string buffer in which to place name + * \param strbuffer_len buffer length + */ +UHD_API uhd_error uhd_sensor_value_name( + uhd_sensor_value_handle h, + char* name_out, + size_t strbuffer_len +); + +//! Get the sensor's value. +/*! + * NOTE: This function will overwrite any string in the given + * buffer before inserting the sensor value. + * + * \param h sensor handle + * \param value_out string buffer in which to place value + * \param strbuffer_len buffer length + */ +UHD_API uhd_error uhd_sensor_value_value( + uhd_sensor_value_handle h, + char* value_out, + size_t strbuffer_len +); + +//! Get the sensor's unit. +/*! + * NOTE: This function will overwrite any string in the given + * buffer before inserting the sensor unit. + * + * \param h sensor handle + * \param unit_out string buffer in which to place unit + * \param strbuffer_len buffer length + */ +UHD_API uhd_error uhd_sensor_value_unit( + uhd_sensor_value_handle h, + char* unit_out, + size_t strbuffer_len +); + +UHD_API uhd_error uhd_sensor_value_data_type( + uhd_sensor_value_handle h, + uhd_sensor_value_data_type_t *data_type_out +); + +//! Get a pretty-print representation of the given sensor. +/*! + * NOTE: This function will overwrite any string in the given + * buffer before inserting the string. + * + * \param h sensor handle + * \param pp_string_out string buffer in which to place pp_string + * \param strbuffer_len buffer length + */ +UHD_API uhd_error uhd_sensor_value_to_pp_string( + uhd_sensor_value_handle h, + char* pp_string_out, + size_t strbuffer_len +); + +//! Get the last error logged by the sensor handle. +/*! + * NOTE: This function will overwrite any string in the given + * buffer before inserting the error string. + * + * \param h sensor handle + * \param error_out string buffer in which to place error + * \param strbuffer_len buffer length + */ +UHD_API uhd_error uhd_sensor_value_last_error( + uhd_sensor_value_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_TYPES_SENSORS_H */ diff --git a/host/include/uhd/types/stream_cmd.hpp b/host/include/uhd/types/stream_cmd.hpp index 3c34c9656..c24296bd6 100644 --- a/host/include/uhd/types/stream_cmd.hpp +++ b/host/include/uhd/types/stream_cmd.hpp @@ -1,19 +1,19 @@ -// -// Copyright 2010-2012 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/>. -// +/* + * Copyright 2010-2012,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/>. + */ #ifndef INCLUDED_UHD_TYPES_STREAM_CMD_HPP #define INCLUDED_UHD_TYPES_STREAM_CMD_HPP @@ -59,6 +59,6 @@ namespace uhd{ stream_cmd_t(const stream_mode_t &stream_mode); }; -} //namespace uhd +} /* namespace uhd */ #endif /* INCLUDED_UHD_TYPES_STREAM_CMD_HPP */ diff --git a/host/include/uhd/types/tune_request.h b/host/include/uhd/types/tune_request.h new file mode 100644 index 000000000..046350643 --- /dev/null +++ b/host/include/uhd/types/tune_request.h @@ -0,0 +1,61 @@ +// +// 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/>. +// + +#ifndef INCLUDED_UHD_TYPES_TUNE_REQUEST_H +#define INCLUDED_UHD_TYPES_TUNE_REQUEST_H + +#include <uhd/config.h> + +#include <stdlib.h> + +//! Policy options for tunable elements in the RF chain. +typedef enum { + //! Do not set this argument, use current setting. + UHD_TUNE_REQUEST_POLICY_NONE = 78, + //! Automatically determine the argument's value. + UHD_TUNE_REQUEST_POLICY_AUTO = 65, + //! Use the argument's value for the setting. + UHD_TUNE_REQUEST_POLICY_MANUAL = 77 +} uhd_tune_request_policy_t; + +//! Instructs implementation how to tune the RF chain +/*! + * See uhd::tune_request_t for more details. + */ +typedef struct { + //! Target frequency for RF chain in Hz + double target_freq; + //! RF frequency policy + uhd_tune_request_policy_t rf_freq_policy; + //! RF frequency in Hz + double rf_freq; + //! DSP frequency policy + uhd_tune_request_policy_t dsp_freq_policy; + //! DSP frequency in Hz + double dsp_freq; + //! Key-value pairs delimited by commas + char* args; +} uhd_tune_request_t; + +#ifdef __cplusplus +#include <uhd/types/tune_request.hpp> + +UHD_API uhd::tune_request_t uhd_tune_request_c_to_cpp(uhd_tune_request_t *tune_request_c); + +#endif + +#endif /* INCLUDED_UHD_TYPES_TUNE_REQUEST_H */ diff --git a/host/include/uhd/types/tune_result.h b/host/include/uhd/types/tune_result.h new file mode 100644 index 000000000..e0d00cd2e --- /dev/null +++ b/host/include/uhd/types/tune_result.h @@ -0,0 +1,60 @@ +// +// 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/>. +// + +#ifndef INCLUDED_UHD_TYPES_TUNE_RESULT_H +#define INCLUDED_UHD_TYPES_TUNE_RESULT_H + +#include <uhd/config.h> + +#include <stdlib.h> + +//! Stores RF and DSP tuned frequencies. +/*! + * See uhd::tune_result_t for more details. + */ +typedef struct { + //! Target RF frequency, clipped to be within system range + double clipped_rf_freq; + //! Target RF frequency, including RF FE offset + double target_rf_freq; + //! Frequency to which RF LO is actually tuned + double actual_rf_freq; + //! Frequency the CORDIC must adjust the RF + double target_dsp_freq; + //! Frequency to which the CORDIC in the DSP actually tuned + double actual_dsp_freq; +} uhd_tune_result_t; + +#ifdef __cplusplus +extern "C" { +#endif + +//! Create a pretty print representation of this tune result. +UHD_API void uhd_tune_result_to_pp_string(uhd_tune_result_t *tune_result, + char* pp_string_out, size_t strbuffer_len); + +#ifdef __cplusplus +} +#include <uhd/types/tune_result.hpp> + +UHD_API uhd::tune_result_t uhd_tune_result_c_to_cpp(uhd_tune_result_t *tune_result_c); + +UHD_API void uhd_tune_result_cpp_to_c(const uhd::tune_result_t &tune_result_cpp, + uhd_tune_result_t *tune_result_c); +#endif + +#endif /* INCLUDED_UHD_TYPES_TUNE_RESULT_H */ diff --git a/host/include/uhd/types/usrp_info.h b/host/include/uhd/types/usrp_info.h new file mode 100644 index 000000000..c118963da --- /dev/null +++ b/host/include/uhd/types/usrp_info.h @@ -0,0 +1,94 @@ +/* + * 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/>. + */ + +#ifndef INCLUDED_UHD_TYPES_USRP_INFO_H +#define INCLUDED_UHD_TYPES_USRP_INFO_H + +#include <uhd/config.h> +#include <uhd/error.h> + +//! USRP RX info +/*! + * This struct is populated by uhd_usrp_get_rx_info(). + */ +typedef struct { + //! Motherboard ID + char* mboard_id; + //! Motherboard name + char* mboard_name; + //! Motherboard serial + char* mboard_serial; + //! RX daughterboard ID + char* rx_id; + //! RX subdev name + char* rx_subdev_name; + //! RX subdev spec + char* rx_subdev_spec; + //! RX daughterboard serial + char* rx_serial; + //! RX daughterboard antenna + char* rx_antenna; +} uhd_usrp_rx_info_t; + +//! USRP TX info +/*! + * This struct is populated by uhd_usrp_get_tx_info(). + */ +typedef struct { + //! Motherboard ID + char* mboard_id; + //! Motherboard name + char* mboard_name; + //! Motherboard serial + char* mboard_serial; + //! TX daughterboard ID + char* tx_id; + //! TX subdev name + char* tx_subdev_name; + //! TX subdev spec + char* tx_subdev_spec; + //! TX daughterboard serial + char* tx_serial; + //! TX daughterboard antenna + char* tx_antenna; +} uhd_usrp_tx_info_t; + +#ifdef __cplusplus +extern "C" { +#endif + +//! Clean up a uhd_usrp_rx_info_t populated by uhd_usrp_get_rx_info(). +/*! + * NOTE: If this function is passed a uhd_usrp_rx_info_t that has not + * been populated by uhd_usrp_get_rx_info(), it will produce a double-free + * error. + */ +UHD_API uhd_error uhd_usrp_rx_info_free(uhd_usrp_rx_info_t *rx_info); + +//! Clean up a uhd_usrp_tx_info_t populated by uhd_usrp_get_tx_info(). +/*! + * NOTE: If this function is passed a uhd_usrp_tx_info_t that has not + * been populated by uhd_usrp_get_tx_info(), it will produce a double-free + * error. + */ +UHD_API uhd_error uhd_usrp_tx_info_free(uhd_usrp_tx_info_t *tx_info); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_TYPES_USRP_INFO_H */ diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index d30a2900a..e974f808d 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2011 Ettus Research LLC +# Copyright 2010-2011,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 @@ -15,7 +15,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # - UHD_INSTALL(FILES #### dboard headers ### @@ -36,3 +35,14 @@ UHD_INSTALL(FILES DESTINATION ${INCLUDE_DIR}/uhd/usrp COMPONENT headers ) + +IF(ENABLE_C_API) + UHD_INSTALL(FILES + dboard_eeprom.h + mboard_eeprom.h + subdev_spec.h + usrp.h + DESTINATION ${INCLUDE_DIR}/uhd/usrp + COMPONENT headers + ) +ENDIF(ENABLE_C_API) diff --git a/host/include/uhd/usrp/dboard_eeprom.h b/host/include/uhd/usrp/dboard_eeprom.h new file mode 100644 index 000000000..6980de0ce --- /dev/null +++ b/host/include/uhd/usrp/dboard_eeprom.h @@ -0,0 +1,110 @@ +// +// 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/>. +// + +#ifndef INCLUDED_UHD_USRP_DBOARD_EEPROM_H +#define INCLUDED_UHD_USRP_DBOARD_EEPROM_H + +#include <uhd/config.h> +#include <uhd/error.h> + +#ifdef __cplusplus +#include <uhd/usrp/dboard_eeprom.hpp> +#include <string> + +struct uhd_dboard_eeprom_t { + uhd::usrp::dboard_eeprom_t dboard_eeprom_cpp; + std::string last_error; +}; + +extern "C" { +#else +struct uhd_dboard_eeprom_t; +#endif + +//! A C-level interface for interacting with a daughterboard EEPROM +/*! + * See uhd::usrp::dboard_eeprom_t for more details. + * + * NOTE: Using a handle before passing it into uhd_dboard_eeprom_make() will + * result in undefined behavior. + */ +typedef struct uhd_dboard_eeprom_t* uhd_dboard_eeprom_handle; + +//! Create handle for a USRP daughterboard EEPROM +UHD_API uhd_error uhd_dboard_eeprom_make( + uhd_dboard_eeprom_handle* h +); + +//! Safely destroy the given handle +/*! + * NOTE: Using a handle after passing it into this function will result in + * a segmentation fault. + */ +UHD_API uhd_error uhd_dboard_eeprom_free( + uhd_dboard_eeprom_handle* h +); + +//! Get the ID associated with the given daughterboard as a string hex representation +UHD_API uhd_error uhd_dboard_eeprom_get_id( + uhd_dboard_eeprom_handle h, + char* id_out, + size_t strbuffer_len +); + +//! Set the daughterboard ID using a string hex representation +UHD_API uhd_error uhd_dboard_eeprom_set_id( + uhd_dboard_eeprom_handle h, + const char* id +); + +//! Get the daughterboard's serial +UHD_API uhd_error uhd_dboard_eeprom_get_serial( + uhd_dboard_eeprom_handle h, + char* serial_out, + size_t strbuffer_len +); + +//! Set the daughterboard's serial +UHD_API uhd_error uhd_dboard_eeprom_set_serial( + uhd_dboard_eeprom_handle h, + const char* serial +); + +//! Get the daughterboard's revision (not always present) +UHD_API uhd_error uhd_dboard_eeprom_get_revision( + uhd_dboard_eeprom_handle h, + int* revision_out +); + +//! Set the daughterboard's revision +UHD_API uhd_error uhd_dboard_eeprom_set_revision( + uhd_dboard_eeprom_handle h, + int revision +); + +//! Get the last error reported by the handle +UHD_API uhd_error uhd_dboard_eeprom_last_error( + uhd_dboard_eeprom_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_USRP_DBOARD_EEPROM_H */ diff --git a/host/include/uhd/usrp/mboard_eeprom.h b/host/include/uhd/usrp/mboard_eeprom.h new file mode 100644 index 000000000..b4474a26d --- /dev/null +++ b/host/include/uhd/usrp/mboard_eeprom.h @@ -0,0 +1,87 @@ +// +// 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/>. +// + +#ifndef INCLUDED_UHD_USRP_MBOARD_EEPROM_H +#define INCLUDED_UHD_USRP_MBOARD_EEPROM_H + +#include <uhd/config.h> +#include <uhd/error.h> + +#ifdef __cplusplus +#include <uhd/usrp/mboard_eeprom.hpp> +#include <string> + +struct uhd_mboard_eeprom_t { + uhd::usrp::mboard_eeprom_t mboard_eeprom_cpp; + std::string last_error; +}; + +extern "C" { +#else +struct uhd_mboard_eeprom_t; +#endif + +//! A C-level interface for interacting with a USRP motherboard's EEPROM +/*! + * See uhd::usrp::mboard_eeprom_t for more details. + * + * NOTE: Using a handle before passing it into uhd_mboard_eeprom_make() will + * result in undefined behavior. + */ +typedef struct uhd_mboard_eeprom_t* uhd_mboard_eeprom_handle; + +//! Create a handle for working with a USRP motherboard EEPROM +UHD_API uhd_error uhd_mboard_eeprom_make( + uhd_mboard_eeprom_handle* h +); + +//! Free a USRP motherboard EEPROM handle +/*! + * NOTE: Using a handle after passing it into this function will result in + * a segmentation fault. + */ +UHD_API uhd_error uhd_mboard_eeprom_free( + uhd_mboard_eeprom_handle* h +); + +//! Get the value associated with the given EEPROM key +UHD_API uhd_error uhd_mboard_eeprom_get_value( + uhd_mboard_eeprom_handle h, + const char* key, + char* value_out, + size_t strbuffer_len +); + +//! Set the value for the given EEPROM key +UHD_API uhd_error uhd_mboard_eeprom_set_value( + uhd_mboard_eeprom_handle h, + const char* key, + const char* value +); + +//! Get the last error recorded by the handle +UHD_API uhd_error uhd_mboard_eeprom_last_error( + uhd_mboard_eeprom_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_USRP_MBOARD_EEPROM_H */ diff --git a/host/include/uhd/usrp/subdev_spec.h b/host/include/uhd/usrp/subdev_spec.h new file mode 100644 index 000000000..f847181b7 --- /dev/null +++ b/host/include/uhd/usrp/subdev_spec.h @@ -0,0 +1,137 @@ +// +// 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/>. +// + +#ifndef INCLUDED_UHD_USRP_SUBDEV_SPEC_H +#define INCLUDED_UHD_USRP_SUBDEV_SPEC_H + +#include <uhd/config.h> +#include <uhd/error.h> + +#include <stdbool.h> + +//! Subdevice specification +typedef struct { + // Daughterboard slot name + char* db_name; + //! Subdevice name + char* sd_name; +} uhd_subdev_spec_pair_t; + +#ifdef __cplusplus +#include <uhd/usrp/subdev_spec.hpp> +#include <string> + +struct uhd_subdev_spec_t { + uhd::usrp::subdev_spec_t subdev_spec_cpp; + std::string last_error; +}; + +extern "C" { +#else +struct uhd_subdev_spec_t; +#endif + +//! A C-level interface for working with a list of subdevice specifications +/*! + * See uhd::usrp::subdev_spec_t for more details. + * + * NOTE: Using a handle before passing it into uhd_subdev_spec_make() will result in + * undefined behavior. + */ +typedef struct uhd_subdev_spec_t* uhd_subdev_spec_handle; + +//! Safely destroy any memory created in the generation of a uhd_subdev_spec_pair_t +UHD_API uhd_error uhd_subdev_spec_pair_free( + uhd_subdev_spec_pair_t *subdev_spec_pair +); + +//! Check to see if two subdevice specifications are equal +UHD_API uhd_error uhd_subdev_spec_pairs_equal( + const uhd_subdev_spec_pair_t* first, + const uhd_subdev_spec_pair_t* second, + bool *result_out +); + +//! Create a handle for a list of subdevice specifications +UHD_API uhd_error uhd_subdev_spec_make( + uhd_subdev_spec_handle* h, + const char* markup +); + +//! Safely destroy a subdevice specification handle +/*! + * NOTE: Using a handle after passing it into this function will result in + * a segmentation fault. + */ +UHD_API uhd_error uhd_subdev_spec_free( + uhd_subdev_spec_handle* h +); + +//! Check how many subdevice specifications are in this list +UHD_API uhd_error uhd_subdev_spec_size( + uhd_subdev_spec_handle h, + size_t *size_out +); + +//! Add a subdevice specification to this list +UHD_API uhd_error uhd_subdev_spec_push_back( + uhd_subdev_spec_handle h, + const char* markup +); + +//! Get the subdevice specification at the given index +UHD_API uhd_error uhd_subdev_spec_at( + uhd_subdev_spec_handle h, + size_t num, + uhd_subdev_spec_pair_t *subdev_spec_pair_out +); + +//! Get a string representation of the given list +UHD_API uhd_error uhd_subdev_spec_to_pp_string( + uhd_subdev_spec_handle h, + char* pp_string_out, + size_t strbuffer_len +); + +//! Get a markup string representation of the given list +UHD_API uhd_error uhd_subdev_spec_to_string( + uhd_subdev_spec_handle h, + char* string_out, + size_t strbuffer_len +); + +//! Get the last error recorded by the given handle +UHD_API uhd_error uhd_subdev_spec_last_error( + uhd_subdev_spec_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} + +UHD_API uhd::usrp::subdev_spec_pair_t uhd_subdev_spec_pair_c_to_cpp( + const uhd_subdev_spec_pair_t* subdev_spec_pair_c +); + +UHD_API void uhd_subdev_spec_pair_cpp_to_c( + const uhd::usrp::subdev_spec_pair_t &subdev_spec_pair_cpp, + uhd_subdev_spec_pair_t *subdev_spec_pair_c +); +#endif + +#endif /* INCLUDED_UHD_USRP_SUBDEV_SPEC_H */ diff --git a/host/include/uhd/usrp/usrp.h b/host/include/uhd/usrp/usrp.h new file mode 100644 index 000000000..e828628c7 --- /dev/null +++ b/host/include/uhd/usrp/usrp.h @@ -0,0 +1,1242 @@ +// +// 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/>. +// + +#ifndef INCLUDED_UHD_USRP_H +#define INCLUDED_UHD_USRP_H + +#include <uhd/config.h> +#include <uhd/error.h> +#include <uhd/types/metadata.h> +#include <uhd/types/ranges.h> +#include <uhd/types/sensors.h> +#include <uhd/types/tune_request.h> +#include <uhd/types/tune_result.h> +#include <uhd/types/usrp_info.h> +#include <uhd/usrp/mboard_eeprom.h> +#include <uhd/usrp/dboard_eeprom.h> +#include <uhd/usrp/subdev_spec.h> + +#include <stdbool.h> +#include <stdlib.h> +#include <stdint.h> +#include <time.h> + +/* + * Streamers + */ + +//! A struct of parameters to construct a stream. +/*! + * See uhd::stream_args_t for more details. + */ +typedef struct { + //! Format of host memory + char* cpu_format; + //! Over-the-wire format + char* otw_format; + //! Other stream args + char* args; + //! Array that lists channels + size_t* channel_list; + //! Number of channels + int n_channels; +} uhd_stream_args_t; + +//! How streaming is issued to the device +/*! + * See uhd::stream_cmd_t for more details. + */ +typedef enum { + //! Stream samples indefinitely + UHD_STREAM_MODE_START_CONTINUOUS = 97, + //! End continuous streaming + UHD_STREAM_MODE_STOP_CONTINUOUS = 111, + //! Stream some number of samples and finish + UHD_STREAM_MODE_NUM_SAMPS_AND_DONE = 100, + //! Stream some number of samples but expect more + UHD_STREAM_MODE_NUM_SAMPS_AND_MORE = 109 +} uhd_stream_mode_t; + +//! Define how device streams to host +/*! + * See uhd::stream_cmd_t for more details. + */ +typedef struct { + //! How streaming is issued to the device + uhd_stream_mode_t stream_mode; + //! Number of samples + size_t num_samps; + //! Stream now? + bool stream_now; + //! If not now, then full seconds into future to stream + time_t time_spec_full_secs; + //! If not now, then fractional seconds into future to stream + double time_spec_frac_secs; +} uhd_stream_cmd_t; + +struct uhd_rx_streamer; +struct uhd_tx_streamer; + +//! C-level interface for working with an RX streamer +/*! + * See uhd::rx_streamer for more details. + */ +typedef struct uhd_rx_streamer* uhd_rx_streamer_handle; + +//! C-level interface for working with a TX streamer +/*! + * See uhd::tx_streamer for more details. + */ +typedef struct uhd_tx_streamer* uhd_tx_streamer_handle; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * RX Streamer + */ + +//! Create an RX streamer handle. +/*! + * NOTE: Using this streamer before passing it into uhd_usrp_get_rx_stream() + * will result in undefined behavior. + */ +UHD_API uhd_error uhd_rx_streamer_make( + uhd_rx_streamer_handle *h +); + +//! Free an RX streamer handle. +/*! + * NOTE: Using a streamer after passing it into this function will result + * in a segmentation fault. + */ +UHD_API uhd_error uhd_rx_streamer_free( + uhd_rx_streamer_handle *h +); + +//! Get the number of channels associated with this streamer +UHD_API uhd_error uhd_rx_streamer_num_channels( + uhd_rx_streamer_handle h, + size_t *num_channels_out +); + +//! Get the max number of samples per buffer per packet +UHD_API uhd_error uhd_rx_streamer_max_num_samps( + uhd_rx_streamer_handle h, + size_t *max_num_samps_out +); + +//! Receive buffers containing samples into the given RX streamer +/*! + * See uhd::rx_streamer::recv() for more details. + * + * \param h RX streamer handle + * \param buffs pointer to buffers in which to receive samples + * \param samps_per_buffer max number of samples per buffer + * \param md handle to RX metadata in which to receive results + * \param timeout timeout in seconds to wait for a packet + * \param one_packet send a single packet + * \param items_recvd pointer to output variable for number of samples received + */ +UHD_API uhd_error uhd_rx_streamer_recv( + uhd_rx_streamer_handle h, + void** buffs, + size_t samps_per_buff, + uhd_rx_metadata_handle md, + double timeout, + bool one_packet, + size_t *items_recvd +); + +//! Issue the given stream command +/*! + * See uhd::rx_streamer::issue_stream_cmd() for more details. + */ +UHD_API uhd_error uhd_rx_streamer_issue_stream_cmd( + uhd_rx_streamer_handle h, + const uhd_stream_cmd_t *stream_cmd +); + +//! Get the last error reported by the RX streamer +/*! + * NOTE: This will overwrite the string currently in error_out before + * using it to return its error. + * + * \param h RX streamer handle + * \param error_out string buffer in which to place error + * \param strbuffer_len buffer size + */ +UHD_API uhd_error uhd_rx_streamer_last_error( + uhd_rx_streamer_handle h, + char* error_out, + size_t strbuffer_len +); + +/* + * TX Streamer + */ + +//! Create an TX streamer handle. +/*! + * NOTE: Using this streamer before passing it into uhd_usrp_get_tx_stream() + * will result in undefined behavior. + */ +UHD_API uhd_error uhd_tx_streamer_make( + uhd_tx_streamer_handle *h +); + +//! Free an TX streamer handle. +/*! + * NOTE: Using a streamer after passing it into this function will result + * in a segmentation fault. + */ +UHD_API uhd_error uhd_tx_streamer_free( + uhd_tx_streamer_handle *h +); + +//! Get the number of channels associated with this streamer +UHD_API uhd_error uhd_tx_streamer_num_channels( + uhd_tx_streamer_handle h, + size_t *num_channels_out +); + +//! Get the max number of samples per buffer per packet +UHD_API uhd_error uhd_tx_streamer_max_num_samps( + uhd_tx_streamer_handle h, + size_t *max_num_samps_out +); + +//! Send buffers containing samples described by the metadata +/*! + * See uhd::tx_streamer::send() for more details. + * + * \param h TX streamer handle + * \param buffs pointer to buffers containing samples to send + * \param samps_per_buffer max number of samples per buffer + * \param md handle to TX metadata + * \param timeout timeout in seconds to wait for a packet + * \param items_sent pointer to output variable for number of samples send + */ +UHD_API uhd_error uhd_tx_streamer_send( + uhd_tx_streamer_handle h, + const void **buffs, + size_t samps_per_buff, + uhd_tx_metadata_handle md, + double timeout, + size_t *items_sent +); + +//! Receive an asynchronous message from this streamer +/*! + * See uhd::tx_streamer::recv_async_msg() for more details. + */ +UHD_API uhd_error uhd_tx_streamer_recv_async_msg( + uhd_tx_streamer_handle h, + uhd_async_metadata_handle md, + double timeout, + bool *valid +); + +//! Get the last error reported by the TX streamer +/*! + * NOTE: This will overwrite the string currently in error_out before + * using it to return its error. + * + * \param h TX streamer handle + * \param error_out string buffer in which to place error + * \param strbuffer_len buffer size + */ +UHD_API uhd_error uhd_tx_streamer_last_error( + uhd_tx_streamer_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} +#endif + +/**************************************************************************** + * Public Datatypes for USRP / streamer handling. + ***************************************************************************/ +struct uhd_usrp; + +//! C-level interface for working with a USRP device +/* + * See uhd::usrp::multi_usrp for more details. + * + * NOTE: You must pass this handle into uhd_usrp_make before using it. + */ +typedef struct uhd_usrp* uhd_usrp_handle; + +/**************************************************************************** + * USRP Make / Free API calls + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +//! Create a USRP handle. +/*! + * \param h the handle + * \param args device args (e.g. "type=x300") + */ +UHD_API uhd_error uhd_usrp_make( + uhd_usrp_handle *h, + const char *args +); + +//! Safely destroy the USRP object underlying the handle. +/*! + * NOTE: Attempting to use a USRP handle after passing it into this function + * will result in a segmentation fault. + */ +UHD_API uhd_error uhd_usrp_free( + uhd_usrp_handle *h +); + +//! Get the last error reported by the USRP handle +UHD_API uhd_error uhd_usrp_last_error( + uhd_usrp_handle h, + char* error_out, + size_t strbuffer_len +); + +//! Create RX streamer from a USRP handle and given stream args +UHD_API uhd_error uhd_usrp_get_rx_stream( + uhd_usrp_handle h, + uhd_stream_args_t *stream_args, + uhd_rx_streamer_handle h_out +); + +//! Create TX streamer from a USRP handle and given stream args +UHD_API uhd_error uhd_usrp_get_tx_stream( + uhd_usrp_handle h, + uhd_stream_args_t *stream_args, + uhd_tx_streamer_handle h_out +); + +/**************************************************************************** + * multi_usrp API calls + ***************************************************************************/ + +//! Get RX info from the USRP device +/*! + * NOTE: After calling this function, uhd_usrp_rx_info_free() must be called on info_out. + */ +UHD_API uhd_error uhd_usrp_get_rx_info( + uhd_usrp_handle h, + size_t chan, + uhd_usrp_rx_info_t *info_out +); + +//! Get TX info from the USRP device +/*! + * NOTE: After calling this function, uhd_usrp_tx_info_free() must be called on info_out. + */ +UHD_API uhd_error uhd_usrp_get_tx_info( + uhd_usrp_handle h, + size_t chan, + uhd_usrp_tx_info_t *info_out +); + +/**************************************************************************** + * Motherboard methods + ***************************************************************************/ + +//! Set the master clock rate. +/*! + * See uhd::usrp::multi_usrp::set_master_clock_rate() for more details. + */ +UHD_API uhd_error uhd_usrp_set_master_clock_rate( + uhd_usrp_handle h, + double rate, + size_t mboard +); + +//! Get the master clock rate. +/*! + * See uhd::usrp::multi_usrp::get_master_clock_rate() for more details. + */ +UHD_API uhd_error uhd_usrp_get_master_clock_rate( + uhd_usrp_handle h, + size_t mboard, + double *clock_rate_out +); + +//! Get a pretty-print representation of the USRP device. +/*! + * See uhd::usrp::multi_usrp::get_pp_string() for more details. + */ +UHD_API uhd_error uhd_usrp_get_pp_string( + uhd_usrp_handle h, + char* pp_string_out, + size_t strbuffer_len +); + +//! Get the motherboard name for the given device +/*! + * See uhd::usrp::multi_usrp::get_mboard_name() for more details. + */ +UHD_API uhd_error uhd_usrp_get_mboard_name( + uhd_usrp_handle h, + size_t mboard, + char* mboard_name_out, + size_t strbuffer_len +); + +//! Get the USRP device's current internal time +/*! + * See uhd::usrp::multi_usrp::get_time_now() for more details. + */ +UHD_API uhd_error uhd_usrp_get_time_now( + uhd_usrp_handle h, + size_t mboard, + time_t *full_secs_out, + double *frac_secs_out +); + +//! Get the time when this device's last PPS pulse occurred +/*! + * See uhd::usrp::multi_usrp::get_time_last_pps() for more details. + */ +UHD_API uhd_error uhd_usrp_get_time_last_pps( + uhd_usrp_handle h, + size_t mboard, + time_t *full_secs_out, + double *frac_secs_out +); + +//! Set the USRP device's time +/*! + * See uhd::usrp::multi_usrp::set_time_now() for more details. + */ +UHD_API uhd_error uhd_usrp_set_time_now( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs, + size_t mboard +); + +//! Set the USRP device's time to the given value upon the next PPS detection +/*! + * See uhd::usrp::multi_usrp::set_time_next_pps() for more details. + */ +UHD_API uhd_error uhd_usrp_set_time_next_pps( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs, + size_t mboard +); + +//! Synchronize the time across all motherboards +/*! + * See uhd::usrp::multi_usrp::set_time_unknown_pps() for more details. + */ +UHD_API uhd_error uhd_usrp_set_time_unknown_pps( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs +); + +//! Are all motherboard times synchronized? +UHD_API uhd_error uhd_usrp_get_time_synchronized( + uhd_usrp_handle h, + bool *result_out +); + +//! Set the time at which timed commands will take place +/*! + * See uhd::usrp::multi_usrp::set_command_time() for more details. + */ +UHD_API uhd_error uhd_usrp_set_command_time( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs, + size_t mboard +); + +//! Clear the command time so that commands are sent ASAP +UHD_API uhd_error uhd_usrp_clear_command_time( + uhd_usrp_handle h, + size_t mboard +); + +//! Issue a stream command to tell the device to send samples to the host +/*! + * See uhd::usrp::multi_usrp::issue_stream_command() for more details. + */ +UHD_API uhd_error uhd_usrp_issue_stream_cmd( + uhd_usrp_handle h, + uhd_stream_cmd_t *stream_cmd, + size_t chan +); + +//! Set the time source for the given device +/*! + * See uhd::usrp::multi_usrp::set_time_source() for more details. + */ +UHD_API uhd_error uhd_usrp_set_time_source( + uhd_usrp_handle h, + const char* time_source, + size_t mboard +); + +//! Get the time source for the given device +/*! + * See uhd::usrp::multi_usrp::get_time_source() for more details. + */ +UHD_API uhd_error uhd_usrp_get_time_source( + uhd_usrp_handle h, + size_t mboard, + char* time_source_out, + size_t strbuffer_len +); + +//! Get a list of time sources for the given device +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of time sources. + * + * \param h USRP handle + * \param mboard which motherboard to use + * \param time_sources_out string buffer in which to place time sources + * \param strbuffer_len buffer length + * \param num_time_sources_out variable in which to place number of time sources + */ +UHD_API uhd_error uhd_usrp_get_time_sources( + uhd_usrp_handle h, + size_t mboard, + char* time_sources_out, + size_t strbuffer_len, + size_t *num_time_sources_out +); + +//! Set the given device's clock source +/*! + * See uhd::usrp::multi_usrp::set_clock_source() for more details. + */ +UHD_API uhd_error uhd_usrp_set_clock_source( + uhd_usrp_handle h, + const char* clock_source, + size_t mboard +); + +//! Get the given device's clock source +/*! + * See uhd::usrp::multi_usrp::get_clock_source() for more details. + */ +UHD_API uhd_error uhd_usrp_get_clock_source( + uhd_usrp_handle h, + size_t mboard, + char* clock_source_out, + size_t strbuffer_len +); + +//! Get a list of clock sources for the given device +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of clock sources. + * + * \param h USRP handle + * \param mboard which motherboard to use + * \param clock_sources_out string buffer in which to place clock sources + * \param strbuffer_len buffer length + * \param num_clock_sources_out variable in which to place number of clock sources + */ +UHD_API uhd_error uhd_usrp_get_clock_sources( + uhd_usrp_handle h, + size_t mboard, + char* clock_sources_out, + size_t strbuffer_len, + size_t *num_clock_sources_out +); + +//! Enable or disable sending the clock source to an output connector +/*! + * See uhd::usrp::set_clock_source_out() for more details. + */ +UHD_API uhd_error uhd_usrp_set_clock_source_out( + uhd_usrp_handle h, + bool enb, + size_t mboard +); + +//! Enable or disable sending the time source to an output connector +/*! + * See uhd::usrp::set_time_source_out() for more details. + */ +UHD_API uhd_error uhd_usrp_set_time_source_out( + uhd_usrp_handle h, + bool enb, + size_t mboard +); + +//! Get the number of devices associated with the given USRP handle +UHD_API uhd_error uhd_usrp_get_num_mboards( + uhd_usrp_handle h, + size_t *num_mboards_out +); + +//! Get the value associated with the given sensor name +UHD_API uhd_error uhd_usrp_get_mboard_sensor( + uhd_usrp_handle h, + const char* name, + size_t mboard, + uhd_sensor_value_handle sensor_value_out +); + +//! Get a list of motherboard sensors for the given device +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of motherboard sensors. + * + * \param h USRP handle + * \param mboard which motherboard to use + * \param mboard_sensors_out string buffer in which to place motherboard sensors + * \param strbuffer_len buffer length + * \param num_mboard_sensors_out variable in which to place number of motherboard sensors + */ +UHD_API uhd_error uhd_usrp_get_mboard_sensor_names( + uhd_usrp_handle h, + size_t mboard, + char* mboard_sensor_names_out, + size_t strbuffer_len, + size_t *num_mboard_sensors_out +); + +//! Perform a write on a user configuration register bus +/*! + * See uhd::usrp::multi_usrp::set_user_register() for more details. + */ +UHD_API uhd_error uhd_usrp_set_user_register( + uhd_usrp_handle h, + uint8_t addr, + uint32_t data, + size_t mboard +); + +/**************************************************************************** + * EEPROM access methods + ***************************************************************************/ + +//! Get a handle for the given motherboard's EEPROM +UHD_API uhd_error uhd_usrp_get_mboard_eeprom( + uhd_usrp_handle h, + uhd_mboard_eeprom_handle mb_eeprom, + size_t mboard +); + +//! Set values in the given motherboard's EEPROM +UHD_API uhd_error uhd_usrp_set_mboard_eeprom( + uhd_usrp_handle h, + uhd_mboard_eeprom_handle mb_eeprom, + size_t mboard +); + +//! Get a handle for the given device's daughterboard EEPROM +UHD_API uhd_error uhd_usrp_get_dboard_eeprom( + uhd_usrp_handle h, + uhd_dboard_eeprom_handle db_eeprom, + const char* unit, + const char* slot, + size_t mboard +); + +//! Set values in the given daughterboard's EEPROM +UHD_API uhd_error uhd_usrp_set_dboard_eeprom( + uhd_usrp_handle h, + uhd_dboard_eeprom_handle db_eeprom, + const char* unit, + const char* slot, + size_t mboard +); + +/**************************************************************************** + * RX methods + ***************************************************************************/ + +//! Map the given device's RX frontend to a channel +/*! + * See uhd::usrp::multi_usrp::set_rx_subdev_spec() for more details. + */ +UHD_API uhd_error uhd_usrp_set_rx_subdev_spec( + uhd_usrp_handle h, + uhd_subdev_spec_handle subdev_spec, + size_t mboard +); + +//! Get the RX frontend specfication for the given device +UHD_API uhd_error uhd_usrp_get_rx_subdev_spec( + uhd_usrp_handle h, + size_t mboard, + uhd_subdev_spec_handle subdev_spec_out +); + +//! Get the number of RX channels for the given handle +UHD_API uhd_error uhd_usrp_get_rx_num_channels( + uhd_usrp_handle h, + size_t *num_channels_out +); + +//! Get the name for the RX frontend +UHD_API uhd_error uhd_usrp_get_rx_subdev_name( + uhd_usrp_handle h, + size_t chan, + char* rx_subdev_name_out, + size_t strbuffer_len +); + +//! Set the given RX channel's sample rate (in Sps) +UHD_API uhd_error uhd_usrp_set_rx_rate( + uhd_usrp_handle h, + double rate, + size_t chan +); + +//! Get the given RX channel's sample rate (in Sps) +UHD_API uhd_error uhd_usrp_get_rx_rate( + uhd_usrp_handle h, + size_t chan, + double *rate_out +); + +//! Get a range of possible RX rates for the given channel +UHD_API uhd_error uhd_usrp_get_rx_rates( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle rates_out +); + +//! Set the given channel's center RX frequency +UHD_API uhd_error uhd_usrp_set_rx_freq( + uhd_usrp_handle h, + uhd_tune_request_t *tune_request, + size_t chan, + uhd_tune_result_t *tune_result +); + +//! Get the given channel's center RX frequency +UHD_API uhd_error uhd_usrp_get_rx_freq( + uhd_usrp_handle h, + size_t chan, + double *freq_out +); + +//! Get all possible center frequency ranges for the given channel +/*! + * See uhd::usrp::multi_usrp::get_rx_freq_range() for more details. + */ +UHD_API uhd_error uhd_usrp_get_rx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +); + +//! Get all possible RF frequency ranges for the given channel's RX RF frontend +UHD_API uhd_error uhd_usrp_get_fe_rx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +); + +//! Set the RX gain for the given channel and name +UHD_API uhd_error uhd_usrp_set_rx_gain( + uhd_usrp_handle h, + double gain, + size_t chan, + const char *gain_name +); + +//! Set the normalized RX gain [0.0, 1.0] for the given channel +/*! + * See uhd::usrp::multi_usrp::set_normalized_rx_gain() for more details. + */ +UHD_API uhd_error uhd_usrp_set_normalized_rx_gain( + uhd_usrp_handle h, + double gain, + size_t chan +); + +//! Enable or disable the given channel's RX AGC module +/*! + * See uhd::usrp::multi_usrp::set_rx_agc() for more details. + */ +UHD_API uhd_error uhd_usrp_set_rx_agc( + uhd_usrp_handle h, + bool enable, + size_t chan +); + +//! Get the given channel's RX gain +UHD_API uhd_error uhd_usrp_get_rx_gain( + uhd_usrp_handle h, + size_t chan, + const char *gain_name, + double *gain_out +); + +//! Get the given channel's normalized RX gain [0.0, 1.0] +/*! + * See uhd::usrp::multi_usrp::get_normalized_rx_gain() for more details. + */ +UHD_API uhd_error uhd_usrp_get_normalized_rx_gain( + uhd_usrp_handle h, + size_t chan, + double *gain_out +); + +//! Get all possible gain ranges for the given channel and name +UHD_API uhd_error uhd_usrp_get_rx_gain_range( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_meta_range_handle gain_range_out +); + +//! Get a list of RX gain names for the given channel +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of RX gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param rx_gain_names_out string buffer in which to place RX gain names + * \param strbuffer_len buffer length + * \param num_rx_gain_names_out variable in which to place number of RX gain names + */ +UHD_API uhd_error uhd_usrp_get_rx_gain_names( + uhd_usrp_handle h, + size_t chan, + char* gain_names_out, + size_t strbuffer_len, + size_t *num_rx_gain_names_out +); + +//! Set the RX antenna for the given channel +UHD_API uhd_error uhd_usrp_set_rx_antenna( + uhd_usrp_handle h, + const char* ant, + size_t chan +); + +//! Get the RX antenna for the given channel +UHD_API uhd_error uhd_usrp_get_rx_antenna( + uhd_usrp_handle h, + size_t chan, + char* ant_out, + size_t strbuffer_len +); + +//! Get a list of RX antennas associated with the given channels +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of RX gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param rx_antennas_out string buffer in which to place RX antennas + * \param strbuffer_len buffer length + * \param num_rx_antennas_out variable in which to place number of RX gain names + */ +UHD_API uhd_error uhd_usrp_get_rx_antennas( + uhd_usrp_handle h, + size_t chan, + char* antennas_out, + size_t strbuffer_len, + size_t *num_rx_antennas_out +); + +//! Get a list of RX sensors associated with the given channels +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of RX gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param sensor_names_out string buffer in which to place RX sensor names + * \param strbuffer_len buffer length + * \param num_rx_sensors_out variable in which to place number of RX sensor names + */ +UHD_API uhd_error uhd_usrp_get_rx_sensor_names( + uhd_usrp_handle h, + size_t chan, + char* sensor_names_out, + size_t strbuffer_len, + size_t *num_rx_sensors_out +); + +//! Set the bandwidth for the given channel's RX frontend +UHD_API uhd_error uhd_usrp_set_rx_bandwidth( + uhd_usrp_handle h, + double bandwidth, + size_t chan +); + +//! Get the bandwidth for the given channel's RX frontend +UHD_API uhd_error uhd_usrp_get_rx_bandwidth( + uhd_usrp_handle h, + size_t chan, + double *bandwidth_out +); + +//! Get all possible bandwidth ranges for the given channel's RX frontend +UHD_API uhd_error uhd_usrp_get_rx_bandwidth_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle bandwidth_range_out +); + +//! Get the value for the given RX sensor +UHD_API uhd_error uhd_usrp_get_rx_sensor( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_sensor_value_handle sensor_value_out +); + +//! Enable or disable RX DC offset correction for the given channel +/*! + * See uhd::usrp::multi_usrp::set_rx_dc_offset() for more details. + */ +UHD_API uhd_error uhd_usrp_set_rx_dc_offset_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +); + +//! Enable or disable RX IQ imbalance correction for the given channel +UHD_API uhd_error uhd_usrp_set_rx_iq_balance_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +); + +/**************************************************************************** + * TX methods + ***************************************************************************/ + +//! Map the given device's TX frontend to a channel +/*! + * See uhd::usrp::multi_usrp::set_tx_subdev_spec() for more details. + */ +UHD_API uhd_error uhd_usrp_set_tx_subdev_spec( + uhd_usrp_handle h, + uhd_subdev_spec_handle subdev_spec, + size_t mboard +); + +//! Get the TX frontend specfication for the given device +UHD_API uhd_error uhd_usrp_get_tx_subdev_spec( + uhd_usrp_handle h, + size_t mboard, + uhd_subdev_spec_handle subdev_spec_out +); + +//! Get the number of TX channels for the given handle +UHD_API uhd_error uhd_usrp_get_tx_num_channels( + uhd_usrp_handle h, + size_t *num_channels_out +); + +//! Get the name for the RX frontend +UHD_API uhd_error uhd_usrp_get_tx_subdev_name( + uhd_usrp_handle h, + size_t chan, + char* tx_subdev_name_out, + size_t strbuffer_len +); + +//! Set the given RX channel's sample rate (in Sps) +UHD_API uhd_error uhd_usrp_set_tx_rate( + uhd_usrp_handle h, + double rate, + size_t chan +); + +//! Get the given RX channel's sample rate (in Sps) +UHD_API uhd_error uhd_usrp_get_tx_rate( + uhd_usrp_handle h, + size_t chan, + double *rate_out +); + +//! Get a range of possible RX rates for the given channel +UHD_API uhd_error uhd_usrp_get_tx_rates( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle rates_out +); + +//! Set the given channel's center TX frequency +UHD_API uhd_error uhd_usrp_set_tx_freq( + uhd_usrp_handle h, + uhd_tune_request_t *tune_request, + size_t chan, + uhd_tune_result_t *tune_result +); + +//! Get the given channel's center TX frequency +UHD_API uhd_error uhd_usrp_get_tx_freq( + uhd_usrp_handle h, + size_t chan, + double *freq_out +); + +//! Get all possible center frequency ranges for the given channel +/*! + * See uhd::usrp::multi_usrp::get_rx_freq_range() for more details. + */ +UHD_API uhd_error uhd_usrp_get_tx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +); + +//! Get all possible RF frequency ranges for the given channel's TX RF frontend +UHD_API uhd_error uhd_usrp_get_fe_tx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +); + +//! Set the TX gain for the given channel and name +UHD_API uhd_error uhd_usrp_set_tx_gain( + uhd_usrp_handle h, + double gain, + size_t chan, + const char *gain_name +); + +//! Set the normalized TX gain [0.0, 1.0] for the given channel +/*! + * See uhd::usrp::multi_usrp::set_normalized_tx_gain() for more details. + */ +UHD_API uhd_error uhd_usrp_set_normalized_tx_gain( + uhd_usrp_handle h, + double gain, + size_t chan +); + +//! Get all possible gain ranges for the given channel and name +UHD_API uhd_error uhd_usrp_get_tx_gain_range( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_meta_range_handle gain_range_out +); + +//! Get the given channel's RX gain +UHD_API uhd_error uhd_usrp_get_tx_gain( + uhd_usrp_handle h, + size_t chan, + const char *gain_name, + double *gain_out +); + +//! Get the given channel's normalized TX gain [0.0, 1.0] +/*! + * See uhd::usrp::multi_usrp::get_normalized_tx_gain() for more details. + */ +UHD_API uhd_error uhd_usrp_get_normalized_tx_gain( + uhd_usrp_handle h, + size_t chan, + double *gain_out +); + +//! Get a list of TX gain names for the given channel +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of TX gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param tx_gain_names_out string buffer in which to place TX gain names + * \param strbuffer_len buffer length + * \param num_tx_gain_names_out variable in which to place number of TX gain names + */ +UHD_API uhd_error uhd_usrp_get_tx_gain_names( + uhd_usrp_handle h, + size_t chan, + char* gain_names_out, + size_t strbuffer_len, + size_t *num_tx_gain_names_out +); + +//! Set the TX antenna for the given channel +UHD_API uhd_error uhd_usrp_set_tx_antenna( + uhd_usrp_handle h, + const char* ant, + size_t chan +); + +//! Get the TX antenna for the given channel +UHD_API uhd_error uhd_usrp_get_tx_antenna( + uhd_usrp_handle h, + size_t chan, + char* ant_out, + size_t strbuffer_len +); + +//! Get a list of tx antennas associated with the given channels +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of tx gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param tx_antennas_out string buffer in which to place TX antennas + * \param strbuffer_len buffer length + * \param num_tx_antennas_out variable in which to place number of TX gain names + */ +UHD_API uhd_error uhd_usrp_get_tx_antennas( + uhd_usrp_handle h, + size_t chan, + char* antennas_out, + size_t strbuffer_len, + size_t *num_tx_antennas_out +); + +//! Set the bandwidth for the given channel's TX frontend +UHD_API uhd_error uhd_usrp_set_tx_bandwidth( + uhd_usrp_handle h, + double bandwidth, + size_t chan +); + +//! Get the bandwidth for the given channel's TX frontend +UHD_API uhd_error uhd_usrp_get_tx_bandwidth( + uhd_usrp_handle h, + size_t chan, + double *bandwidth_out +); + +//! Get all possible bandwidth ranges for the given channel's TX frontend +UHD_API uhd_error uhd_usrp_get_tx_bandwidth_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle bandwidth_range_out +); + +//! Get the value for the given TX sensor +UHD_API uhd_error uhd_usrp_get_tx_sensor( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_sensor_value_handle sensor_value_out +); + +//! Get a list of TX sensors associated with the given channels +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of TX gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param sensor_names_out string buffer in which to place TX sensor names + * \param strbuffer_len buffer length + * \param num_tx_sensors_out variable in which to place number of TX sensor names + */ +UHD_API uhd_error uhd_usrp_get_tx_sensor_names( + uhd_usrp_handle h, + size_t chan, + char* sensor_names_out, + size_t strbuffer_len, + size_t *num_tx_sensors_out +); + +//! Enable or disable TX DC offset correction for the given channel +/*! + * See uhd::usrp::multi_usrp::set_tx_dc_offset() for more details. + */ +UHD_API uhd_error uhd_usrp_set_tx_dc_offset_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +); + +//! Enable or disable TX IQ imbalance correction for the given channel +UHD_API uhd_error uhd_usrp_set_tx_iq_balance_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +); + +/**************************************************************************** + * GPIO methods + ***************************************************************************/ + +//! Get a list of GPIO banks associated with the given channels +/*! + * The list will be returned as a comma-delimited list that can + * be parsed with strtok(). The function will also return the number + * of TX gain names. + * + * \param h USRP handle + * \param channel which channel to use + * \param gpio_banks_out string buffer in which to place GPIO banks + * \param strbuffer_len buffer length + * \param num_gpio_banks_out variable in which to place number of GPIO banks + */ +UHD_API uhd_error uhd_usrp_get_gpio_banks( + uhd_usrp_handle h, + size_t mboard, + char* gpio_banks_out, + size_t strbuffer_len, + size_t *num_gpio_banks_out +); + +//! Set a GPIO attribute for a given GPIO bank +/*! + * See uhd::usrp::multi_usrp::set_gpio_attr() for more details. + */ +UHD_API uhd_error uhd_usrp_set_gpio_attr( + uhd_usrp_handle h, + const char* bank, + const char* attr, + uint32_t value, + uint32_t mask, + size_t mboard +); + +//! Get a GPIO attribute on a particular GPIO bank +/*! + * See uhd::usrp::multi_usrp::get_gpio_attr() for more details. + */ +UHD_API uhd_error uhd_usrp_get_gpio_attr( + uhd_usrp_handle h, + const char* bank, + const char* attr, + size_t mboard, + uint32_t *attr_out +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_USRP_H */ diff --git a/host/include/uhd/usrp_clock/CMakeLists.txt b/host/include/uhd/usrp_clock/CMakeLists.txt index a116e4982..518cb7737 100644 --- a/host/include/uhd/usrp_clock/CMakeLists.txt +++ b/host/include/uhd/usrp_clock/CMakeLists.txt @@ -21,3 +21,9 @@ UHD_INSTALL(FILES DESTINATION ${INCLUDE_DIR}/uhd/usrp_clock COMPONENT headers ) + +IF(ENABLE_C_API) + UHD_INSTALL(FILES + usrp_clock.h + ) +ENDIF(ENABLE_C_API) diff --git a/host/include/uhd/usrp_clock/usrp_clock.h b/host/include/uhd/usrp_clock/usrp_clock.h new file mode 100644 index 000000000..2f5a1db29 --- /dev/null +++ b/host/include/uhd/usrp_clock/usrp_clock.h @@ -0,0 +1,117 @@ +// +// 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/>. +// + +#ifndef INCLUDED_UHD_USRP_CLOCK_H +#define INCLUDED_UHD_USRP_CLOCK_H + +#include <uhd/config.h> +#include <uhd/error.h> +#include <uhd/types/sensors.h> + +#include <stdlib.h> +#include <stdint.h> +#include <time.h> + +/**************************************************************************** + * Public Datatypes for USRP clock + ***************************************************************************/ +struct uhd_usrp_clock; + +//! A C-level interface for interacting with an Ettus Research clock device +/*! + * See uhd::usrp_clock::multi_usrp_clock for more details. + * + * NOTE: Attempting to use a handle before passing it into uhd_usrp_clock_make() + * will result in undefined behavior. + */ +typedef struct uhd_usrp_clock* uhd_usrp_clock_handle; + +/**************************************************************************** + * Make / Free API calls + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +/*! Create a USRP Clock handle. + * + * \param h The handle + * \param args Device args (e.g. "addr=192.168.10.3") + */ +UHD_API uhd_error uhd_usrp_clock_make( + uhd_usrp_clock_handle *h, + const char *args +); + +/*! Safely destroy the USRP_CLOCK object underlying the handle. + * + * Note: After calling this, usage of h may cause segmentation faults. + * However, multiple calling of uhd_usrp_free() is safe. + */ +UHD_API uhd_error uhd_usrp_clock_free( + uhd_usrp_clock_handle *h +); + +//! Get last error +UHD_API uhd_error uhd_usrp_clock_last_error( + uhd_usrp_clock_handle h, + char* error_out, + size_t strbuffer_len +); + +//! Get board information in a nice output +UHD_API uhd_error uhd_usrp_clock_get_pp_string( + uhd_usrp_clock_handle h, + char* pp_string_out, + size_t strbuffer_len +); + +//! Get number of boards +UHD_API uhd_error uhd_usrp_clock_get_num_boards( + uhd_usrp_clock_handle h, + size_t *num_boards_out +); + +//! Get time +UHD_API uhd_error uhd_usrp_clock_get_time( + uhd_usrp_clock_handle h, + size_t board, + uint32_t *clock_time_out +); + +//! Get sensor +UHD_API uhd_error uhd_usrp_clock_get_sensor( + uhd_usrp_clock_handle h, + const char* name, + size_t board, + uhd_sensor_value_handle sensor_value_out +); + +//! Get sensor names +UHD_API uhd_error uhd_usrp_clock_get_sensor_names( + uhd_usrp_clock_handle h, + size_t board, + char *sensor_names_out, + size_t strbuffer_len, + size_t *num_sensors_out +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_USRP_CLOCK_H */ diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt index 6b3d5a581..af6d3ee47 100644 --- a/host/include/uhd/utils/CMakeLists.txt +++ b/host/include/uhd/utils/CMakeLists.txt @@ -42,3 +42,11 @@ UHD_INSTALL(FILES DESTINATION ${INCLUDE_DIR}/uhd/utils COMPONENT headers ) + +IF(ENABLE_C_API) + UHD_INSTALL(FILES + thread_priority.h + DESTINATION ${INCLUDE_DIR}/uhd/utils + COMPONENT headers + ) +ENDIF(ENABLE_C_API) diff --git a/host/include/uhd/utils/thread_priority.h b/host/include/uhd/utils/thread_priority.h new file mode 100644 index 000000000..217d7a1cc --- /dev/null +++ b/host/include/uhd/utils/thread_priority.h @@ -0,0 +1,53 @@ +// +// 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/>. +// + +#ifndef INCLUDED_UHD_UTILS_THREAD_PRIORITY_H +#define INCLUDED_UHD_UTILS_THREAD_PRIORITY_H + +#include <uhd/config.h> +#include <uhd/error.h> + +#ifdef __cplusplus +extern "C" { +#endif + +static const float uhd_default_thread_priority = 0.5; + +/*! + * Set the scheduling priority on the current thread. + * + * A new thread or calling process should make this call + * with the defailts this to enable realtime scheduling. + * + * A priority of zero corresponds to normal priority. + * Positive priority values are higher than normal. + * Negative priority values are lower than normal. + * + * \param priority a value between -1 and 1 + * \param realtime true to use realtime mode + * \return UHD error code + */ +UHD_API uhd_error uhd_set_thread_priority( + float priority, + bool realtime +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_UTILS_THREAD_PRIORITY_H */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 3d4ba8a68..f74af1f29 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -96,6 +96,12 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_BINARY_DIR}/version.cpp ) +IF(ENABLE_C_API) + LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/error_c.cpp + ) +ENDIF(ENABLE_C_API) + ######################################################################## # Add DLL resource file to Windows build ######################################################################## diff --git a/host/lib/error_c.cpp b/host/lib/error_c.cpp new file mode 100644 index 000000000..c3a83eec9 --- /dev/null +++ b/host/lib/error_c.cpp @@ -0,0 +1,40 @@ +// +// 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/error.h> +#include <uhd/exception.hpp> + +#define MAP_TO_ERROR(exception_type, error_type) \ + if (dynamic_cast<const uhd::exception_type*>(e)) return error_type; + +uhd_error error_from_uhd_exception(const uhd::exception* e){ + MAP_TO_ERROR(index_error, UHD_ERROR_INDEX) + MAP_TO_ERROR(key_error, UHD_ERROR_KEY) + MAP_TO_ERROR(not_implemented_error, UHD_ERROR_NOT_IMPLEMENTED) + MAP_TO_ERROR(usb_error, UHD_ERROR_USB) + MAP_TO_ERROR(io_error, UHD_ERROR_IO) + MAP_TO_ERROR(os_error, UHD_ERROR_OS) + MAP_TO_ERROR(assertion_error, UHD_ERROR_ASSERTION) + MAP_TO_ERROR(lookup_error, UHD_ERROR_LOOKUP) + MAP_TO_ERROR(type_error, UHD_ERROR_TYPE) + MAP_TO_ERROR(value_error, UHD_ERROR_VALUE) + MAP_TO_ERROR(runtime_error, UHD_ERROR_RUNTIME) + MAP_TO_ERROR(environment_error, UHD_ERROR_ENVIRONMENT) + MAP_TO_ERROR(system_error, UHD_ERROR_SYSTEM) + + return UHD_ERROR_EXCEPT; +} diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt index 5e97628f0..d8938c8a8 100644 --- a/host/lib/types/CMakeLists.txt +++ b/host/lib/types/CMakeLists.txt @@ -94,3 +94,13 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/filters.cpp ${CMAKE_CURRENT_SOURCE_DIR}/byte_vector.cpp ) + +IF(ENABLE_C_API) + LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/metadata_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ranges_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sensors_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tune_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/usrp_info_c.cpp + ) +ENDIF() diff --git a/host/lib/types/metadata_c.cpp b/host/lib/types/metadata_c.cpp new file mode 100644 index 000000000..96f43d140 --- /dev/null +++ b/host/lib/types/metadata_c.cpp @@ -0,0 +1,315 @@ +// +// 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/types/metadata.h> + +#include <uhd/types/time_spec.hpp> + +#include <string.h> + +/* + * RX metadata + */ + +uhd_error uhd_rx_metadata_make( + uhd_rx_metadata_handle* handle +){ + UHD_SAFE_C( + *handle = new uhd_rx_metadata_t; + ) +} + +uhd_error uhd_rx_metadata_free( + uhd_rx_metadata_handle* handle +){ + UHD_SAFE_C( + delete *handle; + *handle = NULL; + ) +} + +uhd_error uhd_rx_metadata_has_time_spec( + uhd_rx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->rx_metadata_cpp.has_time_spec; + ) +} + +uhd_error uhd_rx_metadata_time_spec( + uhd_rx_metadata_handle h, + time_t *full_secs_out, + double *frac_secs_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp = h->rx_metadata_cpp.time_spec; + *full_secs_out = time_spec_cpp.get_full_secs(); + *frac_secs_out = time_spec_cpp.get_frac_secs(); + ) +} + +uhd_error uhd_rx_metadata_more_fragments( + uhd_rx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->rx_metadata_cpp.more_fragments; + ) +} + +uhd_error uhd_rx_metadata_fragment_offset( + uhd_rx_metadata_handle h, + size_t *fragment_offset_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *fragment_offset_out = h->rx_metadata_cpp.fragment_offset; + ) +} + +uhd_error uhd_rx_metadata_start_of_burst( + uhd_rx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->rx_metadata_cpp.start_of_burst; + ) +} + +uhd_error uhd_rx_metadata_end_of_burst( + uhd_rx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->rx_metadata_cpp.end_of_burst; + ) +} + +uhd_error uhd_rx_metadata_out_of_sequence( + uhd_rx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->rx_metadata_cpp.out_of_sequence; + ) +} + +uhd_error uhd_rx_metadata_to_pp_string( + uhd_rx_metadata_handle h, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string pp_string_cpp = h->rx_metadata_cpp.to_pp_string(); + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, pp_string_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_rx_metadata_error_code( + uhd_rx_metadata_handle h, + uhd_rx_metadata_error_code_t *error_code_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *error_code_out = uhd_rx_metadata_error_code_t(h->rx_metadata_cpp.error_code); + ) +} + +uhd_error uhd_rx_metadata_strerror( + uhd_rx_metadata_handle h, + char* strerror_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string strerror_cpp = h->rx_metadata_cpp.strerror(); + memset(strerror_out, '\0', strbuffer_len); + strncpy(strerror_out, strerror_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_rx_metadata_last_error( + uhd_rx_metadata_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +/* + * TX metadata + */ + +uhd_error uhd_tx_metadata_make( + uhd_tx_metadata_handle* handle, + bool has_time_spec, + time_t full_secs, + double frac_secs, + bool start_of_burst, + bool end_of_burst +){ + UHD_SAFE_C( + *handle = new uhd_tx_metadata_t; + (*handle)->tx_metadata_cpp.has_time_spec = has_time_spec; + if(has_time_spec){ + (*handle)->tx_metadata_cpp.time_spec = uhd::time_spec_t(full_secs, frac_secs); + } + (*handle)->tx_metadata_cpp.start_of_burst = start_of_burst; + (*handle)->tx_metadata_cpp.end_of_burst = end_of_burst; + ) +} + +uhd_error uhd_tx_metadata_free( + uhd_tx_metadata_handle* handle +){ + UHD_SAFE_C( + delete *handle; + *handle = NULL; + ) +} + +uhd_error uhd_tx_metadata_has_time_spec( + uhd_tx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->tx_metadata_cpp.has_time_spec; + ) +} + +uhd_error uhd_tx_metadata_time_spec( + uhd_tx_metadata_handle h, + time_t *full_secs_out, + double *frac_secs_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp = h->tx_metadata_cpp.time_spec; + *full_secs_out = time_spec_cpp.get_full_secs(); + *frac_secs_out = time_spec_cpp.get_frac_secs(); + ) +} + +uhd_error uhd_tx_metadata_start_of_burst( + uhd_tx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->tx_metadata_cpp.start_of_burst; + ) +} + +uhd_error uhd_tx_metadata_end_of_burst( + uhd_tx_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->tx_metadata_cpp.end_of_burst; + ) +} + +uhd_error uhd_tx_metadata_last_error( + uhd_tx_metadata_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +/* + * Async metadata + */ + +uhd_error uhd_async_metadata_make( + uhd_async_metadata_handle* handle +){ + UHD_SAFE_C( + *handle = new uhd_async_metadata_t; + ) +} + +uhd_error uhd_async_metadata_free( + uhd_async_metadata_handle* handle +){ + UHD_SAFE_C( + delete *handle; + *handle = NULL; + ) +} + +uhd_error uhd_async_metadata_channel( + uhd_async_metadata_handle h, + size_t *channel_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *channel_out = h->async_metadata_cpp.channel; + ) +} + +uhd_error uhd_async_metadata_has_time_spec( + uhd_async_metadata_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->async_metadata_cpp.has_time_spec; + ) +} + +uhd_error uhd_async_metadata_time_spec( + uhd_async_metadata_handle h, + time_t *full_secs_out, + double *frac_secs_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp = h->async_metadata_cpp.time_spec; + *full_secs_out = time_spec_cpp.get_full_secs(); + *frac_secs_out = time_spec_cpp.get_frac_secs(); + ) +} + +uhd_error uhd_async_metadata_event_code( + uhd_async_metadata_handle h, + uhd_async_metadata_event_code_t *event_code_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *event_code_out = uhd_async_metadata_event_code_t(h->async_metadata_cpp.event_code); + ) +} + +uhd_error uhd_async_metadata_user_payload( + uhd_async_metadata_handle h, + uint32_t user_payload_out[4] +){ + UHD_SAFE_C_SAVE_ERROR(h, + memcpy(user_payload_out, h->async_metadata_cpp.user_payload, 4*sizeof(uint32_t)); + ) +} + +uhd_error uhd_async_metadata_last_error( + uhd_async_metadata_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} diff --git a/host/lib/types/ranges_c.cpp b/host/lib/types/ranges_c.cpp new file mode 100644 index 000000000..0c0df24ce --- /dev/null +++ b/host/lib/types/ranges_c.cpp @@ -0,0 +1,162 @@ +// +// 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/types/ranges.h> + +#include <string.h> + +/* + * uhd::range_t + */ +uhd_error uhd_range_to_pp_string( + const uhd_range_t *range, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + uhd::range_t range_cpp = uhd_range_c_to_cpp(range); + std::string pp_string_cpp = range_cpp.to_pp_string(); + + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, pp_string_cpp.c_str(), strbuffer_len); + ) +} + +uhd::range_t uhd_range_c_to_cpp( + const uhd_range_t *range_c +){ + return uhd::range_t(range_c->start, range_c->stop, range_c->step); +} + +void uhd_range_cpp_to_c( + const uhd::range_t &range_cpp, + uhd_range_t *range_c +){ + range_c->start = range_cpp.start(); + range_c->stop = range_cpp.stop(); + range_c->step = range_cpp.step(); +} + +/* + * uhd::meta_range_t + */ +uhd_error uhd_meta_range_make( + uhd_meta_range_handle* h +){ + UHD_SAFE_C( + (*h) = new uhd_meta_range_t; + ) +} + +uhd_error uhd_meta_range_free( + uhd_meta_range_handle* h +){ + UHD_SAFE_C( + delete (*h); + (*h) = NULL; + ) +} + +uhd_error uhd_meta_range_start( + uhd_meta_range_handle h, + double *start_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *start_out = h->meta_range_cpp.start(); + ) +} + +uhd_error uhd_meta_range_stop( + uhd_meta_range_handle h, + double *stop_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *stop_out = h->meta_range_cpp.stop(); + ) +} + +uhd_error uhd_meta_range_step( + uhd_meta_range_handle h, + double *step_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *step_out = h->meta_range_cpp.step(); + ) +} + +uhd_error uhd_meta_range_clip( + uhd_meta_range_handle h, + double value, + bool clip_step, + double *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = h->meta_range_cpp.clip(value, clip_step); + ) +} + +uhd_error uhd_meta_range_size( + uhd_meta_range_handle h, + size_t *size_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *size_out = h->meta_range_cpp.size(); + ) +} + +uhd_error uhd_meta_range_push_back( + uhd_meta_range_handle h, + const uhd_range_t *range +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->meta_range_cpp.push_back(uhd_range_c_to_cpp(range)); + ) +} + +uhd_error uhd_meta_range_at( + uhd_meta_range_handle h, + size_t num, + uhd_range_t *range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd_range_cpp_to_c(h->meta_range_cpp.at(num), + range_out); + ) +} + +uhd_error uhd_meta_range_to_pp_string( + uhd_meta_range_handle h, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string pp_string_cpp = h->meta_range_cpp.to_pp_string(); + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, pp_string_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_meta_range_last_error( + uhd_meta_range_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} diff --git a/host/lib/types/sensors_c.cpp b/host/lib/types/sensors_c.cpp new file mode 100644 index 000000000..f1976c102 --- /dev/null +++ b/host/lib/types/sensors_c.cpp @@ -0,0 +1,228 @@ +// +// 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/types/sensors.h> + +#include <boost/lexical_cast.hpp> + +#include <stdexcept> +#include <string.h> +#include <string> + +uhd_error uhd_sensor_value_make_from_bool( + uhd_sensor_value_handle* h, + const char* name, + bool value, + const char* utrue, + const char* ufalse +){ + try{ + *h = new uhd_sensor_value_t; + } + catch(...){ + return UHD_ERROR_UNKNOWN; + } + + UHD_SAFE_C_SAVE_ERROR((*h), + (*h)->sensor_value_cpp = new uhd::sensor_value_t(name, + value, + utrue, + ufalse); + ) +} + +uhd_error uhd_sensor_value_make_from_int( + uhd_sensor_value_handle* h, + const char* name, + int value, + const char* unit, + const char* formatter +){ + try{ + *h = new uhd_sensor_value_t; + } + catch(...){ + return UHD_ERROR_UNKNOWN; + } + + UHD_SAFE_C_SAVE_ERROR((*h), + std::string fmt(formatter); + if(fmt.empty()){ + (*h)->sensor_value_cpp = new uhd::sensor_value_t(name, + value, + unit); + } + else{ + (*h)->sensor_value_cpp = new uhd::sensor_value_t(name, + value, + unit, + fmt); + } + ) +} + +uhd_error uhd_sensor_value_make_from_realnum( + uhd_sensor_value_handle* h, + const char* name, + double value, + const char* unit, + const char* formatter +){ + try{ + *h = new uhd_sensor_value_t; + } + catch(...){ + return UHD_ERROR_UNKNOWN; + } + + UHD_SAFE_C_SAVE_ERROR((*h), + std::string fmt(formatter); + if(fmt.empty()){ + (*h)->sensor_value_cpp = new uhd::sensor_value_t(name, + value, + unit); + } + else{ + (*h)->sensor_value_cpp = new uhd::sensor_value_t(name, + value, + unit, + fmt); + } + ) +} + +uhd_error uhd_sensor_value_make_from_string( + uhd_sensor_value_handle* h, + const char* name, + const char* value, + const char* unit +){ + try{ + *h = new uhd_sensor_value_t; + } + catch(...){ + return UHD_ERROR_UNKNOWN; + } + + UHD_SAFE_C_SAVE_ERROR((*h), + (*h)->sensor_value_cpp = new uhd::sensor_value_t(name, + value, + unit); + ) +} + +uhd_error uhd_sensor_value_free( + uhd_sensor_value_handle *h +){ + UHD_SAFE_C( + delete (*h)->sensor_value_cpp; + delete *h; + *h = NULL; + ) +} + +uhd_error uhd_sensor_value_to_bool( + uhd_sensor_value_handle h, + bool *value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *value_out = h->sensor_value_cpp->to_bool(); + ) +} + +uhd_error uhd_sensor_value_to_int( + uhd_sensor_value_handle h, + int *value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *value_out = h->sensor_value_cpp->to_int(); + ) +} + +uhd_error uhd_sensor_value_to_realnum( + uhd_sensor_value_handle h, + double *value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *value_out = h->sensor_value_cpp->to_real(); + ) +} + +uhd_error uhd_sensor_value_name( + uhd_sensor_value_handle h, + char* name_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + memset(name_out, '\0', strbuffer_len); + strncpy(name_out, h->sensor_value_cpp->name.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_sensor_value_value( + uhd_sensor_value_handle h, + char* value_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + memset(value_out, '\0', strbuffer_len); + strncpy(value_out, h->sensor_value_cpp->value.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_sensor_value_unit( + uhd_sensor_value_handle h, + char* unit_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + memset(unit_out, '\0', strbuffer_len); + strncpy(unit_out, h->sensor_value_cpp->unit.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_sensor_value_data_type( + uhd_sensor_value_handle h, + uhd_sensor_value_data_type_t *data_type_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *data_type_out = uhd_sensor_value_data_type_t(h->sensor_value_cpp->type); + ) +} + +uhd_error uhd_sensor_value_to_pp_string( + uhd_sensor_value_handle h, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string pp_string_cpp = h->sensor_value_cpp->to_pp_string(); + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, pp_string_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_sensor_value_last_error( + uhd_sensor_value_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} diff --git a/host/lib/types/tune_c.cpp b/host/lib/types/tune_c.cpp new file mode 100644 index 000000000..c62935cb8 --- /dev/null +++ b/host/lib/types/tune_c.cpp @@ -0,0 +1,76 @@ +// +// 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/types/tune_request.h> +#include <uhd/types/tune_result.h> + +#include <boost/format.hpp> + +#include <cstdlib> +#include <cstring> +#include <iostream> + +/* + * Tune request + */ + +uhd::tune_request_t uhd_tune_request_c_to_cpp(uhd_tune_request_t *tune_request_c){ + uhd::tune_request_t tune_request_cpp; + + tune_request_cpp.target_freq = tune_request_c->target_freq; + tune_request_cpp.rf_freq_policy = uhd::tune_request_t::policy_t(tune_request_c->rf_freq_policy); + tune_request_cpp.rf_freq = tune_request_c->rf_freq; + tune_request_cpp.dsp_freq_policy = uhd::tune_request_t::policy_t(tune_request_c->dsp_freq_policy); + tune_request_cpp.dsp_freq = tune_request_c->dsp_freq; + + std::string args_cpp = (tune_request_c->args) ? tune_request_c->args : std::string(""); + tune_request_cpp.args = uhd::device_addr_t(args_cpp); + + return tune_request_cpp; +} + +/* + * Tune result + */ + +void uhd_tune_result_to_pp_string(uhd_tune_result_t *tune_result_c, + char* pp_string_out, size_t strbuffer_len){ + std::string pp_string_cpp = uhd_tune_result_c_to_cpp(tune_result_c).to_pp_string(); + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, pp_string_cpp.c_str(), strbuffer_len); +} + +uhd::tune_result_t uhd_tune_result_c_to_cpp(uhd_tune_result_t *tune_result_c){ + uhd::tune_result_t tune_result_cpp; + + tune_result_cpp.clipped_rf_freq = tune_result_c->clipped_rf_freq; + tune_result_cpp.target_rf_freq = tune_result_c->target_rf_freq; + tune_result_cpp.actual_rf_freq = tune_result_c->actual_rf_freq; + tune_result_cpp.target_dsp_freq = tune_result_c->target_dsp_freq; + tune_result_cpp.actual_dsp_freq = tune_result_c->actual_dsp_freq; + + return tune_result_cpp; +} + +void uhd_tune_result_cpp_to_c(const uhd::tune_result_t &tune_result_cpp, + uhd_tune_result_t *tune_result_c){ + tune_result_c->clipped_rf_freq = tune_result_cpp.clipped_rf_freq; + tune_result_c->target_rf_freq = tune_result_cpp.target_rf_freq; + tune_result_c->actual_rf_freq = tune_result_cpp.actual_rf_freq; + tune_result_c->target_dsp_freq = tune_result_cpp.target_dsp_freq; + tune_result_c->actual_dsp_freq = tune_result_cpp.actual_dsp_freq; +} diff --git a/host/lib/types/usrp_info_c.cpp b/host/lib/types/usrp_info_c.cpp new file mode 100644 index 000000000..77354d901 --- /dev/null +++ b/host/lib/types/usrp_info_c.cpp @@ -0,0 +1,44 @@ +// +// 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/types/usrp_info.h> + +uhd_error uhd_usrp_rx_info_free(uhd_usrp_rx_info_t *rx_info){ + free(rx_info->mboard_id); + free(rx_info->mboard_name); + free(rx_info->mboard_serial); + free(rx_info->rx_id); + free(rx_info->rx_subdev_name); + free(rx_info->rx_subdev_spec); + free(rx_info->rx_serial); + free(rx_info->rx_antenna); + + return UHD_ERROR_NONE; +} + +uhd_error uhd_usrp_tx_info_free(uhd_usrp_tx_info_t *tx_info){ + free(tx_info->mboard_id); + free(tx_info->mboard_name); + free(tx_info->mboard_serial); + free(tx_info->tx_id); + free(tx_info->tx_subdev_name); + free(tx_info->tx_subdev_spec); + free(tx_info->tx_serial); + free(tx_info->tx_antenna); + + return UHD_ERROR_NONE; +} diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index ce913aaf6..e01e5e09d 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2013 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 @@ -34,6 +34,15 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/subdev_spec.cpp ) +IF(ENABLE_C_API) + LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/dboard_eeprom_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mboard_eeprom_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/subdev_spec_c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/usrp_c.cpp + ) +ENDIF(ENABLE_C_API) + LIBUHD_REGISTER_COMPONENT("GPSD" ENABLE_GPSD OFF "ENABLE_LIBUHD;ENABLE_GPSD;LIBGPS_FOUND" OFF) IF(ENABLE_GPSD) diff --git a/host/lib/usrp/dboard_eeprom_c.cpp b/host/lib/usrp/dboard_eeprom_c.cpp new file mode 100644 index 000000000..e3ef4933f --- /dev/null +++ b/host/lib/usrp/dboard_eeprom_c.cpp @@ -0,0 +1,109 @@ +// +// 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/usrp/dboard_eeprom.h> +#include <uhd/error.h> + +#include <boost/lexical_cast.hpp> + +#include <string.h> + +uhd_error uhd_dboard_eeprom_make( + uhd_dboard_eeprom_handle* h +){ + UHD_SAFE_C( + *h = new uhd_dboard_eeprom_t; + ) +} + +uhd_error uhd_dboard_eeprom_free( + uhd_dboard_eeprom_handle* h +){ + UHD_SAFE_C( + delete *h; + *h = NULL; + ) +} + +uhd_error uhd_dboard_eeprom_get_id( + uhd_dboard_eeprom_handle h, + char* id_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string dboard_id_cpp = h->dboard_eeprom_cpp.id.to_string(); + strncpy(id_out, dboard_id_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_dboard_eeprom_set_id( + uhd_dboard_eeprom_handle h, + const char* id +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->dboard_eeprom_cpp.id = uhd::usrp::dboard_id_t::from_string(id); + ) +} + +uhd_error uhd_dboard_eeprom_get_serial( + uhd_dboard_eeprom_handle h, + char* id_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string dboard_serial_cpp = h->dboard_eeprom_cpp.serial; + strncpy(id_out, dboard_serial_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_dboard_eeprom_set_serial( + uhd_dboard_eeprom_handle h, + const char* serial +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->dboard_eeprom_cpp.serial = serial; + ) +} + +uhd_error uhd_dboard_eeprom_get_revision( + uhd_dboard_eeprom_handle h, + int* revision_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *revision_out = boost::lexical_cast<int>(h->dboard_eeprom_cpp.revision); + ) +} + +uhd_error uhd_dboard_eeprom_set_revision( + uhd_dboard_eeprom_handle h, + int revision +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->dboard_eeprom_cpp.revision = boost::lexical_cast<std::string>(revision); + ) +} + +uhd_error uhd_dboard_eeprom_last_error( + uhd_dboard_eeprom_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} diff --git a/host/lib/usrp/mboard_eeprom_c.cpp b/host/lib/usrp/mboard_eeprom_c.cpp new file mode 100644 index 000000000..8d5c069b9 --- /dev/null +++ b/host/lib/usrp/mboard_eeprom_c.cpp @@ -0,0 +1,72 @@ +// +// 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/usrp/mboard_eeprom.h> + +#include <uhd/exception.hpp> + +#include <string.h> + +uhd_error uhd_mboard_eeprom_make( + uhd_mboard_eeprom_handle* h +){ + UHD_SAFE_C( + *h = new uhd_mboard_eeprom_t; + ) +} + +uhd_error uhd_mboard_eeprom_free( + uhd_mboard_eeprom_handle* h +){ + UHD_SAFE_C( + delete *h; + *h = NULL; + ) +} + +uhd_error uhd_mboard_eeprom_get_value( + uhd_mboard_eeprom_handle h, + const char* key, + char* value_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string value_cpp = h->mboard_eeprom_cpp.get(key); + strncpy(value_out, value_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_mboard_eeprom_set_value( + uhd_mboard_eeprom_handle h, + const char* key, + const char* value +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->mboard_eeprom_cpp[key] = value; + ) +} + +uhd_error uhd_mboard_eeprom_last_error( + uhd_mboard_eeprom_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} diff --git a/host/lib/usrp/subdev_spec_c.cpp b/host/lib/usrp/subdev_spec_c.cpp new file mode 100644 index 000000000..2c9c20506 --- /dev/null +++ b/host/lib/usrp/subdev_spec_c.cpp @@ -0,0 +1,149 @@ +// +// 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/usrp/subdev_spec.h> + +#include <string.h> + +uhd_error uhd_subdev_spec_pair_free( + uhd_subdev_spec_pair_t *subdev_spec_pair +){ + UHD_SAFE_C( + if(subdev_spec_pair->db_name){ + free(subdev_spec_pair->db_name); + subdev_spec_pair->db_name = NULL; + } + if(subdev_spec_pair->sd_name){ + free(subdev_spec_pair->sd_name); + subdev_spec_pair->sd_name = NULL; + } + ) +} + +uhd_error uhd_subdev_spec_pairs_equal( + const uhd_subdev_spec_pair_t* first, + const uhd_subdev_spec_pair_t* second, + bool *result_out +){ + UHD_SAFE_C( + *result_out = (uhd_subdev_spec_pair_c_to_cpp(first) == + uhd_subdev_spec_pair_c_to_cpp(second)); + ) +} + +uhd_error uhd_subdev_spec_make( + uhd_subdev_spec_handle* h, + const char* markup +){ + UHD_SAFE_C( + (*h) = new uhd_subdev_spec_t; + std::string markup_cpp(markup); + if(!markup_cpp.empty()){ + (*h)->subdev_spec_cpp = uhd::usrp::subdev_spec_t(markup_cpp); + } + ) +} + +uhd_error uhd_subdev_spec_free( + uhd_subdev_spec_handle* h +){ + UHD_SAFE_C( + delete (*h); + (*h) = NULL; + ) +} + +uhd_error uhd_subdev_spec_size( + uhd_subdev_spec_handle h, + size_t *size_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *size_out = h->subdev_spec_cpp.size(); + ) +} + +uhd_error uhd_subdev_spec_push_back( + uhd_subdev_spec_handle h, + const char* markup +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->subdev_spec_cpp.push_back(uhd::usrp::subdev_spec_pair_t(markup)); + ) +} + +uhd_error uhd_subdev_spec_at( + uhd_subdev_spec_handle h, + size_t num, + uhd_subdev_spec_pair_t *subdev_spec_pair_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd_subdev_spec_pair_cpp_to_c( + h->subdev_spec_cpp.at(num), + subdev_spec_pair_out + ); + ) +} + +uhd_error uhd_subdev_spec_to_pp_string( + uhd_subdev_spec_handle h, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string pp_string_cpp = h->subdev_spec_cpp.to_pp_string(); + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, pp_string_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_subdev_spec_to_string( + uhd_subdev_spec_handle h, + char* string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string string_cpp = h->subdev_spec_cpp.to_string(); + memset(string_out, '\0', strbuffer_len); + strncpy(string_out, string_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_subdev_spec_last_error( + uhd_subdev_spec_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +uhd::usrp::subdev_spec_pair_t uhd_subdev_spec_pair_c_to_cpp( + const uhd_subdev_spec_pair_t *subdev_spec_pair_c +){ + return uhd::usrp::subdev_spec_pair_t(subdev_spec_pair_c->db_name, + subdev_spec_pair_c->sd_name); +} + +void uhd_subdev_spec_pair_cpp_to_c( + const uhd::usrp::subdev_spec_pair_t &subdev_spec_pair_cpp, + uhd_subdev_spec_pair_t *subdev_spec_pair_c +){ + subdev_spec_pair_c->db_name = strdup(subdev_spec_pair_cpp.db_name.c_str()); + subdev_spec_pair_c->sd_name = strdup(subdev_spec_pair_cpp.sd_name.c_str()); +} diff --git a/host/lib/usrp/usrp_c.cpp b/host/lib/usrp/usrp_c.cpp new file mode 100644 index 000000000..3eaf70405 --- /dev/null +++ b/host/lib/usrp/usrp_c.cpp @@ -0,0 +1,1509 @@ +/* + * 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/>. + */ + +/* C-Interface for multi_usrp */ + +#include <uhd/utils/static.hpp> +#include <uhd/usrp/multi_usrp.hpp> + +#include <uhd/error.h> +#include <uhd/usrp/usrp.h> + +#include <boost/foreach.hpp> +#include <boost/thread/mutex.hpp> + +#include <string.h> +#include <map> + +/**************************************************************************** + * Helpers + ***************************************************************************/ +uhd::stream_args_t stream_args_c_to_cpp(const uhd_stream_args_t *stream_args_c) +{ + std::string otw_format(stream_args_c->otw_format); + std::string cpu_format(stream_args_c->cpu_format); + std::string args(stream_args_c->args); + std::vector<size_t> channels(stream_args_c->channel_list, stream_args_c->channel_list + stream_args_c->n_channels); + + uhd::stream_args_t stream_args_cpp(cpu_format, otw_format); + stream_args_cpp.args = args; + stream_args_cpp.channels = channels; + + return stream_args_cpp; +} + +uhd::stream_cmd_t stream_cmd_c_to_cpp(const uhd_stream_cmd_t *stream_cmd_c) +{ + uhd::stream_cmd_t stream_cmd_cpp(uhd::stream_cmd_t::stream_mode_t(stream_cmd_c->stream_mode)); + stream_cmd_cpp.num_samps = stream_cmd_c->num_samps; + stream_cmd_cpp.stream_now = stream_cmd_c->stream_now; + stream_cmd_cpp.time_spec = uhd::time_spec_t(stream_cmd_c->time_spec_full_secs, stream_cmd_c->time_spec_frac_secs); + return stream_cmd_cpp; +} + +/**************************************************************************** + * Registry / Pointer Management + ***************************************************************************/ +/* Public structs */ +struct uhd_usrp { + size_t usrp_index; + std::string last_error; +}; + +struct uhd_tx_streamer { + size_t usrp_index; + size_t streamer_index; + std::string last_error; +}; + +struct uhd_rx_streamer { + size_t usrp_index; + size_t streamer_index; + std::string last_error; +}; + +/* Not public: We use this for our internal registry */ +struct usrp_ptr { + uhd::usrp::multi_usrp::sptr ptr; + std::vector< uhd::rx_streamer::sptr > rx_streamers; + std::vector< uhd::tx_streamer::sptr > tx_streamers; + static size_t usrp_counter; +}; +size_t usrp_ptr::usrp_counter = 0; +typedef struct usrp_ptr usrp_ptr; +/* Prefer map, because the list can be discontiguous */ +typedef std::map<size_t, usrp_ptr> usrp_ptrs; + +UHD_SINGLETON_FCN(usrp_ptrs, get_usrp_ptrs); +/* Shortcut for accessing the underlying USRP sptr from a uhd_usrp_handle* */ +#define USRP(h_ptr) (get_usrp_ptrs()[h_ptr->usrp_index].ptr) +#define RX_STREAMER(h_ptr) (get_usrp_ptrs()[h_ptr->usrp_index].rx_streamers[h_ptr->streamer_index]) +#define TX_STREAMER(h_ptr) (get_usrp_ptrs()[h_ptr->usrp_index].tx_streamers[h_ptr->streamer_index]) + +/**************************************************************************** + * RX Streamer + ***************************************************************************/ +static boost::mutex _rx_streamer_make_mutex; +uhd_error uhd_rx_streamer_make(uhd_rx_streamer_handle* h){ + UHD_SAFE_C( + boost::mutex::scoped_lock(_rx_streamer_make_mutex); + (*h) = new uhd_rx_streamer; + ) +} + +static boost::mutex _rx_streamer_free_mutex; +uhd_error uhd_rx_streamer_free(uhd_rx_streamer_handle* h){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_rx_streamer_free_mutex); + delete (*h); + (*h) = NULL; + ) +} + +uhd_error uhd_rx_streamer_num_channels(uhd_rx_streamer_handle h, + size_t *num_channels_out){ + UHD_SAFE_C_SAVE_ERROR(h, + *num_channels_out = RX_STREAMER(h)->get_num_channels(); + ) +} + +uhd_error uhd_rx_streamer_max_num_samps(uhd_rx_streamer_handle h, + size_t *max_num_samps_out){ + UHD_SAFE_C_SAVE_ERROR(h, + *max_num_samps_out = RX_STREAMER(h)->get_max_num_samps(); + ) +} + +uhd_error uhd_rx_streamer_recv( + uhd_rx_streamer_handle h, + void **buffs, + size_t samps_per_buff, + uhd_rx_metadata_handle md, + double timeout, + bool one_packet, + size_t *items_recvd +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::rx_streamer::buffs_type buffs_cpp(buffs, RX_STREAMER(h)->get_num_channels()); + *items_recvd = RX_STREAMER(h)->recv(buffs_cpp, samps_per_buff, md->rx_metadata_cpp, timeout, one_packet); + ) +} + +uhd_error uhd_rx_streamer_issue_stream_cmd( + uhd_rx_streamer_handle h, + const uhd_stream_cmd_t *stream_cmd +){ + UHD_SAFE_C_SAVE_ERROR(h, + RX_STREAMER(h)->issue_stream_cmd(stream_cmd_c_to_cpp(stream_cmd)); + ) +} + +uhd_error uhd_rx_streamer_last_error( + uhd_rx_streamer_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +/**************************************************************************** + * TX Streamer + ***************************************************************************/ +static boost::mutex _tx_streamer_make_mutex; +uhd_error uhd_tx_streamer_make( + uhd_tx_streamer_handle* h +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_tx_streamer_make_mutex); + (*h) = new uhd_tx_streamer; + ) +} + +static boost::mutex _tx_streamer_free_mutex; +uhd_error uhd_tx_streamer_free( + uhd_tx_streamer_handle* h +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_tx_streamer_free_mutex); + delete *h; + *h = NULL; + ) +} + +uhd_error uhd_tx_streamer_num_channels( + uhd_tx_streamer_handle h, + size_t *num_channels_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *num_channels_out = TX_STREAMER(h)->get_num_channels(); + ) +} + +uhd_error uhd_tx_streamer_max_num_samps( + uhd_tx_streamer_handle h, + size_t *max_num_samps_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *max_num_samps_out = TX_STREAMER(h)->get_max_num_samps(); + ) +} + +uhd_error uhd_tx_streamer_send( + uhd_tx_streamer_handle h, + const void **buffs, + const size_t samps_per_buff, + const uhd_tx_metadata_handle md, + const double timeout, + size_t *items_sent +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::tx_streamer::buffs_type buffs_cpp(buffs, TX_STREAMER(h)->get_num_channels()); + *items_sent = TX_STREAMER(h)->send( + buffs_cpp, + samps_per_buff, + md->tx_metadata_cpp, + timeout + ); + ) +} + +uhd_error uhd_tx_streamer_recv_async_msg( + uhd_tx_streamer_handle h, + uhd_async_metadata_handle md, + const double timeout, + bool *valid +){ + UHD_SAFE_C_SAVE_ERROR(h, + *valid = TX_STREAMER(h)->recv_async_msg(md->async_metadata_cpp, timeout); + ) +} + +uhd_error uhd_tx_streamer_last_error( + uhd_tx_streamer_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +/**************************************************************************** + * Generate / Destroy API calls + ***************************************************************************/ +static boost::mutex _usrp_make_mutex; +uhd_error uhd_usrp_make( + uhd_usrp_handle *h, + const char *args +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_usrp_make_mutex); + + size_t usrp_count = usrp_ptr::usrp_counter; + usrp_ptr::usrp_counter++; + + // Initialize USRP + uhd::device_addr_t device_addr(args); + usrp_ptr P; + P.ptr = uhd::usrp::multi_usrp::make(device_addr); + + // Dump into registry + get_usrp_ptrs()[usrp_count] = P; + + // Update handle + (*h) = new uhd_usrp; + (*h)->usrp_index = usrp_count; + ) +} + +static boost::mutex _usrp_free_mutex; +uhd_error uhd_usrp_free( + uhd_usrp_handle *h +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_usrp_free_mutex); + + if(!get_usrp_ptrs().count((*h)->usrp_index)){ + return UHD_ERROR_INVALID_DEVICE; + } + + get_usrp_ptrs().erase((*h)->usrp_index); + delete *h; + *h = NULL; + ) +} + +uhd_error uhd_usrp_last_error( + uhd_usrp_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +static boost::mutex _usrp_get_rx_stream_mutex; +uhd_error uhd_usrp_get_rx_stream( + uhd_usrp_handle h_u, + uhd_stream_args_t *stream_args, + uhd_rx_streamer_handle h_s +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_usrp_get_rx_stream_mutex); + + if(!get_usrp_ptrs().count(h_u->usrp_index)){ + return UHD_ERROR_INVALID_DEVICE; + } + + usrp_ptr &usrp = get_usrp_ptrs()[h_u->usrp_index]; + usrp.rx_streamers.push_back( + usrp.ptr->get_rx_stream(stream_args_c_to_cpp(stream_args)) + ); + h_s->usrp_index = h_u->usrp_index; + h_s->streamer_index = usrp.rx_streamers.size() - 1; + ) +} + +static boost::mutex _usrp_get_tx_stream_mutex; +uhd_error uhd_usrp_get_tx_stream( + uhd_usrp_handle h_u, + uhd_stream_args_t *stream_args, + uhd_tx_streamer_handle h_s +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_usrp_get_tx_stream_mutex); + + if(!get_usrp_ptrs().count(h_u->usrp_index)){ + return UHD_ERROR_INVALID_DEVICE; + } + + usrp_ptr &usrp = get_usrp_ptrs()[h_u->usrp_index]; + usrp.tx_streamers.push_back( + usrp.ptr->get_tx_stream(stream_args_c_to_cpp(stream_args)) + ); + h_s->usrp_index = h_u->usrp_index; + h_s->streamer_index = usrp.tx_streamers.size() - 1; + ) +} + +/**************************************************************************** + * multi_usrp API calls + ***************************************************************************/ + +#define COPY_INFO_FIELD(out, dict, field) \ + out->field = strdup(dict.get(BOOST_STRINGIZE(field)).c_str()) + +uhd_error uhd_usrp_get_rx_info( + uhd_usrp_handle h, + size_t chan, + uhd_usrp_rx_info_t *info_out +) { + UHD_SAFE_C_SAVE_ERROR(h, + uhd::dict<std::string, std::string> rx_info = USRP(h)->get_usrp_rx_info(chan); + + COPY_INFO_FIELD(info_out, rx_info, mboard_id); + COPY_INFO_FIELD(info_out, rx_info, mboard_serial); + COPY_INFO_FIELD(info_out, rx_info, rx_id); + COPY_INFO_FIELD(info_out, rx_info, rx_subdev_name); + COPY_INFO_FIELD(info_out, rx_info, rx_subdev_spec); + COPY_INFO_FIELD(info_out, rx_info, rx_serial); + COPY_INFO_FIELD(info_out, rx_info, rx_antenna); + ) +} + +uhd_error uhd_usrp_get_tx_info( + uhd_usrp_handle h, + size_t chan, + uhd_usrp_tx_info_t *info_out +) { + UHD_SAFE_C_SAVE_ERROR(h, + uhd::dict<std::string, std::string> tx_info = USRP(h)->get_usrp_tx_info(chan); + + COPY_INFO_FIELD(info_out, tx_info, mboard_id); + COPY_INFO_FIELD(info_out, tx_info, mboard_serial); + COPY_INFO_FIELD(info_out, tx_info, tx_id); + COPY_INFO_FIELD(info_out, tx_info, tx_subdev_name); + COPY_INFO_FIELD(info_out, tx_info, tx_subdev_spec); + COPY_INFO_FIELD(info_out, tx_info, tx_serial); + COPY_INFO_FIELD(info_out, tx_info, tx_antenna); + ) +} + +/**************************************************************************** + * Motherboard methods + ***************************************************************************/ +uhd_error uhd_usrp_set_master_clock_rate( + uhd_usrp_handle h, + double rate, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_master_clock_rate(rate, mboard); + ) +} + +uhd_error uhd_usrp_get_master_clock_rate( + uhd_usrp_handle h, + size_t mboard, + double *clock_rate_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *clock_rate_out = USRP(h)->get_master_clock_rate(mboard); + ) +} + +uhd_error uhd_usrp_get_pp_string( + uhd_usrp_handle h, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + strncpy(pp_string_out, USRP(h)->get_pp_string().c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_get_mboard_name( + uhd_usrp_handle h, + size_t mboard, + char* mboard_name_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + strncpy(mboard_name_out, USRP(h)->get_mboard_name(mboard).c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_get_time_now( + uhd_usrp_handle h, + size_t mboard, + time_t *full_secs_out, + double *frac_secs_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp = USRP(h)->get_time_now(mboard); + *full_secs_out = time_spec_cpp.get_full_secs(); + *frac_secs_out = time_spec_cpp.get_frac_secs(); + ) +} + +uhd_error uhd_usrp_get_time_last_pps( + uhd_usrp_handle h, + size_t mboard, + time_t *full_secs_out, + double *frac_secs_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp = USRP(h)->get_time_last_pps(mboard); + *full_secs_out = time_spec_cpp.get_full_secs(); + *frac_secs_out = time_spec_cpp.get_frac_secs(); + ) +} + +uhd_error uhd_usrp_set_time_now( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp(full_secs, frac_secs); + USRP(h)->set_time_now(time_spec_cpp, mboard); + ) +} + +uhd_error uhd_usrp_set_time_next_pps( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp(full_secs, frac_secs); + USRP(h)->set_time_next_pps(time_spec_cpp, mboard); + ) +} + +uhd_error uhd_usrp_set_time_unknown_pps( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp(full_secs, frac_secs); + USRP(h)->set_time_unknown_pps(time_spec_cpp); + ) +} + +uhd_error uhd_usrp_get_time_synchronized( + uhd_usrp_handle h, + bool *result_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *result_out = USRP(h)->get_time_synchronized(); + return UHD_ERROR_NONE; + ) +} + +uhd_error uhd_usrp_set_command_time( + uhd_usrp_handle h, + time_t full_secs, + double frac_secs, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::time_spec_t time_spec_cpp(full_secs, frac_secs); + USRP(h)->set_command_time(time_spec_cpp, mboard); + ) +} + +uhd_error uhd_usrp_clear_command_time( + uhd_usrp_handle h, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->clear_command_time(mboard); + ) +} + +uhd_error uhd_usrp_issue_stream_cmd( + uhd_usrp_handle h, + uhd_stream_cmd_t *stream_cmd, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->issue_stream_cmd(stream_cmd_c_to_cpp(stream_cmd), chan); + ) +} + +uhd_error uhd_usrp_set_time_source( + uhd_usrp_handle h, + const char* time_source, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_time_source(std::string(time_source), mboard); + ) +} + +uhd_error uhd_usrp_get_time_source( + uhd_usrp_handle h, + size_t mboard, + char* time_source_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + strncpy(time_source_out, USRP(h)->get_time_source(mboard).c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_get_time_sources( + uhd_usrp_handle h, + size_t mboard, + char* time_sources_out, + size_t strbuffer_len, + size_t *num_time_sources_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> time_sources = USRP(h)->get_time_sources(mboard); + *num_time_sources_out = time_sources.size(); + + std::string time_sources_str = ""; + BOOST_FOREACH(const std::string &time_source, time_sources){ + time_sources_str += time_source; + time_sources_str += ','; + } + if(time_sources.size() > 0){ + time_sources_str.resize(time_sources_str.size()-1); + } + + memset(time_sources_out, '\0', strbuffer_len); + strncpy(time_sources_out, time_sources_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_clock_source( + uhd_usrp_handle h, + const char* clock_source, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_clock_source(std::string(clock_source), mboard); + ) +} + +uhd_error uhd_usrp_get_clock_source( + uhd_usrp_handle h, + size_t mboard, + char* clock_source_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + strncpy(clock_source_out, USRP(h)->get_clock_source(mboard).c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_get_clock_sources( + uhd_usrp_handle h, + size_t mboard, + char* clock_sources_out, + size_t strbuffer_len, + size_t *num_clock_sources_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> clock_sources = USRP(h)->get_clock_sources(mboard); + *num_clock_sources_out = clock_sources.size(); + + std::string clock_sources_str = ""; + BOOST_FOREACH(const std::string &clock_source, clock_sources){ + clock_sources_str += clock_source; + clock_sources_str += ','; + } + if(clock_sources.size() > 0){ + clock_sources_str.resize(clock_sources_str.size()-1); + } + + memset(clock_sources_out, '\0', strbuffer_len); + strncpy(clock_sources_out, clock_sources_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_clock_source_out( + uhd_usrp_handle h, + bool enb, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_clock_source_out(enb, mboard); + ) +} + +uhd_error uhd_usrp_get_num_mboards( + uhd_usrp_handle h, + size_t *num_mboards_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *num_mboards_out = USRP(h)->get_num_mboards(); + ) +} + +uhd_error uhd_usrp_get_mboard_sensor( + uhd_usrp_handle h, + const char* name, + size_t mboard, + uhd_sensor_value_handle sensor_value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + delete sensor_value_out->sensor_value_cpp; + sensor_value_out->sensor_value_cpp = new uhd::sensor_value_t(USRP(h)->get_mboard_sensor(name, mboard)); + ) +} + +uhd_error uhd_usrp_get_mboard_sensor_names( + uhd_usrp_handle h, + size_t mboard, + char* mboard_sensor_names_out, + size_t strbuffer_len, + size_t *num_mboard_sensors_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> mboard_sensor_names = USRP(h)->get_mboard_sensor_names(mboard); + *num_mboard_sensors_out = mboard_sensor_names.size(); + + std::string mboard_sensor_names_str = ""; + BOOST_FOREACH(const std::string &mboard_sensor_name, mboard_sensor_names){ + mboard_sensor_names_str += mboard_sensor_name; + mboard_sensor_names_str += ','; + } + if(mboard_sensor_names.size() > 0){ + mboard_sensor_names_str.resize(mboard_sensor_names_str.size()-1); + } + + memset(mboard_sensor_names_out, '\0', strbuffer_len); + strncpy(mboard_sensor_names_out, mboard_sensor_names_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_user_register( + uhd_usrp_handle h, + uint8_t addr, + uint32_t data, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_user_register(addr, data, mboard); + ) +} + +/**************************************************************************** + * EEPROM access methods + ***************************************************************************/ + +uhd_error uhd_usrp_get_mboard_eeprom( + uhd_usrp_handle h, + uhd_mboard_eeprom_handle mb_eeprom, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::fs_path eeprom_path = str(boost::format("/mboards/%d/eeprom") + % mboard); + + uhd::property_tree::sptr ptree = USRP(h)->get_device()->get_tree(); + mb_eeprom->mboard_eeprom_cpp = ptree->access<uhd::usrp::mboard_eeprom_t>(eeprom_path).get(); + ) +} + +uhd_error uhd_usrp_set_mboard_eeprom( + uhd_usrp_handle h, + uhd_mboard_eeprom_handle mb_eeprom, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::fs_path eeprom_path = str(boost::format("/mboards/%d/eeprom") + % mboard); + + uhd::property_tree::sptr ptree = USRP(h)->get_device()->get_tree(); + ptree->access<uhd::usrp::mboard_eeprom_t>(eeprom_path).set(mb_eeprom->mboard_eeprom_cpp); + ) +} + +uhd_error uhd_usrp_get_dboard_eeprom( + uhd_usrp_handle h, + uhd_dboard_eeprom_handle db_eeprom, + const char* unit, + const char* slot, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::fs_path eeprom_path = str(boost::format("/mboards/%d/dboards/%s/%s_eeprom") + % mboard % slot % unit); + + uhd::property_tree::sptr ptree = USRP(h)->get_device()->get_tree(); + db_eeprom->dboard_eeprom_cpp = ptree->access<uhd::usrp::dboard_eeprom_t>(eeprom_path).get(); + ) +} + +uhd_error uhd_usrp_set_dboard_eeprom( + uhd_usrp_handle h, + uhd_dboard_eeprom_handle db_eeprom, + const char* unit, + const char* slot, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::fs_path eeprom_path = str(boost::format("/mboards/%d/dboards/%s/%s_eeprom") + % mboard % slot % unit); + + uhd::property_tree::sptr ptree = USRP(h)->get_device()->get_tree(); + ptree->access<uhd::usrp::dboard_eeprom_t>(eeprom_path).set(db_eeprom->dboard_eeprom_cpp); + ) +} + +/**************************************************************************** + * RX methods + ***************************************************************************/ + +uhd_error uhd_usrp_set_rx_subdev_spec( + uhd_usrp_handle h, + uhd_subdev_spec_handle subdev_spec, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_subdev_spec(subdev_spec->subdev_spec_cpp, mboard); + ) +} + +uhd_error uhd_usrp_get_rx_subdev_spec( + uhd_usrp_handle h, + size_t mboard, + uhd_subdev_spec_handle subdev_spec_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + subdev_spec_out->subdev_spec_cpp = USRP(h)->get_rx_subdev_spec(mboard); + ) +} + +uhd_error uhd_usrp_get_rx_num_channels( + uhd_usrp_handle h, + size_t *num_channels_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *num_channels_out = USRP(h)->get_rx_num_channels(); + ) +} + +uhd_error uhd_usrp_get_rx_subdev_name( + uhd_usrp_handle h, + size_t chan, + char* rx_subdev_name_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string rx_subdev_name = USRP(h)->get_rx_subdev_name(chan); + strncpy(rx_subdev_name_out, rx_subdev_name.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_rx_rate( + uhd_usrp_handle h, + double rate, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_rate(rate, chan); + ) +} + +uhd_error uhd_usrp_get_rx_rate( + uhd_usrp_handle h, + size_t chan, + double *rate_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *rate_out = USRP(h)->get_rx_rate(chan); + ) +} + +uhd_error uhd_usrp_get_rx_rates( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle rates_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + rates_out->meta_range_cpp = USRP(h)->get_rx_rates(chan); + ) +} + +uhd_error uhd_usrp_set_rx_freq( + uhd_usrp_handle h, + uhd_tune_request_t *tune_request, + size_t chan, + uhd_tune_result_t *tune_result +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::tune_request_t tune_request_cpp = uhd_tune_request_c_to_cpp(tune_request); + uhd::tune_result_t tune_result_cpp = USRP(h)->set_rx_freq(tune_request_cpp, chan); + uhd_tune_result_cpp_to_c(tune_result_cpp, tune_result); + ) +} + +uhd_error uhd_usrp_get_rx_freq( + uhd_usrp_handle h, + size_t chan, + double *freq_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *freq_out = USRP(h)->get_rx_freq(chan); + ) +} + +uhd_error uhd_usrp_get_rx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + freq_range_out->meta_range_cpp = USRP(h)->get_rx_freq_range(chan); + ) +} + +uhd_error uhd_usrp_get_fe_rx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + freq_range_out->meta_range_cpp = USRP(h)->get_fe_rx_freq_range(chan); + ) +} + +uhd_error uhd_usrp_set_rx_gain( + uhd_usrp_handle h, + double gain, + size_t chan, + const char *gain_name +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string name(gain_name); + if(name.empty()){ + USRP(h)->set_rx_gain(gain, chan); + } + else{ + USRP(h)->set_rx_gain(gain, name, chan); + } + ) +} + +uhd_error uhd_usrp_set_normalized_rx_gain( + uhd_usrp_handle h, + double gain, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_normalized_rx_gain(gain, chan); + ) +} + +uhd_error uhd_usrp_set_rx_agc( + uhd_usrp_handle h, + bool enable, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_agc(enable, chan); + ) +} + +uhd_error uhd_usrp_get_rx_gain( + uhd_usrp_handle h, + size_t chan, + const char *gain_name, + double *gain_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string name(gain_name); + if(name.empty()){ + *gain_out = USRP(h)->get_rx_gain(chan); + } + else{ + *gain_out = USRP(h)->get_rx_gain(name, chan); + } + ) +} + +uhd_error uhd_usrp_get_normalized_rx_gain( + uhd_usrp_handle h, + size_t chan, + double *gain_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *gain_out = USRP(h)->get_normalized_rx_gain(chan); + ) +} + +uhd_error uhd_usrp_get_rx_gain_range( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_meta_range_handle gain_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + gain_range_out->meta_range_cpp = USRP(h)->get_rx_gain_range(name, chan); + ) +} + +uhd_error uhd_usrp_get_rx_gain_names( + uhd_usrp_handle h, + size_t chan, + char* gain_names_out, + size_t strbuffer_len, + size_t *num_rx_gain_names_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> rx_gain_names = USRP(h)->get_rx_gain_names(chan); + *num_rx_gain_names_out = rx_gain_names.size(); + + std::string rx_gain_names_str = ""; + BOOST_FOREACH(const std::string &gain_name, rx_gain_names){ + rx_gain_names_str += gain_name; + rx_gain_names_str += ','; + } + if(rx_gain_names.size() > 0){ + rx_gain_names_str.resize(rx_gain_names_str.size()-1); + } + + memset(gain_names_out, '\0', strbuffer_len); + strncpy(gain_names_out, rx_gain_names_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_rx_antenna( + uhd_usrp_handle h, + const char* ant, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_antenna(std::string(ant), chan); + ) +} + +uhd_error uhd_usrp_get_rx_antenna( + uhd_usrp_handle h, + size_t chan, + char* ant_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string rx_antenna = USRP(h)->get_rx_antenna(chan); + strncpy(ant_out, rx_antenna.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_get_rx_antennas( + uhd_usrp_handle h, + size_t chan, + char* antennas_out, + size_t strbuffer_len, + size_t *num_rx_antennas_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> rx_antennas = USRP(h)->get_rx_antennas(chan); + *num_rx_antennas_out = rx_antennas.size(); + + std::string rx_antennas_str = ""; + BOOST_FOREACH(const std::string &rx_antenna, rx_antennas){ + rx_antennas_str += rx_antenna; + rx_antennas_str += ','; + } + if(rx_antennas.size() > 0){ + rx_antennas_str.resize(rx_antennas_str.size()-1); + } + + memset(antennas_out, '\0', strbuffer_len); + strncpy(antennas_out, rx_antennas_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_rx_bandwidth( + uhd_usrp_handle h, + double bandwidth, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_bandwidth(bandwidth, chan); + ) +} + +uhd_error uhd_usrp_get_rx_bandwidth( + uhd_usrp_handle h, + size_t chan, + double *bandwidth_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *bandwidth_out = USRP(h)->get_rx_bandwidth(chan); + ) +} + +uhd_error uhd_usrp_get_rx_bandwidth_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle bandwidth_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + bandwidth_range_out->meta_range_cpp = USRP(h)->get_rx_bandwidth_range(chan); + ) +} + +uhd_error uhd_usrp_get_rx_sensor( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_sensor_value_handle sensor_value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + delete sensor_value_out->sensor_value_cpp; + sensor_value_out->sensor_value_cpp = new uhd::sensor_value_t(USRP(h)->get_rx_sensor(name, chan)); + ) +} + +uhd_error uhd_usrp_get_rx_sensor_names( + uhd_usrp_handle h, + size_t chan, + char* sensor_names_out, + size_t strbuffer_len, + size_t *num_rx_sensors_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> rx_sensor_names = USRP(h)->get_rx_sensor_names(chan); + *num_rx_sensors_out = rx_sensor_names.size(); + + std::string rx_sensor_names_str = ""; + BOOST_FOREACH(const std::string &rx_sensor_name, rx_sensor_names){ + rx_sensor_names_str += rx_sensor_name; + rx_sensor_names_str += ','; + } + if(rx_sensor_names.size() > 0){ + rx_sensor_names_str.resize(rx_sensor_names_str.size()-1); + } + + memset(sensor_names_out, '\0', strbuffer_len); + strncpy(sensor_names_out, rx_sensor_names_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_rx_dc_offset_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_dc_offset(enb, chan); + ) +} + +uhd_error uhd_usrp_set_rx_iq_balance_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_rx_iq_balance(enb, chan); + ) +} + +/**************************************************************************** + * TX methods + ***************************************************************************/ + +uhd_error uhd_usrp_set_tx_subdev_spec( + uhd_usrp_handle h, + uhd_subdev_spec_handle subdev_spec, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_tx_subdev_spec(subdev_spec->subdev_spec_cpp, mboard); + ) +} + +uhd_error uhd_usrp_get_tx_subdev_spec( + uhd_usrp_handle h, + size_t mboard, + uhd_subdev_spec_handle subdev_spec_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + subdev_spec_out->subdev_spec_cpp = USRP(h)->get_tx_subdev_spec(mboard); + ) +} + + +uhd_error uhd_usrp_get_tx_num_channels( + uhd_usrp_handle h, + size_t *num_channels_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *num_channels_out = USRP(h)->get_tx_num_channels(); + ) +} + +uhd_error uhd_usrp_get_tx_subdev_name( + uhd_usrp_handle h, + size_t chan, + char* tx_subdev_name_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string tx_subdev_name = USRP(h)->get_tx_subdev_name(chan); + strncpy(tx_subdev_name_out, tx_subdev_name.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_tx_rate( + uhd_usrp_handle h, + double rate, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_tx_rate(rate, chan); + ) +} + +uhd_error uhd_usrp_get_tx_rate( + uhd_usrp_handle h, + size_t chan, + double *rate_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *rate_out = USRP(h)->get_tx_rate(chan); + ) +} + +uhd_error uhd_usrp_get_tx_rates( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle rates_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + rates_out->meta_range_cpp = USRP(h)->get_tx_rates(chan); + ) +} + +uhd_error uhd_usrp_set_tx_freq( + uhd_usrp_handle h, + uhd_tune_request_t *tune_request, + size_t chan, + uhd_tune_result_t *tune_result +){ + UHD_SAFE_C_SAVE_ERROR(h, + uhd::tune_request_t tune_request_cpp = uhd_tune_request_c_to_cpp(tune_request); + uhd::tune_result_t tune_result_cpp = USRP(h)->set_tx_freq(tune_request_cpp, chan); + uhd_tune_result_cpp_to_c(tune_result_cpp, tune_result); + ) +} + +uhd_error uhd_usrp_get_tx_freq( + uhd_usrp_handle h, + size_t chan, + double *freq_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *freq_out = USRP(h)->get_tx_freq(chan); + ) +} + +uhd_error uhd_usrp_get_tx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + freq_range_out->meta_range_cpp = USRP(h)->get_tx_freq_range(chan); + ) +} + +uhd_error uhd_usrp_get_fe_tx_freq_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle freq_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + freq_range_out->meta_range_cpp = USRP(h)->get_fe_tx_freq_range(chan); + ) +} + +uhd_error uhd_usrp_set_tx_gain( + uhd_usrp_handle h, + double gain, + size_t chan, + const char *gain_name +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string name(gain_name); + if(name.empty()){ + USRP(h)->set_tx_gain(gain, chan); + } + else{ + USRP(h)->set_tx_gain(gain, name, chan); + } + ) +} + +uhd_error uhd_usrp_set_normalized_tx_gain( + uhd_usrp_handle h, + double gain, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_normalized_tx_gain(gain, chan); + ) +} + +uhd_error uhd_usrp_get_tx_gain( + uhd_usrp_handle h, + size_t chan, + const char *gain_name, + double *gain_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string name(gain_name); + if(name.empty()){ + *gain_out = USRP(h)->get_tx_gain(chan); + } + else{ + *gain_out = USRP(h)->get_tx_gain(name, chan); + } + ) +} + +uhd_error uhd_usrp_get_normalized_tx_gain( + uhd_usrp_handle h, + size_t chan, + double *gain_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *gain_out = USRP(h)->get_normalized_tx_gain(chan); + ) +} + +uhd_error uhd_usrp_get_tx_gain_range( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_meta_range_handle gain_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + gain_range_out->meta_range_cpp = USRP(h)->get_tx_gain_range(name, chan); + ) +} + +uhd_error uhd_usrp_get_tx_gain_names( + uhd_usrp_handle h, + size_t chan, + char* gain_names_out, + size_t strbuffer_len, + size_t *num_tx_gain_names_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> tx_gain_names = USRP(h)->get_tx_gain_names(chan); + *num_tx_gain_names_out = tx_gain_names.size(); + + std::string tx_gain_names_str = ""; + BOOST_FOREACH(const std::string &tx_gain_name, tx_gain_names){ + tx_gain_names_str += tx_gain_name; + tx_gain_names_str += ','; + } + if(tx_gain_names.size() > 0){ + tx_gain_names_str.resize(tx_gain_names_str.size()-1); + } + + memset(gain_names_out, '\0', strbuffer_len); + strncpy(gain_names_out, tx_gain_names_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_tx_antenna( + uhd_usrp_handle h, + const char* ant, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_tx_antenna(std::string(ant), chan); + ) +} + +uhd_error uhd_usrp_get_tx_antenna( + uhd_usrp_handle h, + size_t chan, + char* ant_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::string tx_antenna = USRP(h)->get_tx_antenna(chan); + strncpy(ant_out, tx_antenna.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_get_tx_antennas( + uhd_usrp_handle h, + size_t chan, + char* antennas_out, + size_t strbuffer_len, + size_t *num_tx_antennas_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> tx_antennas = USRP(h)->get_tx_antennas(chan); + *num_tx_antennas_out = tx_antennas.size(); + + std::string tx_antennas_str = ""; + BOOST_FOREACH(const std::string &tx_antenna, tx_antennas){ + tx_antennas_str += tx_antenna; + tx_antennas_str += ','; + } + if(tx_antennas.size() > 0){ + tx_antennas_str.resize(tx_antennas_str.size()-1); + } + + memset(antennas_out, '\0', strbuffer_len); + strncpy(antennas_out, tx_antennas_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_tx_bandwidth( + uhd_usrp_handle h, + double bandwidth, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_tx_bandwidth(bandwidth, chan); + ) +} + +uhd_error uhd_usrp_get_tx_bandwidth( + uhd_usrp_handle h, + size_t chan, + double *bandwidth_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *bandwidth_out = USRP(h)->get_tx_bandwidth(chan); + ) +} + +uhd_error uhd_usrp_get_tx_bandwidth_range( + uhd_usrp_handle h, + size_t chan, + uhd_meta_range_handle bandwidth_range_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + bandwidth_range_out->meta_range_cpp = USRP(h)->get_tx_bandwidth_range(chan); + ) +} + +uhd_error uhd_usrp_get_tx_sensor( + uhd_usrp_handle h, + const char* name, + size_t chan, + uhd_sensor_value_handle sensor_value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + delete sensor_value_out->sensor_value_cpp; + sensor_value_out->sensor_value_cpp = new uhd::sensor_value_t(USRP(h)->get_tx_sensor(name, chan)); + ) +} + +uhd_error uhd_usrp_get_tx_sensor_names( + uhd_usrp_handle h, + size_t chan, + char* sensor_names_out, + size_t strbuffer_len, + size_t *num_tx_sensors_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> tx_sensor_names = USRP(h)->get_tx_sensor_names(chan); + *num_tx_sensors_out = tx_sensor_names.size(); + + std::string tx_sensor_names_str = ""; + BOOST_FOREACH(const std::string &tx_sensor_name, tx_sensor_names){ + tx_sensor_names_str += tx_sensor_name; + tx_sensor_names_str += ','; + } + if(tx_sensor_names.size() > 0){ + tx_sensor_names_str.resize(tx_sensor_names_str.size()-1); + } + + memset(sensor_names_out, '\0', strbuffer_len); + strncpy(sensor_names_out, tx_sensor_names_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_tx_dc_offset_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_tx_dc_offset(enb, chan); + ) +} + +uhd_error uhd_usrp_set_tx_iq_balance_enabled( + uhd_usrp_handle h, + bool enb, + size_t chan +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_tx_iq_balance(enb, chan); + ) +} + +/**************************************************************************** + * GPIO methods + ***************************************************************************/ + +uhd_error uhd_usrp_get_gpio_banks( + uhd_usrp_handle h, + size_t chan, + char* gpio_banks_out, + size_t strbuffer_len, + size_t *num_gpio_banks_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> gpio_banks = USRP(h)->get_gpio_banks(chan); + *num_gpio_banks_out = gpio_banks.size(); + + std::string gpio_banks_str = ""; + BOOST_FOREACH(const std::string &gpio_bank, gpio_banks){ + gpio_banks_str += gpio_bank; + gpio_banks_str += ','; + } + if(gpio_banks.size() > 0){ + gpio_banks_str.resize(gpio_banks_str.size()-1); + } + + memset(gpio_banks_out, '\0', strbuffer_len); + strncpy(gpio_banks_out, gpio_banks_str.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_set_gpio_attr( + uhd_usrp_handle h, + const char* bank, + const char* attr, + uint32_t value, + uint32_t mask, + size_t mboard +){ + UHD_SAFE_C_SAVE_ERROR(h, + USRP(h)->set_gpio_attr(std::string(bank), std::string(attr), + value, mask, mboard); + ) +} + +uhd_error uhd_usrp_get_gpio_attr( + uhd_usrp_handle h, + const char* bank, + const char* attr, + size_t mboard, + uint32_t *attr_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *attr_out = USRP(h)->get_gpio_attr(std::string(bank), std::string(attr), mboard); + ) +} diff --git a/host/lib/usrp_clock/CMakeLists.txt b/host/lib/usrp_clock/CMakeLists.txt index 8a58aa9ac..ba0f5fe0a 100644 --- a/host/lib/usrp_clock/CMakeLists.txt +++ b/host/lib/usrp_clock/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2011-2014 Ettus Research LLC +# Copyright 2011-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 @@ -23,4 +23,10 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/multi_usrp_clock.cpp ) +IF(ENABLE_C_API) + LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/usrp_clock_c.cpp + ) +ENDIF(ENABLE_C_API) + INCLUDE_SUBDIRECTORY(octoclock) diff --git a/host/lib/usrp_clock/usrp_clock_c.cpp b/host/lib/usrp_clock/usrp_clock_c.cpp new file mode 100644 index 000000000..b55abc852 --- /dev/null +++ b/host/lib/usrp_clock/usrp_clock_c.cpp @@ -0,0 +1,175 @@ +/* + * 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/>. + */ + +/* C-Interface for multi_usrp_clock */ + +#include <uhd/utils/static.hpp> +#include <uhd/usrp_clock/multi_usrp_clock.hpp> + +#include <uhd/usrp_clock/usrp_clock.h> + +#include <boost/foreach.hpp> +#include <boost/thread/mutex.hpp> + +#include <string.h> +#include <map> + +/**************************************************************************** + * Registry / Pointer Management + ***************************************************************************/ +/* Public structs */ +struct uhd_usrp_clock { + size_t usrp_clock_index; + std::string last_error; +}; + +/* Not public: We use this for our internal registry */ +struct usrp_clock_ptr { + uhd::usrp_clock::multi_usrp_clock::sptr ptr; + static size_t usrp_clock_counter; +}; +size_t usrp_clock_ptr::usrp_clock_counter = 0; +typedef struct usrp_clock_ptr usrp_clock_ptr; +/* Prefer map, because the list can be discontiguous */ +typedef std::map<size_t, usrp_clock_ptr> usrp_clock_ptrs; + +UHD_SINGLETON_FCN(usrp_clock_ptrs, get_usrp_clock_ptrs); +/* Shortcut for accessing the underlying USRP clock sptr from a uhd_usrp_clock_handle* */ +#define USRP_CLOCK(h_ptr) (get_usrp_clock_ptrs()[h_ptr->usrp_clock_index].ptr) + +/**************************************************************************** + * Generate / Destroy API calls + ***************************************************************************/ +static boost::mutex _usrp_clock_make_mutex; +uhd_error uhd_usrp_clock_make( + uhd_usrp_clock_handle *h, + const char *args +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_usrp_clock_make_mutex); + + size_t usrp_clock_count = usrp_clock_ptr::usrp_clock_counter; + usrp_clock_ptr::usrp_clock_counter++; + + // Initialize USRP Clock + uhd::device_addr_t device_addr(args); + usrp_clock_ptr P; + P.ptr = uhd::usrp_clock::multi_usrp_clock::make(device_addr); + + // Dump into registry + get_usrp_clock_ptrs()[usrp_clock_count] = P; + + // Update handle + (*h) = new uhd_usrp_clock; + (*h)->usrp_clock_index = usrp_clock_count; + ) +} + +static boost::mutex _usrp_clock_free_mutex; +uhd_error uhd_usrp_clock_free( + uhd_usrp_clock_handle *h +){ + UHD_SAFE_C( + boost::mutex::scoped_lock lock(_usrp_clock_free_mutex); + + if(!get_usrp_clock_ptrs().count((*h)->usrp_clock_index)){ + return UHD_ERROR_INVALID_DEVICE; + } + + get_usrp_clock_ptrs().erase((*h)->usrp_clock_index); + delete *h; + *h = NULL; + ) +} + +uhd_error uhd_usrp_clock_last_error( + uhd_usrp_clock_handle h, + char* error_out, + size_t strbuffer_len +){ + UHD_SAFE_C( + memset(error_out, '\0', strbuffer_len); + strncpy(error_out, h->last_error.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_clock_get_pp_string( + uhd_usrp_clock_handle h, + char* pp_string_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + memset(pp_string_out, '\0', strbuffer_len); + strncpy(pp_string_out, USRP_CLOCK(h)->get_pp_string().c_str(), strbuffer_len); + ) +} + +uhd_error uhd_usrp_clock_get_num_boards( + uhd_usrp_clock_handle h, + size_t *num_boards_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *num_boards_out = USRP_CLOCK(h)->get_num_boards(); + ) +} + +uhd_error uhd_usrp_clock_get_time( + uhd_usrp_clock_handle h, + size_t board, + uint32_t *clock_time_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *clock_time_out = USRP_CLOCK(h)->get_time(board); + ) +} + +uhd_error uhd_usrp_clock_get_sensor( + uhd_usrp_clock_handle h, + const char* name, + size_t board, + uhd_sensor_value_handle sensor_value_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + delete sensor_value_out->sensor_value_cpp; + sensor_value_out->sensor_value_cpp = new uhd::sensor_value_t(USRP_CLOCK(h)->get_sensor(name, board)); + ) +} + +uhd_error uhd_usrp_clock_get_sensor_names( + uhd_usrp_clock_handle h, + size_t board, + char* sensor_names_out, + size_t strbuffer_len, + size_t *num_sensors_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + std::vector<std::string> sensor_names = USRP_CLOCK(h)->get_sensor_names(board); + *num_sensors_out = sensor_names.size(); + + std::string sensor_names_str = ""; + BOOST_FOREACH(const std::string &sensor_name, sensor_names){ + sensor_names_str += sensor_name; + sensor_names_str += ','; + } + if(sensor_names.size() > 0){ + sensor_names_str.resize(sensor_names_str.size()-1); + } + + memset(sensor_names_out, '\0', strbuffer_len); + strncpy(sensor_names_out, sensor_names_str.c_str(), strbuffer_len); + ) +} diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt index 369920ac1..c5c975dfa 100644 --- a/host/lib/utils/CMakeLists.txt +++ b/host/lib/utils/CMakeLists.txt @@ -141,3 +141,9 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/tasks.cpp ${CMAKE_CURRENT_SOURCE_DIR}/thread_priority.cpp ) + +IF(ENABLE_C_API) + LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/thread_priority_c.cpp + ) +ENDIF(ENABLE_C_API) diff --git a/host/lib/utils/thread_priority.cpp b/host/lib/utils/thread_priority.cpp index af25d088a..98023c5aa 100644 --- a/host/lib/utils/thread_priority.cpp +++ b/host/lib/utils/thread_priority.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2011,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 diff --git a/host/lib/utils/thread_priority_c.cpp b/host/lib/utils/thread_priority_c.cpp new file mode 100644 index 000000000..fe019e51d --- /dev/null +++ b/host/lib/utils/thread_priority_c.cpp @@ -0,0 +1,33 @@ +// +// 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/error.h> +#include <uhd/utils/thread_priority.h> +#include <uhd/utils/thread_priority.hpp> +#include <uhd/utils/msg.hpp> +#include <uhd/exception.hpp> +#include <boost/format.hpp> +#include <iostream> + +uhd_error uhd_set_thread_priority( + float priority, + bool realtime +){ + UHD_SAFE_C( + uhd::set_thread_priority(priority, realtime); + ) +} diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt index 1fb1a1951..009509286 100644 --- a/host/tests/CMakeLists.txt +++ b/host/tests/CMakeLists.txt @@ -53,6 +53,16 @@ ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK -DBOOST_TEST_MAIN) SET(UHD_TEST_TARGET_DEPS uhd) SET(UHD_TEST_LIBRARY_DIRS ${Boost_LIBRARY_DIRS}) +IF(ENABLE_C_API) + LIST(APPEND test_sources + eeprom_c_test.c + error_c_test.cpp + ranges_c_test.c + sensors_c_test.c + subdev_spec_c_test.c + ) +ENDIF(ENABLE_C_API) + #for each source: build an executable, register it as a test FOREACH(test_source ${test_sources}) GET_FILENAME_COMPONENT(test_name ${test_source} NAME_WE) diff --git a/host/tests/eeprom_c_test.c b/host/tests/eeprom_c_test.c new file mode 100644 index 000000000..0f03295e8 --- /dev/null +++ b/host/tests/eeprom_c_test.c @@ -0,0 +1,155 @@ +// +// 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define UHD_TEST_EXECUTE_OR_GOTO(label, ...) \ + if(__VA_ARGS__){ \ + fprintf(stderr, "Error occurred at %s:%d\n", __FILE__, (__LINE__-1)); \ + return_code = EXIT_FAILURE; \ + goto label; \ + } + +#define BUFFER_SIZE 1024 + +int main(){ + + // Variables + int return_code; + uhd_mboard_eeprom_handle mb_eeprom; + uhd_dboard_eeprom_handle db_eeprom; + int db_revision; + char str_buffer[BUFFER_SIZE]; + + return_code = EXIT_SUCCESS; + + /* + * Motherboard EEPROM test + */ + + // Create EEPROM handle + UHD_TEST_EXECUTE_OR_GOTO(end_of_test, + uhd_mboard_eeprom_make(&mb_eeprom) + ) + + // Set a value, retrieve it, and make sure it matches + UHD_TEST_EXECUTE_OR_GOTO(free_mboard_eeprom, + uhd_mboard_eeprom_set_value( + mb_eeprom, + "serial", + "F12345" + ) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_mboard_eeprom, + uhd_mboard_eeprom_get_value( + mb_eeprom, + "serial", + str_buffer, + BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "F12345")){ + return_code = EXIT_FAILURE; + fprintf(stderr, "%s:%d: Mismatched EEPROM value: \"%s\" vs. \"F12345\"\n", + __FILE__, __LINE__, + str_buffer); + goto free_mboard_eeprom; + } + + /* + * Daughterboard EEPROM test + */ + + // Create EEPROM handle + UHD_TEST_EXECUTE_OR_GOTO(free_mboard_eeprom, + uhd_dboard_eeprom_make(&db_eeprom) + ) + + // Set the ID, retrieve it, and make sure it matches + UHD_TEST_EXECUTE_OR_GOTO(free_dboard_eeprom, + uhd_dboard_eeprom_set_id(db_eeprom, "0x0067") + ) + UHD_TEST_EXECUTE_OR_GOTO(free_dboard_eeprom, + uhd_dboard_eeprom_get_id( + db_eeprom, + str_buffer, + BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "0x0067")){ + return_code = EXIT_FAILURE; + fprintf(stderr, "%s:%d: Mismatched daughterboard ID: \"%s\" vs. \"0x0067\"\n", + __FILE__, __LINE__, + str_buffer); + goto free_dboard_eeprom; + } + + // Set the serial, retrieve it, and make sure it matches + UHD_TEST_EXECUTE_OR_GOTO(free_dboard_eeprom, + uhd_dboard_eeprom_set_serial(db_eeprom, "F12345") + ) + UHD_TEST_EXECUTE_OR_GOTO(free_dboard_eeprom, + uhd_dboard_eeprom_get_serial( + db_eeprom, + str_buffer, + BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "F12345")){ + return_code = EXIT_FAILURE; + fprintf(stderr, "%s:%d: Mismatched daughterboard serial: \"%s\" vs. \"F12345\"\n", + __FILE__, __LINE__, + str_buffer); + goto free_dboard_eeprom; + } + + // Set the revision, retrieve it, and make sure it matches + UHD_TEST_EXECUTE_OR_GOTO(free_dboard_eeprom, + uhd_dboard_eeprom_set_revision(db_eeprom, 4) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_dboard_eeprom, + uhd_dboard_eeprom_get_revision(db_eeprom, &db_revision) + ) + if(db_revision != 4){ + return_code = EXIT_FAILURE; + fprintf(stderr, "%s:%d: Mismatched daughterboard revision: \"%d\" vs. 4\n", + __FILE__, __LINE__, db_revision); + goto free_dboard_eeprom; + } + + free_dboard_eeprom: + if(return_code){ + uhd_dboard_eeprom_last_error(db_eeprom, str_buffer, BUFFER_SIZE); + fprintf(stderr, "db_eeprom error: %s\n", str_buffer); + } + + free_mboard_eeprom: + if(return_code){ + uhd_mboard_eeprom_last_error(mb_eeprom, str_buffer, BUFFER_SIZE); + fprintf(stderr, "mb_eeprom error: %s\n", str_buffer); + } + + end_of_test: + if(!return_code){ + printf("\nNo errors detected\n"); + } + return return_code; +} diff --git a/host/tests/error_c_test.cpp b/host/tests/error_c_test.cpp new file mode 100644 index 000000000..bb9454678 --- /dev/null +++ b/host/tests/error_c_test.cpp @@ -0,0 +1,142 @@ +// +// 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/error.h> +#include <uhd/types/dict.hpp> + +#include <boost/test/unit_test.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/assign.hpp> +#include <boost/format.hpp> + +/* + * Test our conversions from exceptions to C-level UHD error codes. + * We use inline functions separate from the Boost test cases themselves + * to test our C++ macro, which returns the error code. + */ + +typedef struct { + std::string last_error; +} dummy_handle_t; + +template <typename error_type> +UHD_INLINE uhd_error throw_uhd_exception(dummy_handle_t *handle, const uhd::exception* except){ + UHD_SAFE_C_SAVE_ERROR(handle, + throw *dynamic_cast<const error_type*>(except); + ) +} + +UHD_INLINE uhd_error throw_boost_exception(dummy_handle_t *handle){ + UHD_SAFE_C_SAVE_ERROR(handle, + std::runtime_error except("This is a std::runtime_error, thrown by Boost."); + BOOST_THROW_EXCEPTION(except); + ) +} + +UHD_INLINE uhd_error throw_std_exception(dummy_handle_t *handle){ + UHD_SAFE_C_SAVE_ERROR(handle, + throw std::runtime_error("This is a std::runtime_error."); + ) +} + +UHD_INLINE uhd_error throw_unknown_exception(dummy_handle_t *handle){ + UHD_SAFE_C_SAVE_ERROR(handle, + throw 1; + ) +} + +// There are enough non-standard names that we can't just use a conversion function +static const uhd::dict<std::string, std::string> pretty_exception_names = + boost::assign::map_list_of + ("assertion_error", "AssertionError") + ("lookup_error", "LookupError") + ("index_error", "LookupError: IndexError") + ("key_error", "LookupError: KeyError") + ("type_error", "TypeError") + ("value_error", "ValueError") + ("runtime_error", "RuntimeError") + ("not_implemented_error", "RuntimeError: NotImplementedError") + ("usb_error", "RuntimeError: USBError 1") + ("environment_error", "EnvironmentError") + ("io_error", "EnvironmentError: IOError") + ("os_error", "EnvironmentError: OSError") + ("system_error", "SystemError") + ; + +#define UHD_TEST_CHECK_ERROR_CODE(cpp_exception_type, c_error_code) \ + expected_msg = str(boost::format("This is a uhd::%s.") % BOOST_STRINGIZE(cpp_exception_type)); \ + uhd::cpp_exception_type cpp_exception_type ## _foo(expected_msg); \ + error_code = throw_uhd_exception<uhd::cpp_exception_type>(&handle, &cpp_exception_type ## _foo); \ + BOOST_CHECK_EQUAL(error_code, c_error_code); \ + BOOST_CHECK_EQUAL(handle.last_error, \ + str(boost::format("%s: %s") \ + % pretty_exception_names.get(BOOST_STRINGIZE(cpp_exception_type)) \ + % expected_msg)); + +// uhd::usb_error has a different constructor +#define UHD_TEST_CHECK_USB_ERROR_CODE() \ + expected_msg = "This is a uhd::usb_error."; \ + uhd::usb_error usb_error_foo(1, expected_msg); \ + error_code = throw_uhd_exception<uhd::usb_error>(&handle, &usb_error_foo); \ + BOOST_CHECK_EQUAL(error_code, UHD_ERROR_USB); \ + BOOST_CHECK_EQUAL(handle.last_error, \ + str(boost::format("%s: %s") \ + % pretty_exception_names.get("usb_error") \ + % expected_msg)); + +BOOST_AUTO_TEST_CASE(test_uhd_exception){ + dummy_handle_t handle; + std::string expected_msg; + uhd_error error_code; + + UHD_TEST_CHECK_ERROR_CODE(assertion_error, UHD_ERROR_ASSERTION); + UHD_TEST_CHECK_ERROR_CODE(lookup_error, UHD_ERROR_LOOKUP); + UHD_TEST_CHECK_ERROR_CODE(index_error, UHD_ERROR_INDEX); + UHD_TEST_CHECK_ERROR_CODE(key_error, UHD_ERROR_KEY); + UHD_TEST_CHECK_ERROR_CODE(type_error, UHD_ERROR_TYPE); + UHD_TEST_CHECK_ERROR_CODE(value_error, UHD_ERROR_VALUE); + UHD_TEST_CHECK_ERROR_CODE(runtime_error, UHD_ERROR_RUNTIME); + UHD_TEST_CHECK_ERROR_CODE(not_implemented_error, UHD_ERROR_NOT_IMPLEMENTED); + UHD_TEST_CHECK_ERROR_CODE(io_error, UHD_ERROR_IO); + UHD_TEST_CHECK_ERROR_CODE(os_error, UHD_ERROR_OS); + UHD_TEST_CHECK_ERROR_CODE(system_error, UHD_ERROR_SYSTEM); + UHD_TEST_CHECK_USB_ERROR_CODE(); +} + +BOOST_AUTO_TEST_CASE(test_boost_exception){ + dummy_handle_t handle; + uhd_error error_code = throw_boost_exception(&handle); + + // Boost error message cannot be determined here, so just check code + BOOST_CHECK_EQUAL(error_code, UHD_ERROR_BOOSTEXCEPT); +} + +BOOST_AUTO_TEST_CASE(test_std_exception){ + dummy_handle_t handle; + uhd_error error_code = throw_std_exception(&handle); + + BOOST_CHECK_EQUAL(error_code, UHD_ERROR_STDEXCEPT); + BOOST_CHECK_EQUAL(handle.last_error, "This is a std::runtime_error."); +} + +BOOST_AUTO_TEST_CASE(test_unknown_exception){ + dummy_handle_t handle; + uhd_error error_code = throw_unknown_exception(&handle); + + BOOST_CHECK_EQUAL(error_code, UHD_ERROR_UNKNOWN); + BOOST_CHECK_EQUAL(handle.last_error, "Unrecognized exception caught."); +} diff --git a/host/tests/ranges_c_test.c b/host/tests/ranges_c_test.c new file mode 100644 index 000000000..da9c86a48 --- /dev/null +++ b/host/tests/ranges_c_test.c @@ -0,0 +1,236 @@ +// +// 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 <stdio.h> +#include <stdlib.h> +#include <math.h> + +#define UHD_TEST_EXECUTE_OR_GOTO(label, ...) \ + if(__VA_ARGS__){ \ + fprintf(stderr, "Error occurred at %s:%d\n", __FILE__, (__LINE__-1)); \ + return_code = EXIT_FAILURE; \ + goto label; \ + } + +#define UHD_TEST_CHECK_CLOSE(lhs, rhs) (fabs(lhs-rhs) < 0.001) + +#define BUFFER_SIZE 1024 + +static UHD_INLINE int test_range_values( + const uhd_range_t *range, + double start_input, double stop_input, double step_input +){ + if(!UHD_TEST_CHECK_CLOSE(range->start, start_input)){ + fprintf(stderr, "%s:%d: Starts did not match: %f vs. %f\n", + __FILE__, __LINE__, + range->start, start_input); + return 1; + } + if(!UHD_TEST_CHECK_CLOSE(range->stop, stop_input)){ + fprintf(stderr, "%s:%d: Stops did not match: %f vs. %f\n", + __FILE__, __LINE__, + range->stop, stop_input); + return 1; + } + if(!UHD_TEST_CHECK_CLOSE(range->step, step_input)){ + fprintf(stderr, "%s:%d: Steps did not match: %f vs. %f\n", + __FILE__, __LINE__, + range->step, step_input); + return 1; + } + + return 0; +} + +static UHD_INLINE int test_meta_range_values( + uhd_meta_range_handle meta_range, + double start_input, double stop_input, double step_input, + double start_test, double stop_test, double step_test +){ + // Add range + uhd_range_t range; + range.start = start_input; + range.stop = stop_input; + range.step = step_input; + if(uhd_meta_range_push_back(meta_range, &range)){ + fprintf(stderr, "%s:%d: Failed to push back range.\n", + __FILE__, __LINE__); + return 1; + } + + // Test bounds + uhd_meta_range_start(meta_range, &range.start); + if(!UHD_TEST_CHECK_CLOSE(range.start, start_test)){ + fprintf(stderr, "%s:%d: Starts did not match: %f vs. %f\n", + __FILE__, __LINE__, + range.start, start_test); + return 1; + } + uhd_meta_range_stop(meta_range, &range.stop); + if(!UHD_TEST_CHECK_CLOSE(range.stop, stop_test)){ + fprintf(stderr, "%s:%d: Stops did not match: %f vs. %f\n", + __FILE__, __LINE__, + range.stop, stop_test); + return 1; + } + uhd_meta_range_step(meta_range, &range.step); + if(!UHD_TEST_CHECK_CLOSE(range.step, step_test)){ + fprintf(stderr, "%s:%d: Steps did not match: %f vs. %f\n", + __FILE__, __LINE__, + range.step, step_test); + return 1; + } + + return 0; +} + +static UHD_INLINE int test_meta_range_clip( + uhd_meta_range_handle meta_range, + double clip_value, double test_value, + bool clip_step +){ + double clip_result; + + uhd_meta_range_clip(meta_range, clip_value, clip_step, &clip_result); + if(!UHD_TEST_CHECK_CLOSE(test_value, clip_result)){ + fprintf(stderr, "%s:%d: Values did not match: %f vs. %f\n", + __FILE__, __LINE__, + test_value, clip_result); + return 1; + } + + return 0; +} + +int main(){ + + // Variables + int return_code; + uhd_range_t range; + uhd_meta_range_handle meta_range1, meta_range2; + char str_buffer[BUFFER_SIZE]; + size_t size; + + return_code = EXIT_SUCCESS; + + // Create meta range 1 + UHD_TEST_EXECUTE_OR_GOTO(end_of_test, + uhd_meta_range_make(&meta_range1) + ) + + // Test bounds + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_values(meta_range1, -1.0, +1.0, 0.1, + -1.0, +1.0, 0.1) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_values(meta_range1, 40.0, 60.0, 1.0, + -1.0, 60.0, 0.1) + ) + uhd_meta_range_at(meta_range1, 0, &range); + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_range_values(&range, -1.0, +1.0, 0.1) + ) + + // Check meta range size + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + uhd_meta_range_size(meta_range1, &size) + ) + if(size != 2){ + fprintf(stderr, "%s:%d: Invalid size: %lu vs. 2", + __FILE__, __LINE__, + size); + goto free_meta_range1; + } + + // Test clipping (with steps) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_clip(meta_range1, -30.0, -1.0, false) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_clip(meta_range1, 70.0, 60.0, false) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_clip(meta_range1, 20.0, 1.0, false) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_clip(meta_range1, 50.0, 50.0, false) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_clip(meta_range1, 50.9, 50.9, false) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + test_meta_range_clip(meta_range1, 50.9, 51.0, true) + ) + + // Create meta range 2 + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range1, + uhd_meta_range_make(&meta_range2) + ) + range.step = 0.0; + range.start = range.stop = 1.; + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + uhd_meta_range_push_back(meta_range2, &range) + ) + range.start = range.stop = 2.; + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + uhd_meta_range_push_back(meta_range2, &range) + ) + range.start = range.stop = 3.; + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + uhd_meta_range_push_back(meta_range2, &range) + ) + + // Test clipping (without steps) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + test_meta_range_clip(meta_range2, 2., 2., true) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + test_meta_range_clip(meta_range2, 0., 1., true) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + test_meta_range_clip(meta_range2, 1.2, 1., true) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + test_meta_range_clip(meta_range2, 3.1, 3., true) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_meta_range2, + test_meta_range_clip(meta_range2, 4., 3., true) + ) + + free_meta_range2: + if(return_code){ + uhd_meta_range_last_error(meta_range2, str_buffer, BUFFER_SIZE); + fprintf(stderr, "meta_range2 error: %s\n", str_buffer); + } + uhd_meta_range_free(&meta_range1); + + free_meta_range1: + if(return_code){ + uhd_meta_range_last_error(meta_range1, str_buffer, BUFFER_SIZE); + fprintf(stderr, "meta_range1 error: %s\n", str_buffer); + } + uhd_meta_range_free(&meta_range1); + + end_of_test: + if(!return_code){ + printf("\nNo errors detected.\n"); + } + return return_code; +} diff --git a/host/tests/sensors_c_test.c b/host/tests/sensors_c_test.c new file mode 100644 index 000000000..8babe905a --- /dev/null +++ b/host/tests/sensors_c_test.c @@ -0,0 +1,411 @@ +// +// 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#define UHD_TEST_EXECUTE_OR_GOTO(label, ...) \ + if(__VA_ARGS__){ \ + fprintf(stderr, "Error occurred at %s:%d\n", __FILE__, (__LINE__-1)); \ + return_code = EXIT_FAILURE; \ + goto label; \ + } + +#define UHD_TEST_CHECK_CLOSE(lhs, rhs) (fabs(lhs-rhs) < 0.001) + +#define BUFFER_SIZE 1024 + +int main(){ + + // Variables + int return_code; + uhd_sensor_value_handle boolean_sensor, integer_sensor, realnum_sensor, string_sensor; + uhd_sensor_value_data_type_t sensor_type; + bool bool_out; + int int_out; + double realnum_out; + char str_buffer[BUFFER_SIZE]; + + return_code = EXIT_SUCCESS; + + /* + * Test a sensor made from a boolean + */ + + // Create the sensor + UHD_TEST_EXECUTE_OR_GOTO(end_of_test, + uhd_sensor_value_make_from_bool( + &boolean_sensor, + "Bool sensor", false, + "True", "False" + ) + ) + + // Check the name + UHD_TEST_EXECUTE_OR_GOTO(free_boolean_sensor, + uhd_sensor_value_name( + boolean_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "Bool sensor")){ + fprintf(stderr, "%s:%d: Boolean sensor name invalid: \"%s\" vs. \"false\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_boolean_sensor; + } + + // Check the value + UHD_TEST_EXECUTE_OR_GOTO(free_boolean_sensor, + uhd_sensor_value_value( + boolean_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "false")){ + fprintf(stderr, "%s:%d: Boolean sensor value invalid: \"%s\" vs. \"false\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_boolean_sensor; + } + + // Check the unit + UHD_TEST_EXECUTE_OR_GOTO(free_boolean_sensor, + uhd_sensor_value_unit( + boolean_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "False")){ + fprintf(stderr, "%s:%d: Boolean sensor unit invalid: \"%s\" vs. \"False\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_boolean_sensor; + } + + // Check the type + UHD_TEST_EXECUTE_OR_GOTO(free_boolean_sensor, + uhd_sensor_value_data_type( + boolean_sensor, + &sensor_type + ) + ) + if(sensor_type != UHD_SENSOR_VALUE_BOOLEAN){ + fprintf(stderr, "%s:%d: Wrong sensor type detected: %d vs. %d\n", + __FILE__, __LINE__, + sensor_type, UHD_SENSOR_VALUE_BOOLEAN); + return_code = EXIT_FAILURE; + goto free_boolean_sensor; + } + + // Check the casted value + UHD_TEST_EXECUTE_OR_GOTO(free_boolean_sensor, + uhd_sensor_value_to_bool( + boolean_sensor, + &bool_out + ) + ) + if(bool_out){ + fprintf(stderr, "%s:%d: Boolean sensor value invalid: true vs. false\n", + __FILE__, __LINE__); + return_code = EXIT_FAILURE; + goto free_boolean_sensor; + } + + /* + * Test a sensor made from a integer + */ + + // Create the sensor + UHD_TEST_EXECUTE_OR_GOTO(free_boolean_sensor, + uhd_sensor_value_make_from_int( + &integer_sensor, + "Int sensor", 50, + "Int type", "%d" + ) + ) + + // Check the name + UHD_TEST_EXECUTE_OR_GOTO(free_integer_sensor, + uhd_sensor_value_name( + integer_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "Int sensor")){ + fprintf(stderr, "%s:%d: Integer sensor name invalid: \"%s\" vs. \"Int sensor\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_integer_sensor; + } + + // Check the value + UHD_TEST_EXECUTE_OR_GOTO(free_integer_sensor, + uhd_sensor_value_value( + integer_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "50")){ + fprintf(stderr, "%s:%d: Integer sensor value invalid: \"%s\" vs. \"50\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_integer_sensor; + } + + // Check the unit + UHD_TEST_EXECUTE_OR_GOTO(free_integer_sensor, + uhd_sensor_value_unit( + integer_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "Int type")){ + fprintf(stderr, "%s:%d: Integer sensor unit invalid: \"%s\" vs. \"Int type\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_integer_sensor; + } + + // Check the type + UHD_TEST_EXECUTE_OR_GOTO(free_integer_sensor, + uhd_sensor_value_data_type( + integer_sensor, + &sensor_type + ) + ) + if(sensor_type != UHD_SENSOR_VALUE_INTEGER){ + fprintf(stderr, "%s:%d: Wrong sensor type detected: %d vs. %d\n", + __FILE__, __LINE__, + sensor_type, UHD_SENSOR_VALUE_INTEGER); + return_code = EXIT_FAILURE; + goto free_integer_sensor; + } + + // Check the casted value + UHD_TEST_EXECUTE_OR_GOTO(free_integer_sensor, + uhd_sensor_value_to_int( + integer_sensor, + &int_out + ) + ) + if(int_out != 50){ + fprintf(stderr, "%s:%d: Integer sensor value invalid: %d vs. 50\n", + __FILE__, __LINE__, + int_out); + return_code = EXIT_FAILURE; + goto free_integer_sensor; + } + + /* + * Test a sensor made from a real number + */ + + // Create the sensor + UHD_TEST_EXECUTE_OR_GOTO(free_integer_sensor, + uhd_sensor_value_make_from_realnum( + &realnum_sensor, + "Realnum sensor", 50.0, + "Realnum type", "%d" + ) + ) + + // Check the name + UHD_TEST_EXECUTE_OR_GOTO(free_realnum_sensor, + uhd_sensor_value_name( + realnum_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "Realnum sensor")){ + fprintf(stderr, "%s:%d: Realnum sensor name invalid: \"%s\" vs. \"Realnum sensor\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_realnum_sensor; + } + + // Check the value + UHD_TEST_EXECUTE_OR_GOTO(free_realnum_sensor, + uhd_sensor_value_value( + realnum_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "50")){ + fprintf(stderr, "%s:%d: Realnum sensor value invalid: \"%s\" vs. \"50\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_realnum_sensor; + } + + // Check the unit + UHD_TEST_EXECUTE_OR_GOTO(free_realnum_sensor, + uhd_sensor_value_unit( + realnum_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "Realnum type")){ + fprintf(stderr, "%s:%d: Realnum sensor unit invalid: \"%s\" vs. \"Realnum type\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_realnum_sensor; + } + + // Check the type + UHD_TEST_EXECUTE_OR_GOTO(free_realnum_sensor, + uhd_sensor_value_data_type( + realnum_sensor, + &sensor_type + ) + ) + if(sensor_type != UHD_SENSOR_VALUE_REALNUM){ + fprintf(stderr, "%s:%d: Wrong sensor type detected: %d vs. %d\n", + __FILE__, __LINE__, + sensor_type, UHD_SENSOR_VALUE_REALNUM); + return_code = EXIT_FAILURE; + goto free_realnum_sensor; + } + + // Check the casted value + UHD_TEST_EXECUTE_OR_GOTO(free_realnum_sensor, + uhd_sensor_value_to_realnum( + realnum_sensor, + &realnum_out + ) + ) + if(realnum_out != 50.0){ + fprintf(stderr, "%s:%d: Realnum sensor value invalid: %2.1f vs. 50.0\n", + __FILE__, __LINE__, + realnum_out); + return_code = EXIT_FAILURE; + goto free_realnum_sensor; + } + + /* + * Test a sensor made from a string + */ + + // Create the sensor + UHD_TEST_EXECUTE_OR_GOTO(free_realnum_sensor, + uhd_sensor_value_make_from_string( + &string_sensor, + "String sensor", + "String value", + "String unit" + ) + ) + + // Check the name + UHD_TEST_EXECUTE_OR_GOTO(free_string_sensor, + uhd_sensor_value_name( + string_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "String sensor")){ + fprintf(stderr, "%s:%d: String sensor name invalid: \"%s\" vs. \"String sensor\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_string_sensor; + } + + // Check the value + UHD_TEST_EXECUTE_OR_GOTO(free_string_sensor, + uhd_sensor_value_value( + string_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "String value")){ + fprintf(stderr, "%s:%d: String sensor value invalid: \"%s\" vs. \"String value\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_string_sensor; + } + + // Check the unit + UHD_TEST_EXECUTE_OR_GOTO(free_string_sensor, + uhd_sensor_value_unit( + string_sensor, + str_buffer, BUFFER_SIZE + ) + ) + if(strcmp(str_buffer, "String unit")){ + fprintf(stderr, "%s:%d: String sensor unit invalid: \"%s\" vs. \"String unit\"\n", + __FILE__, __LINE__, str_buffer); + return_code = EXIT_FAILURE; + goto free_string_sensor; + } + + // Check the type + UHD_TEST_EXECUTE_OR_GOTO(free_string_sensor, + uhd_sensor_value_data_type( + string_sensor, + &sensor_type + ) + ) + if(sensor_type != UHD_SENSOR_VALUE_STRING){ + fprintf(stderr, "%s:%d: Wrong sensor type detected: %d vs. %d\n", + __FILE__, __LINE__, + sensor_type, UHD_SENSOR_VALUE_STRING); + return_code = EXIT_FAILURE; + goto free_string_sensor; + } + + /* + * Cleanup + */ + + free_string_sensor: + if(return_code){ + uhd_sensor_value_last_error(string_sensor, str_buffer, BUFFER_SIZE); + fprintf(stderr, "string_sensor error: %s\n", str_buffer); + } + uhd_sensor_value_free(&string_sensor); + + free_realnum_sensor: + if(return_code){ + uhd_sensor_value_last_error(realnum_sensor, str_buffer, BUFFER_SIZE); + fprintf(stderr, "realnum_sensor error: %s\n", str_buffer); + } + uhd_sensor_value_free(&realnum_sensor); + + free_integer_sensor: + if(return_code){ + uhd_sensor_value_last_error(integer_sensor, str_buffer, BUFFER_SIZE); + fprintf(stderr, "integer_sensor error: %s\n", str_buffer); + } + uhd_sensor_value_free(&integer_sensor); + + free_boolean_sensor: + if(return_code){ + uhd_sensor_value_last_error(boolean_sensor, str_buffer, BUFFER_SIZE); + fprintf(stderr, "boolean_sensor error: %s\n", str_buffer); + } + uhd_sensor_value_free(&boolean_sensor); + + end_of_test: + if(!return_code){ + printf("\nNo errors detected.\n"); + } + return return_code; +} diff --git a/host/tests/subdev_spec_c_test.c b/host/tests/subdev_spec_c_test.c new file mode 100644 index 000000000..7663ba357 --- /dev/null +++ b/host/tests/subdev_spec_c_test.c @@ -0,0 +1,130 @@ +// +// 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 <stdio.h> +#include <stdlib.h> + +#define UHD_TEST_EXECUTE_OR_GOTO(label, ...) \ + if(__VA_ARGS__){ \ + fprintf(stderr, "Error occurred at %s:%d\n", __FILE__, (__LINE__-1)); \ + return_code = EXIT_FAILURE; \ + goto label; \ + } + +#define BUFFER_SIZE 1024 + +int main(){ + + // Variables + int return_code; + uhd_subdev_spec_pair_t subdev_spec_pair1, subdev_spec_pair2; + uhd_subdev_spec_handle subdev_spec1, subdev_spec2; + size_t size1, size2, i; + bool pairs_equal; + char str_buffer[BUFFER_SIZE]; + + printf("Testing subdevice specification...\n"); + return_code = EXIT_SUCCESS; + + // Create subdev spec + UHD_TEST_EXECUTE_OR_GOTO(end_of_test, + uhd_subdev_spec_make(&subdev_spec1, "A:AB B:AB") + ) + + // Convert to and from args string + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec1, + uhd_subdev_spec_to_pp_string(subdev_spec1, str_buffer, BUFFER_SIZE) + ) + printf("Pretty Print:\n%s", str_buffer); + + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec1, + uhd_subdev_spec_to_string(subdev_spec1, str_buffer, BUFFER_SIZE) + ) + printf("Markup String: %s\n", str_buffer); + + // Make a second subdev spec from the first's markup string + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec2, + uhd_subdev_spec_make(&subdev_spec2, str_buffer) + ) + + // Make sure both subdev specs are equal + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec2, + uhd_subdev_spec_size(subdev_spec1, &size1) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec2, + uhd_subdev_spec_size(subdev_spec2, &size2) + ) + if(size1 != size2){ + printf("%s:%d: Sizes do not match. %lu vs. %lu\n", __FILE__, __LINE__, size1, size2); + return_code = EXIT_FAILURE; + goto free_subdev_spec2; + } + for(i = 0; i < size1; i++){ + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec_pair1, + uhd_subdev_spec_at(subdev_spec1, i, &subdev_spec_pair1) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec_pair2, + uhd_subdev_spec_at(subdev_spec2, i, &subdev_spec_pair2) + ) + UHD_TEST_EXECUTE_OR_GOTO(free_subdev_spec_pair2, + uhd_subdev_spec_pairs_equal(&subdev_spec_pair1, &subdev_spec_pair2, &pairs_equal) + ) + if(!pairs_equal){ + printf("%s:%d: Subdev spec pairs are not equal.\n" + " db_name: %s vs. %s\n" + " sd_name: %s vs. %s\n", + __FILE__, __LINE__, + subdev_spec_pair1.db_name, subdev_spec_pair2.db_name, + subdev_spec_pair1.sd_name, subdev_spec_pair2.sd_name + ); + return_code = EXIT_FAILURE; + goto free_subdev_spec_pair2; + } + uhd_subdev_spec_pair_free(&subdev_spec_pair1); + uhd_subdev_spec_pair_free(&subdev_spec_pair2); + } + + // Cleanup (and error report, if needed) + + free_subdev_spec_pair2: + uhd_subdev_spec_pair_free(&subdev_spec_pair2); + + free_subdev_spec_pair1: + uhd_subdev_spec_pair_free(&subdev_spec_pair1); + + free_subdev_spec2: + if(return_code){ + uhd_subdev_spec_last_error(subdev_spec2, str_buffer, BUFFER_SIZE); + fprintf(stderr, "subdev_spec2 error: %s\n", str_buffer); + } + uhd_subdev_spec_free(&subdev_spec2); + + free_subdev_spec1: + if(return_code){ + uhd_subdev_spec_last_error(subdev_spec1, str_buffer, BUFFER_SIZE); + fprintf(stderr, "subdev_spec1 error: %s\n", str_buffer); + } + uhd_subdev_spec_free(&subdev_spec1); + + end_of_test: + if(!return_code){ + printf("\nNo errors detected.\n"); + } + return return_code; +} |