diff options
Diffstat (limited to 'host')
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; +} | 
