diff options
111 files changed, 9245 insertions, 1080 deletions
diff --git a/firmware/e300/rev_b/bq24190.c b/firmware/e300/rev_b/bq24190.c index 029beacf6..d864ad0b3 100644 --- a/firmware/e300/rev_b/bq24190.c +++ b/firmware/e300/rev_b/bq24190.c @@ -1,8 +1,7 @@ /* * bq24190.c * - * Created: 11/12/2012 4:58:12 PM - * Author: Balint Seeber + * Copyright 2015 National Instruments Corp */ #ifdef CHARGER_TI diff --git a/firmware/e300/rev_b/bq24190.h b/firmware/e300/rev_b/bq24190.h index dc20ca796..bca415181 100644 --- a/firmware/e300/rev_b/bq24190.h +++ b/firmware/e300/rev_b/bq24190.h @@ -1,8 +1,7 @@ /* * bq24190.h * - * Created: 11/12/2012 4:58:23 PM - * Author: Balint Seeber + * Copyright 2015 National Instruments Corp */ diff --git a/firmware/e300/rev_b/error.h b/firmware/e300/rev_b/error.h index 82a8f0aca..4275fbf47 100644 --- a/firmware/e300/rev_b/error.h +++ b/firmware/e300/rev_b/error.h @@ -1,8 +1,7 @@ /* * error.h * - * Created: 4/09/2012 6:25:53 PM - * Author: Balint Seeber + * Copyright 2015 National Instruments Corp */ diff --git a/firmware/e300/rev_b/global.h b/firmware/e300/rev_b/global.h index 50fab581d..a142d6efc 100644 --- a/firmware/e300/rev_b/global.h +++ b/firmware/e300/rev_b/global.h @@ -1,8 +1,7 @@ /* * global.h * - * Created: 31/08/2012 8:47:14 PM - * Author: Balint Seeber + * Copyright 2015 National Instruments Corp */ #ifndef GLOBAL_H_ diff --git a/firmware/e300/rev_b/ltc4155.h b/firmware/e300/rev_b/ltc4155.h index 7e8e3751d..048e476cb 100644 --- a/firmware/e300/rev_b/ltc4155.h +++ b/firmware/e300/rev_b/ltc4155.h @@ -1,8 +1,7 @@ /* * ltc4155.h * - * Created: 17/08/2012 8:09:43 PM - * Author: Balint Seeber + * Copyright 2015 National Instruments Corp */ diff --git a/firmware/e300/rev_c/bq24190.c b/firmware/e300/rev_c/bq24190.c index 029beacf6..d864ad0b3 100644 --- a/firmware/e300/rev_c/bq24190.c +++ b/firmware/e300/rev_c/bq24190.c @@ -1,8 +1,7 @@ /* * bq24190.c * - * Created: 11/12/2012 4:58:12 PM - * Author: Balint Seeber + * Copyright 2015 National Instruments Corp */ #ifdef CHARGER_TI diff --git a/firmware/e300/rev_c/bq24190.h b/firmware/e300/rev_c/bq24190.h index dc20ca796..bca415181 100644 --- a/firmware/e300/rev_c/bq24190.h +++ b/firmware/e300/rev_c/bq24190.h @@ -1,8 +1,7 @@ /* * bq24190.h * - * Created: 11/12/2012 4:58:23 PM - * Author: Balint Seeber + * Copyright 2015 National Instruments Corp */ diff --git a/firmware/e300/rev_c/error.h b/firmware/e300/rev_c/error.h index 82a8f0aca..4275fbf47 100644 --- a/firmware/e300/rev_c/error.h +++ b/firmware/e300/rev_c/error.h @@ -1,8 +1,7 @@ /* * error.h * - * Created: 4/09/2012 6:25:53 PM - * Author: Balint Seeber + * Copyright 2015 National Instruments Corp */ diff --git a/firmware/e300/rev_c/global.h b/firmware/e300/rev_c/global.h index 50fab581d..a142d6efc 100644 --- a/firmware/e300/rev_c/global.h +++ b/firmware/e300/rev_c/global.h @@ -1,8 +1,7 @@ /* * global.h * - * Created: 31/08/2012 8:47:14 PM - * Author: Balint Seeber + * Copyright 2015 National Instruments Corp */ #ifndef GLOBAL_H_ diff --git a/firmware/e300/rev_c/ltc4155.h b/firmware/e300/rev_c/ltc4155.h index 7e8e3751d..048e476cb 100644 --- a/firmware/e300/rev_c/ltc4155.h +++ b/firmware/e300/rev_c/ltc4155.h @@ -1,8 +1,7 @@ /* * ltc4155.h * - * Created: 17/08/2012 8:09:43 PM - * Author: Balint Seeber + * Copyright 2015 National Instruments Corp */ 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/Modules/FindUSB1.cmake b/host/cmake/Modules/FindUSB1.cmake index 1e8e3ba03..7c4a8fb6b 100644 --- a/host/cmake/Modules/FindUSB1.cmake +++ b/host/cmake/Modules/FindUSB1.cmake @@ -8,7 +8,7 @@ PKG_CHECK_MODULES(PC_LIBUSB QUIET libusb-1.0) FIND_PATH(LIBUSB_INCLUDE_DIRS NAMES libusb.h - HINTS $ENV{LIBUSB_DIR}/include $ENV{LIBUSB_DIR}/include/libusb-1.0 + HINTS $ENV{LIBUSB_DIR}/include $ENV{LIBUSB_DIR}/include/libusb-1.0 ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDEDIR}/libusb-1.0 PATHS /usr/local/include/libusb-1.0 /usr/local/include /usr/include/libusb-1.0 /usr/include @@ -52,6 +52,11 @@ if(HAVE_LIBUSB_ERROR_NAME) list(APPEND LIBUSB_DEFINITIONS "HAVE_LIBUSB_ERROR_NAME=1") endif(HAVE_LIBUSB_ERROR_NAME) +CHECK_FUNCTION_EXISTS("libusb_strerror" HAVE_LIBUSB_STRERROR) +if(HAVE_LIBUSB_STRERROR) + list(APPEND LIBUSB_DEFINITIONS "HAVE_LIBUSB_STRERROR=1") +endif(HAVE_LIBUSB_STRERROR) + include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIRS) MARK_AS_ADVANCED(LIBUSB_INCLUDE_DIRS LIBUSB_LIBRARIES) 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..063bfd901 100644 --- a/host/docs/CMakeLists.txt +++ b/host/docs/CMakeLists.txt @@ -75,6 +75,8 @@ 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 h_files ${CMAKE_SOURCE_DIR}/include/*.h) + LIST(APPEND header_files ${h_files}) 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/docs/general.dox b/host/docs/general.dox index e4ffcfb6e..3e9dfc63a 100644 --- a/host/docs/general.dox +++ b/host/docs/general.dox @@ -34,6 +34,8 @@ support this functionality are: - SBX-120 - CBX - CBX-120 +- UBX +- UBX-160 \subsubsection general_tuning_rxchain Tuning the receive chain: @@ -78,6 +80,45 @@ second). usrp->issue_stream_command(...); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +\section general_sampleratenotes Sample rate notes + +Sample rates as delivered to the host computer for USRP devices are constrained to follow several important rules. + +It is important to understand that strictly-integer <b>decimation</b> and <b>interpolation</b> are used within USRP +hardware to meet the requested sample-rate requirements of the application at hand. That means that the desired +sample rate must meet the requirement that master-clock-rate/desired-sample-rate be an integer ratio. Further, it is +strongly desirable for that ratio to be <b>even</b>. + +There are further constraints on the desired sample rate, such that if the required decimation or interpolation exceeds 128, +then the resulting decimation <b>must</b> be evenly divisible by 2, and that if the required decimation exceeds 256, the +resulting decimation \b must be evenly divisible by 4. + +For USRP devices with fixed master clocks (notably: USRP1, USRP2, N2xx), there are fewer effective sample rates available than +on USRP hardware that provides some flexibility in selecting a master clock. Several USRP devices support flexible master +clock selection, allowing a broader range of sample rate selections by applications. See the individual devices' manual +pages for more details. + +In many cases using USRPs with flexible master-clock rates, it is possible to achieve lower sample rates without running into +the constraints of higher decimations, simply by choosing a lower master-clock rate to keep required decimation below 128. + +\subsection general_sampleratenotes_automatic Automatic master-clock selection + +In recent versions of UHD software (3.8.5 and newer), and on some devices (currently: B2xx and E3xx series), +the master clock rate is chosen automatically (unless specified by the user). +UHD will select a master clock rate that is consistent with the desired sample rate indicated by the application. + +\subsection general_sampleratenotes_nyquist Master clock rate and Nyquist + +In selecting a master clock rate on certain USRP hardware (X3xx and B1xx), it is important to select a rate that still provides +correct alias suppression by the analog hardware. For daughtercards with a 40 MHz analog bandwidth, this means the clock rate +must be <b>at least</b> 40 MHz, with better performance to be expected with a higher clock rate. For daughtercards +with 160 MHz bandwidth, it must be <b>at least</b> 160 MHz, again, better performance is to expected with a higher clock rate. + +For hardware with fixed master clock rates, of course, this isn't a consideration. + +For B2xx and E3xx hardware, the alias suppression is handled differently by the AD936x RFIC, and master clock rate +is significantly more flexible as a result. + \section general_ounotes Overflow/Underflow Notes <b>Note:</b> The following overflow/underflow notes do not apply to USRP1, diff --git a/host/docs/usrp_e3x0.dox b/host/docs/usrp_e3x0.dox index b175cc201..e6a574a51 100644 --- a/host/docs/usrp_e3x0.dox +++ b/host/docs/usrp_e3x0.dox @@ -1,4 +1,4 @@ -/*! \page page_usrp_e3x0 USRP-E3x0 Series +/*! \page page_usrp_e3x0 USRP-E3xx Series \tableofcontents @@ -35,7 +35,7 @@ There are two different methods to connect to the device - using the gigabit ethernet connector and a ssh client on your host computer For the first boot, booting with the serial cable connected to the device -is recommended, as it allows to review and modify the network configuration, +is recommended, as it allows to review and modify the \ref e3xx_network_configuration and allows to enter the bootloader in case of issues during the boot. @@ -134,6 +134,8 @@ which should return 'arm-oe-linux-gnueabi'. $ cmake -DCMAKE_TOOLCHAIN_FILE=<youruhdsrc>/host/cmake/Toolchains/oe-sdk_cross.cmake -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_E300=ON .. $ make +For instructions on building UHD on a PC to interact with your E-Series device, follow these instructions: \ref e3x0_uhd_build + \subsubsection e3x0_sdk_usage_gnuradio Building GNU Radio -# Obtain the gnuradio source code via git. @@ -248,8 +250,7 @@ You may need to change the USRP's IP address for several reasons: - to use multiple USRP-E Series devices with the same host computer - to set a known IP address into USRP (in case you forgot) - - +For examples refer to the \ref e3xx_network_configuration section. \section e3x0_hw Hardware Notes @@ -626,6 +627,51 @@ TRX-B | >= 2940.0 | 11 | 10 | XXX _Note: Although the transmit filters are low pass, the following table describes UHD's tuning range for selecting each filter path. The table also includes the required transmit enable states._ +\section e3xx_network_configuration Network configuration + +Your USRP E3XX Series device can be configured by editing the /etc/network/interfaces.<br> +The device defaults to *DHCP*, meaning it will query the local network's DHCP server for an address. + +\subsection e3xx_network_dhcp DHCP + +The default configuration should look similar to, instructing your device to query +local DHCP servers for an IP address, gateway, etc. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +auto eth0 +iface eth0 inet dhcp +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to change the hostname used to obtain an IP address via DHCP change + + /etc/hostname + +and edit: + + /etc/network/interfaces + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +auto eth0 +iface eth0 inet dhcp + hostname your-hostname +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +\subsection e3xx_network_static Static IP + +To configure a static IP address edit + + /etc/hostname + +to look like + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +auto eth0 +iface eth0 inet static + address your-ip + netmask your-netmask + gateway your-gateway +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + \section e3x0_misc Miscellaneous \subsection e3x0_misc_multirx Multiple RX channels @@ -655,10 +701,22 @@ they can be queried through the API. \subsection e3x0_network_mode Network Mode -Your USRP-E series device can be used in network mode for narrow band signal observation, evaluation and debugging purposes. +Your USRP-E series device can be used in network mode for narrow band signal observation, evaluation and debugging purposes. See the instructions below for how to use network mode. Please note that when compared with normal operation as a standalone device the usable bandwidth is limited and therefore Network Mode is not the recommended mode of operation. +\subsubsection e3x0_uhd_build Building UHD + +To work with your E-Series device in network mode, you will need to build UHD on your PC with extra CMake flags. Assuming you are in the host/build directory, +see below: + + $ cmake -DENABLE_E300=ON -DE300_FORCE_NETWORK=ON .. + $ make + +Once UHD is installed on your device, it will be able to interact with an E-Series device with network mode active (see below). + +\subsubsection e3x0_activating_network Activating Network Mode on the Device + In order to use the device in network mode it is necessary to start the *usrp_e3x0_network_mode* executable on the device. In order to start the executable please log into your device either via SSH or serial console(see \ref e3x0_first_boot) and type diff --git a/host/docs/usrp_x3x0.dox b/host/docs/usrp_x3x0.dox index 7183efc04..bf2323b71 100644 --- a/host/docs/usrp_x3x0.dox +++ b/host/docs/usrp_x3x0.dox @@ -609,6 +609,30 @@ The +3.3V is for ESD clamping purposes only and not designed to deliver high cur Please see the \ref page_gpio_api for information on configuring and using the GPIO bus. +\subsection x3x0_hw_on_board_leds On-Board LEDs + +|LED | | Description | +|-------|---------------|-------------------------------| +|DS1 |1.2V |power | +|DS2 |TXRX1 |Red: TX, Green: RX | +|DS3 |RX1 |Green: RX | +|DS4 |REF |reference lock | +|DS5 |PPS |flashes on edge | +|DS6 |GPS |GPS lock | +|DS7 |SFP0 |link | +|DS8 |SFP0 |link activity | +|DS10 |TXRX2 |Red: TX Green: RX | +|DS11 |RX2 |Green: RX | +|DS12 |6V |daughterboard power | +|DS13 |3.8V |power | +|DS14 |3.3V |management power | +|DS15 |3.3V |auxiliary management power | +|DS16 |1.8V |FPGA power | +|DS16 |3.3V |FPGA power | +|DS19 |SFP1 |link | +|DS20 |SFP1 |link active | +|DS21 |LINK |link activity | + \subsection x3x0_hw_chipscope Debugging custom FPGA designs with Xilinx Chipscope Xilinx chipscope allows for debugging custom FPGA designs similar to a logic analyzer. diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 92947d86c..43e0db9c0 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2014 Ettus Research LLC +# Copyright 2010-2015 Ettus Research LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -61,3 +61,48 @@ IF(CURSES_FOUND) TARGET_LINK_LIBRARIES(rx_ascii_art_dft uhd ${CURSES_LIBRARIES} ${Boost_LIBRARIES}) UHD_INSTALL(TARGETS rx_ascii_art_dft RUNTIME DESTINATION ${PKG_LIB_DIR}/examples COMPONENT examples) ENDIF(CURSES_FOUND) + +######################################################################## +# Examples using C API +######################################################################## +IF(ENABLE_C_API) + # + # Check if this particular C99 feature is available with this compiler + # + INCLUDE(CheckCSourceCompiles) + CHECK_C_SOURCE_COMPILES(" + typedef struct { + int bar; + int baz; + } foo; + + int main() + { + foo wat = { + .bar = 1, + .baz = 2 + }; + + return 0; + } + " HAVE_C99_STRUCTDECL) + + IF(HAVE_C99_STRUCTDECL) + ADD_SUBDIRECTORY(getopt) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/getopt) + + SET(C_API_EXAMPLES + rx_samples_c + tx_samples_c + ) + + FOREACH(example ${C_API_EXAMPLES}) + ADD_EXECUTABLE(${example} ${example}.c) + TARGET_LINK_LIBRARIES(${example} uhd getopt) + IF(UNIX) + TARGET_LINK_LIBRARIES(${example} m) + ENDIF(UNIX) + UHD_INSTALL(TARGETS ${example} RUNTIME DESTINATION ${PKG_LIB_DIR}/examples COMPONENT examples) + ENDFOREACH(example ${C_API_EXAMPLES}) + ENDIF(HAVE_C99_STRUCTDECL) +ENDIF(ENABLE_C_API) diff --git a/host/examples/getopt/CMakeLists.txt b/host/examples/getopt/CMakeLists.txt new file mode 100644 index 000000000..46ad1460c --- /dev/null +++ b/host/examples/getopt/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# Copyright 2015 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +######################################################################## +# getopt library for C examples since MSVC does not include it +######################################################################## +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIRECTORY}) +ADD_LIBRARY(getopt STATIC + ${CMAKE_CURRENT_SOURCE_DIR}/getopt.c +) diff --git a/host/examples/getopt/getopt.c b/host/examples/getopt/getopt.c new file mode 100644 index 000000000..e571ff9c8 --- /dev/null +++ b/host/examples/getopt/getopt.c @@ -0,0 +1,70 @@ +/* + * This file was copied from the following newsgroup posting: + * + * Newsgroups: mod.std.unix + * Subject: public domain AT&T getopt source + * Date: 3 Nov 85 19:34:15 GMT + * + * Here's something you've all been waiting for: the AT&T public domain + * source for getopt(3). It is the code which was given out at the 1985 + * UNIFORUM conference in Dallas. I obtained it by electronic mail + * directly from AT&T. The people there assure me that it is indeed + * in the public domain. + */ + +#include <stdio.h> +#include <string.h> + +#define ERR(szz,czz) if(opterr){fprintf(stderr,"%s%s%c\n",argv[0],szz,czz);} + +int opterr = 1; +int optind = 1; +int optopt; +char *optarg; + +int +getopt(int argc, char **argv, char *opts) +{ + static int sp; + int c; + char *cp; + + sp = 1; + + if (sp == 1) { + if (optind >= argc || + argv[optind][0] != '-' || argv[optind][1] == '\0') + return (EOF); + else if (strcmp(argv[optind], "--") == 0) { + optind++; + return (EOF); + } + } + optopt = c = argv[optind][sp]; + if (c == ':' || (cp = strchr(opts, c)) == NULL) { + ERR(": illegal option -- ", c); + if (argv[optind][++sp] == '\0') { + optind++; + sp = 1; + } + return ('?'); + } + if (*++cp == ':') { + if (argv[optind][sp + 1] != '\0') + optarg = &argv[optind++][sp + 1]; + else if (++optind >= argc) { + ERR(": option requires an argument -- ", c); + sp = 1; + return ('?'); + } else + optarg = argv[optind++]; + sp = 1; + } else { + if (argv[optind][++sp] == '\0') { + sp = 1; + optind++; + } + optarg = NULL; + } + return (c); +} diff --git a/host/examples/getopt/getopt.h b/host/examples/getopt/getopt.h new file mode 100644 index 000000000..ada96ecf0 --- /dev/null +++ b/host/examples/getopt/getopt.h @@ -0,0 +1,19 @@ +/* + * This header is for a function released into the public domain + * by AT&T in 1985. See the newsgroup posting: + * + * Newsgroups: mod.std.unix + * Subject: public domain AT&T getopt source + * Date: 3 Nov 85 19:34:15 GMT + */ +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +extern int optarr; +extern int optind; +extern int optopt; +extern char* optarg; + +int getopt(int argc, char **argv, char *opts); + +#endif /* _GETOPT_H_ */ diff --git a/host/examples/rx_samples_c.c b/host/examples/rx_samples_c.c new file mode 100644 index 000000000..b5882b79b --- /dev/null +++ b/host/examples/rx_samples_c.c @@ -0,0 +1,291 @@ +/* + * Copyright 2015 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <uhd.h> + +#include "getopt.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define EXECUTE_OR_GOTO(label, ...) \ + if(__VA_ARGS__){ \ + return_code = EXIT_FAILURE; \ + goto label; \ + } + +void print_help(void){ + fprintf(stderr, "rx_samples_c - A simple RX example using UHD's C API\n\n" + + "Options:\n" + " -a (device args)\n" + " -f (frequency in Hz)\n" + " -r (sample rate in Hz)\n" + " -g (gain)\n" + " -n (number of samples to receive)\n" + " -o (output filename, default = \"out.dat\")\n" + " -v (enable verbose prints)\n" + " -h (print this help message)\n"); +}; + +int main(int argc, char* argv[]) +{ + if(uhd_set_thread_priority(uhd_default_thread_priority, true)){ + fprintf(stderr, "Unable to set thread priority. Continuing anyway.\n"); + } + + int option = 0; + double freq = 500e6; + double rate = 1e6; + double gain = 5.0; + char* device_args = ""; + size_t channel = 0; + char* filename = "out.dat"; + size_t n_samples = 1000000; + bool verbose = false; + int return_code = EXIT_SUCCESS; + bool custom_filename = false; + char error_string[512]; + + // Process options + while((option = getopt(argc, argv, "a:f:r:g:n:o:vh")) != -1){ + switch(option){ + case 'a': + device_args = strdup(optarg); + break; + + case 'f': + freq = atof(optarg); + break; + + case 'r': + rate = atof(optarg); + break; + + case 'g': + gain = atof(optarg); + break; + + case 'n': + n_samples = atoi(optarg); + break; + + case 'o': + filename = strdup(optarg); + custom_filename = true; + break; + + case 'v': + verbose = true; + break; + + case 'h': + print_help(); + goto free_option_strings; + + default: + print_help(); + return_code = EXIT_FAILURE; + goto free_option_strings; + } + } + + // Create USRP + uhd_usrp_handle usrp; + fprintf(stderr, "Creating USRP with args \"%s\"...\n", device_args); + EXECUTE_OR_GOTO(free_option_strings, + uhd_usrp_make(&usrp, device_args) + ) + + // Create RX streamer + uhd_rx_streamer_handle rx_streamer; + EXECUTE_OR_GOTO(free_usrp, + uhd_rx_streamer_make(&rx_streamer) + ) + + // Create RX metadata + uhd_rx_metadata_handle md; + EXECUTE_OR_GOTO(free_rx_streamer, + uhd_rx_metadata_make(&md) + ) + + // Create other necessary structs + uhd_tune_request_t tune_request = { + .target_freq = freq, + .rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO, + .dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO, + }; + uhd_tune_result_t tune_result; + + uhd_stream_args_t stream_args = { + .cpu_format = "fc32", + .otw_format = "sc16", + .args = "", + .channel_list = &channel, + .n_channels = 1 + }; + + uhd_stream_cmd_t stream_cmd = { + .stream_mode = UHD_STREAM_MODE_NUM_SAMPS_AND_DONE, + .num_samps = n_samples, + .stream_now = true + }; + + size_t samps_per_buff; + float *buff = NULL; + void **buffs_ptr = NULL; + FILE *fp = NULL; + size_t num_acc_samps = 0; + + // Set rate + fprintf(stderr, "Setting RX Rate: %f...\n", rate); + EXECUTE_OR_GOTO(free_rx_metadata, + uhd_usrp_set_rx_rate(usrp, rate, channel) + ) + + // See what rate actually is + EXECUTE_OR_GOTO(free_rx_metadata, + uhd_usrp_get_rx_rate(usrp, channel, &rate) + ) + fprintf(stderr, "Actual RX Rate: %f...\n", rate); + + // Set gain + fprintf(stderr, "Setting RX Gain: %f dB...\n", gain); + EXECUTE_OR_GOTO(free_rx_metadata, + uhd_usrp_set_rx_gain(usrp, gain, channel, "") + ) + + // See what gain actually is + EXECUTE_OR_GOTO(free_rx_metadata, + uhd_usrp_get_rx_gain(usrp, channel, "", &gain) + ) + fprintf(stderr, "Actual RX Gain: %f...\n", gain); + + // Set frequency + fprintf(stderr, "Setting RX frequency: %f MHz...\n", freq/1e6); + EXECUTE_OR_GOTO(free_rx_metadata, + uhd_usrp_set_rx_freq(usrp, &tune_request, channel, &tune_result) + ) + + // See what frequency actually is + EXECUTE_OR_GOTO(free_rx_metadata, + uhd_usrp_get_rx_freq(usrp, channel, &freq) + ) + fprintf(stderr, "Actual RX frequency: %f MHz...\n", freq / 1e6); + + // Set up streamer + stream_args.channel_list = &channel; + EXECUTE_OR_GOTO(free_rx_streamer, + uhd_usrp_get_rx_stream(usrp, &stream_args, rx_streamer) + ) + + // Set up buffer + EXECUTE_OR_GOTO(free_rx_streamer, + uhd_rx_streamer_max_num_samps(rx_streamer, &samps_per_buff) + ) + fprintf(stderr, "Buffer size in samples: %zu\n", samps_per_buff); + buff = malloc(samps_per_buff * 2 * sizeof(float)); + buffs_ptr = (void**)&buff; + + // Issue stream command + fprintf(stderr, "Issuing stream command.\n"); + EXECUTE_OR_GOTO(free_buffer, + uhd_rx_streamer_issue_stream_cmd(rx_streamer, &stream_cmd) + ) + + // Set up file output + fp = fopen(filename, "wb"); + + // Actual streaming + while (num_acc_samps < n_samples) { + size_t num_rx_samps = 0; + EXECUTE_OR_GOTO(close_file, + uhd_rx_streamer_recv(rx_streamer, buffs_ptr, samps_per_buff, md, 3.0, false, &num_rx_samps) + ) + + uhd_rx_metadata_error_code_t error_code; + EXECUTE_OR_GOTO(close_file, + uhd_rx_metadata_error_code(md, &error_code) + ) + if(return_code != UHD_RX_METADATA_ERROR_CODE_NONE){ + fprintf(stderr, "Error code 0x%x was returned during streaming. Aborting.\n", return_code); + goto close_file; + } + + // Handle data + fwrite(buff, sizeof(float) * 2, num_rx_samps, fp); + if (verbose) { + time_t full_secs; + double frac_secs; + uhd_rx_metadata_time_spec(md, &full_secs, &frac_secs); + fprintf(stderr, "Received packet: %zu samples, %zu full secs, %f frac secs\n", + num_rx_samps, + full_secs, + frac_secs); + } + + num_acc_samps += num_rx_samps; + } + + // Cleanup + close_file: + fclose(fp); + + free_buffer: + if(buff){ + if(verbose){ + fprintf(stderr, "Freeing buffer.\n"); + } + free(buff); + } + buff = NULL; + buffs_ptr = NULL; + + free_rx_streamer: + if(verbose){ + fprintf(stderr, "Cleaning up RX streamer.\n"); + } + uhd_rx_streamer_free(&rx_streamer); + + free_rx_metadata: + if(verbose){ + fprintf(stderr, "Cleaning up RX metadata.\n"); + } + uhd_rx_metadata_free(&md); + + free_usrp: + if(verbose){ + fprintf(stderr, "Cleaning up USRP.\n"); + } + if(return_code != EXIT_SUCCESS && usrp != NULL){ + uhd_usrp_last_error(usrp, error_string, 512); + fprintf(stderr, "USRP reported the following error: %s\n", error_string); + } + uhd_usrp_free(&usrp); + + free_option_strings: + if(strcmp(device_args,"")){ + free(device_args); + } + if(custom_filename){ + free(filename); + } + + fprintf(stderr, (return_code ? "Failure\n" : "Success\n")); + return return_code; +} diff --git a/host/examples/tx_samples_c.c b/host/examples/tx_samples_c.c new file mode 100644 index 000000000..3035297fd --- /dev/null +++ b/host/examples/tx_samples_c.c @@ -0,0 +1,241 @@ +/* + * Copyright 2015 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <uhd.h> + +#include "getopt.h" + +#include <math.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define EXECUTE_OR_GOTO(label, ...) \ + if(__VA_ARGS__){ \ + return_code = EXIT_FAILURE; \ + goto label; \ + } + +void print_help(void){ + fprintf(stderr, "tx_samples_c - A simple TX example using UHD's C API\n\n" + + "Options:\n" + " -a (device args)\n" + " -f (frequency in Hz)\n" + " -r (sample rate in Hz)\n" + " -g (gain)\n" + " -v (enable verbose prints)\n" + " -h (print this help message)\n"); +} + +bool stop_signal_called = false; + +void sigint_handler(int code){ + (void)code; + stop_signal_called = true; +} + +int main(int argc, char* argv[]){ + int option = 0; + double freq = 2e9; + double rate = 1e6; + double gain = 0; + char* device_args = ""; + size_t channel = 0; + bool verbose = false; + int return_code = EXIT_SUCCESS; + char error_string[512]; + + // Process options + while((option = getopt(argc, argv, "a:f:r:g:vh")) != -1){ + switch(option){ + case 'a': + device_args = strdup(optarg); + break; + + case 'f': + freq = atof(optarg); + break; + + case 'r': + rate = atof(optarg); + break; + + case 'g': + gain = atof(optarg); + break; + + case 'v': + verbose = true; + break; + + case 'h': + print_help(); + goto free_option_strings; + + default: + print_help(); + return_code = EXIT_FAILURE; + goto free_option_strings; + } + } + + if(uhd_set_thread_priority(uhd_default_thread_priority, true)){ + fprintf(stderr, "Unable to set thread priority. Continuing anyway.\n"); + } + + // Create USRP + uhd_usrp_handle usrp; + fprintf(stderr, "Creating USRP with args \"%s\"...\n", device_args); + EXECUTE_OR_GOTO(free_option_strings, + uhd_usrp_make(&usrp, device_args) + ) + + // Create TX streamer + uhd_tx_streamer_handle tx_streamer; + EXECUTE_OR_GOTO(free_usrp, + uhd_tx_streamer_make(&tx_streamer) + ) + + // Create TX metadata + uhd_tx_metadata_handle md; + EXECUTE_OR_GOTO(free_tx_streamer, + uhd_tx_metadata_make(&md, false, 0.0, 0.1, true, false) + ) + + // Create other necessary structs + uhd_tune_request_t tune_request = { + .target_freq = freq, + .rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO, + .dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO + }; + uhd_tune_result_t tune_result; + + uhd_stream_args_t stream_args = { + .cpu_format = "fc32", + .otw_format = "sc16", + .args = "", + .channel_list = &channel, + .n_channels = 1 + }; + + size_t samps_per_buff; + float* buff = NULL; + const void** buffs_ptr = NULL; + + // Set rate + fprintf(stderr, "Setting TX Rate: %f...\n", rate); + EXECUTE_OR_GOTO(free_tx_metadata, + uhd_usrp_set_tx_rate(usrp, rate, channel) + ) + + // See what rate actually is + EXECUTE_OR_GOTO(free_tx_metadata, + uhd_usrp_get_tx_rate(usrp, channel, &rate) + ) + fprintf(stderr, "Actual TX Rate: %f...\n\n", rate); + + // Set gain + fprintf(stderr, "Setting TX Gain: %f db...\n", gain); + EXECUTE_OR_GOTO(free_tx_metadata, + uhd_usrp_set_tx_gain(usrp, gain, 0, "") + ) + + // See what gain actually is + EXECUTE_OR_GOTO(free_tx_metadata, + uhd_usrp_get_tx_gain(usrp, channel, "", &gain) + ) + fprintf(stderr, "Actual TX Gain: %f...\n", gain); + + // Set frequency + fprintf(stderr, "Setting TX frequency: %f MHz...\n", freq / 1e6); + EXECUTE_OR_GOTO(free_tx_metadata, + uhd_usrp_set_tx_freq(usrp, &tune_request, channel, &tune_result) + ) + + // See what frequency actually is + EXECUTE_OR_GOTO(free_tx_metadata, + uhd_usrp_get_tx_freq(usrp, channel, &freq) + ) + fprintf(stderr, "Actual TX frequency: %f MHz...\n", freq / 1e6); + + // Set up streamer + stream_args.channel_list = &channel; + EXECUTE_OR_GOTO(free_tx_streamer, + uhd_usrp_get_tx_stream(usrp, &stream_args, tx_streamer) + ) + + // Set up buffer + EXECUTE_OR_GOTO(free_tx_streamer, + uhd_tx_streamer_max_num_samps(tx_streamer, &samps_per_buff) + ) + fprintf(stderr, "Buffer size in samples: %zu\n", samps_per_buff); + buff = malloc(samps_per_buff * 2 * sizeof(float)); + buffs_ptr = (const void**)&buff; + size_t i = 0; + for(i = 0; i < (samps_per_buff*2); i+=2){ + buff[i] = 0.1; + buff[i+1] = 0; + } + + // Ctrl+C will exit loop + signal(SIGINT, &sigint_handler); + fprintf(stderr, "Press Ctrl+C to stop streaming...\n"); + + // Actual streaming + size_t num_samps_sent = 0; + while(!stop_signal_called){ + EXECUTE_OR_GOTO(free_tx_streamer, + uhd_tx_streamer_send(tx_streamer, buffs_ptr, samps_per_buff, md, 0.1, &num_samps_sent) + ) + if(verbose){ + fprintf(stderr, "Sent %zu samples\n", num_samps_sent); + } + } + + free_tx_streamer: + if(verbose){ + fprintf(stderr, "Cleaning up TX streamer.\n"); + } + uhd_tx_streamer_free(&tx_streamer); + + free_tx_metadata: + if(verbose){ + fprintf(stderr, "Cleaning up TX metadata.\n"); + } + uhd_tx_metadata_free(&md); + + free_usrp: + if(verbose){ + fprintf(stderr, "Cleaning up USRP.\n"); + } + if(return_code != EXIT_SUCCESS && usrp != NULL){ + uhd_usrp_last_error(usrp, error_string, 512); + fprintf(stderr, "USRP reported the following error: %s\n", error_string); + } + uhd_usrp_free(&usrp); + + free_option_strings: + if(strcmp(device_args,"")){ + free(device_args); + } + + fprintf(stderr, (return_code ? "Failure\n" : "Success\n")); + + return return_code; +} 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..1f8f9e896 --- /dev/null +++ b/host/include/uhd.h @@ -0,0 +1,41 @@ +/* + * 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/device_addrs.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/exception.hpp b/host/include/uhd/exception.hpp index 69e902fd5..a21106166 100644 --- a/host/include/uhd/exception.hpp +++ b/host/include/uhd/exception.hpp @@ -98,6 +98,14 @@ namespace uhd{ virtual void dynamic_throw(void) const; }; + struct UHD_API usb_error : runtime_error{ + int _code; + usb_error(int code, const std::string &what); + virtual unsigned code(void) const { return _code; }; + virtual usb_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; + }; + struct UHD_API not_implemented_error : runtime_error{ not_implemented_error(const std::string &what); virtual unsigned code(void) const; diff --git a/host/include/uhd/image_loader.hpp b/host/include/uhd/image_loader.hpp index 8124e7dea..5963c862f 100644 --- a/host/include/uhd/image_loader.hpp +++ b/host/include/uhd/image_loader.hpp @@ -46,8 +46,9 @@ public: * * This function must return true upon the end of a successful image load * or false if no applicable device was found. It may only throw a runtime - * error under one of two conditions: + * error under one of three conditions: * + * * The function finds multiple devices that fit the user's arguments. * * The function has already engaged with a specific device and * something goes wrong. * * The user gives arguments that unambiguously lead to a specific diff --git a/host/include/uhd/transport/nirio/nirio_fifo.h b/host/include/uhd/transport/nirio/nirio_fifo.h index 5a2e29631..a0cd7149f 100644 --- a/host/include/uhd/transport/nirio/nirio_fifo.h +++ b/host/include/uhd/transport/nirio/nirio_fifo.h @@ -1,5 +1,5 @@ // -// Copyright 2013-2014 Ettus Research LLC +// Copyright 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 @@ -114,7 +114,7 @@ private: //Members static const uint32_t FIFO_LOCK_TIMEOUT_IN_MS = 5000; }; -#include "nirio_fifo.ipp" +#include <uhd/transport/nirio/nirio_fifo.ipp> }} diff --git a/host/include/uhd/transport/nirio/nirio_quirks.h b/host/include/uhd/transport/nirio/nirio_quirks.h index 8e58f80f1..45ef40394 100644 --- a/host/include/uhd/transport/nirio/nirio_quirks.h +++ b/host/include/uhd/transport/nirio/nirio_quirks.h @@ -35,8 +35,8 @@ public: nirio_quirks() : _tx_stream_count(0) { } - UHD_INLINE void register_tx_streams(const uint32_t tx_stream_indices[]) { - for (size_t i = 0; i < sizeof(tx_stream_indices)/sizeof(*tx_stream_indices); i++) { + UHD_INLINE void register_tx_streams(const uint32_t tx_stream_indices[], size_t size) { + for (size_t i = 0; i < size; i++) { _tx_stream_fifo_indices.insert(tx_stream_indices[i]); } } diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index 2a25df35f..07a752806 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -42,3 +42,17 @@ UHD_INSTALL(FILES DESTINATION ${INCLUDE_DIR}/uhd/types COMPONENT headers ) + +IF(ENABLE_C_API) + UHD_INSTALL(FILES + device_addrs.h + 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/device_addrs.h b/host/include/uhd/types/device_addrs.h new file mode 100644 index 000000000..3acc7f179 --- /dev/null +++ b/host/include/uhd/types/device_addrs.h @@ -0,0 +1,87 @@ +/* + * 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_DEVICE_ADDRS_H +#define INCLUDED_UHD_TYPES_DEVICE_ADDRS_H + +#include <uhd/config.h> +#include <uhd/error.h> + +#include <stdlib.h> + +#ifdef __cplusplus +#include <uhd/types/device_addr.hpp> +#include <string> + +struct uhd_device_addrs_t { + uhd::device_addrs_t device_addrs_cpp; + std::string last_error; +}; + +extern "C" { +#else +struct uhd_device_addrs_t; +#endif + +//! C-level interface for interacting with a list of device addresses +/*! + * See uhd::device_addrs_t for more information. + */ +typedef struct uhd_device_addrs_t* uhd_device_addrs_handle; + +//! Instantiate a device_addrs handle. +UHD_API uhd_error uhd_device_addrs_make( + uhd_device_addrs_handle *h +); + +//! Safely destroy a device_addrs handle. +UHD_API uhd_error uhd_device_addrs_free( + uhd_device_addrs_handle *h +); + +//! Add a device address to the list in string form +UHD_API uhd_error uhd_device_addrs_push_back( + uhd_device_addrs_handle h, + const char* value +); + +//! Get the device information (in string form) at the given index +UHD_API uhd_error uhd_device_addrs_at( + uhd_device_addrs_handle h, + size_t index, + char* value_out, + size_t strbuffer_len +); + +//! Get the number of device addresses in this list +UHD_API uhd_error uhd_device_addrs_size( + uhd_device_addrs_handle h, + size_t *size_out +); + +//! Get the last error reported by the underlying object +UHD_API uhd_error uhd_device_addrs_last_error( + uhd_device_addrs_handle h, + char* error_out, + size_t strbuffer_len +); + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_UHD_TYPES_DEVICE_ADDRS_H */ 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..99a06b6e1 --- /dev/null +++ b/host/include/uhd/usrp/usrp.h @@ -0,0 +1,1253 @@ +// +// 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/device_addrs.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 + +//! Find all connected USRP devices. +/*! + * See uhd::device::find() for more details. + */ +UHD_API uhd_error uhd_usrp_find( + uhd_device_addrs_handle h, + const char* args, + size_t *num_found +); + +//! 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..4a9eb871e --- /dev/null +++ b/host/include/uhd/usrp_clock/usrp_clock.h @@ -0,0 +1,128 @@ +// +// 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/device_addrs.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 + +//! Find all connected clock devices. +/*! + * See uhd::device::find() for more details. + */ +UHD_API uhd_error uhd_usrp_clock_find( + uhd_device_addrs_handle h, + const char* args, + size_t *num_found +); + +//! Create a 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 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 05f6892d2..af6d3ee47 100644 --- a/host/include/uhd/utils/CMakeLists.txt +++ b/host/include/uhd/utils/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2012 Ettus Research LLC +# 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 @@ -24,6 +24,8 @@ UHD_INSTALL(FILES byteswap.ipp cast.hpp csv.hpp + fp_compare_delta.ipp + fp_compare_epsilon.ipp gain_group.hpp log.hpp math.hpp @@ -40,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/math.hpp b/host/include/uhd/utils/math.hpp index 46a1cf7e4..ef7bfb6b7 100644 --- a/host/include/uhd/utils/math.hpp +++ b/host/include/uhd/utils/math.hpp @@ -1,5 +1,5 @@ // -// Copyright 2014 Ettus Research LLC +// Copyright 2014-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 @@ -250,7 +250,7 @@ namespace fp_compare { } // namespace math } // namespace uhd -#include "fp_compare_epsilon.ipp" -#include "fp_compare_delta.ipp" +#include <uhd/utils/fp_compare_epsilon.ipp> +#include <uhd/utils/fp_compare_delta.ipp> #endif /* INCLUDED_UHD_UTILS_MATH_HPP */ 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/convert/convert_common.hpp b/host/lib/convert/convert_common.hpp index 65fdcbea2..6e73e9436 100644 --- a/host/lib/convert/convert_common.hpp +++ b/host/lib/convert/convert_common.hpp @@ -86,6 +86,7 @@ typedef float f32_t; typedef boost::int32_t s32_t; typedef boost::int16_t s16_t; typedef boost::int8_t s8_t; +typedef boost::uint8_t u8_t; typedef boost::uint32_t item32_t; diff --git a/host/lib/convert/convert_impl.cpp b/host/lib/convert/convert_impl.cpp index fd6c8497e..d90bb9c94 100644 --- a/host/lib/convert/convert_impl.cpp +++ b/host/lib/convert/convert_impl.cpp @@ -172,6 +172,7 @@ UHD_STATIC_BLOCK(convert_register_item_sizes){ convert::register_bytes_per_item("s32", sizeof(boost::int32_t)); convert::register_bytes_per_item("s16", sizeof(boost::int16_t)); convert::register_bytes_per_item("s8", sizeof(boost::int8_t)); + convert::register_bytes_per_item("u8", sizeof(boost::uint8_t)); //register VITA types convert::register_bytes_per_item("item32", sizeof(boost::int32_t)); diff --git a/host/lib/convert/gen_convert_general.py b/host/lib/convert/gen_convert_general.py index 8090f14bd..4f9eeb747 100644 --- a/host/lib/convert/gen_convert_general.py +++ b/host/lib/convert/gen_convert_general.py @@ -28,26 +28,79 @@ TMPL_HEADER = """ #include <uhd/utils/byteswap.hpp> using namespace uhd::convert; + + +// item32 -> item32: Just a memcpy. No scaling possible. +DECLARE_CONVERTER(item32, 1, item32, 1, PRIORITY_GENERAL) { + const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); + item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); + + memcpy(output, input, nsamps * sizeof(item32_t)); +} """ TMPL_CONV_GEN2_ITEM32 = """ -DECLARE_CONVERTER(item32, 1, sc16_item32_${end}, 1, PRIORITY_GENERAL){ +DECLARE_CONVERTER(item32, 1, sc16_item32_{end}, 1, PRIORITY_GENERAL) {{ const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); - for (size_t i = 0; i < nsamps; i++){ - output[i] = ${to_wire}(input[i]); - } -} + for (size_t i = 0; i < nsamps; i++) {{ + output[i] = {to_wire}(input[i]); + }} +}} -DECLARE_CONVERTER(sc16_item32_${end}, 1, item32, 1, PRIORITY_GENERAL){ +DECLARE_CONVERTER(sc16_item32_{end}, 1, item32, 1, PRIORITY_GENERAL) {{ const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); - for (size_t i = 0; i < nsamps; i++){ - output[i] = ${to_host}(input[i]); - } -} + for (size_t i = 0; i < nsamps; i++) {{ + output[i] = {to_host}(input[i]); + }} +}} +""" + +TMPL_CONV_U8 = """ +DECLARE_CONVERTER(u8, 1, u8_item32_{end}, 1, PRIORITY_GENERAL) {{ + const boost::uint32_t *input = reinterpret_cast<const boost::uint32_t *>(inputs[0]); + boost::uint32_t *output = reinterpret_cast<boost::uint32_t *>(outputs[0]); + + // 1) Copy all the 4-byte tuples + size_t n_words = nsamps / 4; + for (size_t i = 0; i < n_words; i++) {{ + output[i] = {to_wire}(input[i]); + }} + // 2) If nsamps was not a multiple of 4, copy the rest by hand + size_t bytes_left = nsamps % 4; + if (bytes_left) {{ + const u8_t *last_input_word = reinterpret_cast<const u8_t *>(&input[n_words]); + u8_t *last_output_word = reinterpret_cast<u8_t *>(&output[n_words]); + for (size_t k = 0; k < bytes_left; k++) {{ + last_output_word[k] = last_input_word[k]; + }} + output[n_words] = {to_wire}(output[n_words]); + }} +}} + +DECLARE_CONVERTER(u8_item32_{end}, 1, u8, 1, PRIORITY_GENERAL) {{ + const boost::uint32_t *input = reinterpret_cast<const boost::uint32_t *>(inputs[0]); + boost::uint32_t *output = reinterpret_cast<boost::uint32_t *>(outputs[0]); + + // 1) Copy all the 4-byte tuples + size_t n_words = nsamps / 4; + for (size_t i = 0; i < n_words; i++) {{ + output[i] = {to_host}(input[i]); + }} + // 2) If nsamps was not a multiple of 4, copy the rest by hand + size_t bytes_left = nsamps % 4; + if (bytes_left) {{ + boost::uint32_t last_input_word = {to_host}(input[n_words]); + const u8_t *last_input_word_ptr = reinterpret_cast<const u8_t *>(&last_input_word); + u8_t *last_output_word = reinterpret_cast<u8_t *>(&output[n_words]); + for (size_t k = 0; k < bytes_left; k++) {{ + last_output_word[k] = last_input_word_ptr[k]; + }} + }} +}} """ TMPL_CONV_USRP1_COMPLEX = """ @@ -116,12 +169,19 @@ if __name__ == '__main__': ('be', 'uhd::ntohx', 'uhd::htonx'), ('le', 'uhd::wtohx', 'uhd::htowx'), ): - output += parse_tmpl( - TMPL_CONV_GEN2_ITEM32, + output += TMPL_CONV_GEN2_ITEM32.format( end=end, to_host=to_host, to_wire=to_wire - ) + ) + #generate raw (u8) converters: + for end, to_host, to_wire in ( + ('be', 'uhd::ntohx', 'uhd::htonx'), + ('le', 'uhd::wtohx', 'uhd::htowx'), + ): + output += TMPL_CONV_U8.format( + end=end, to_host=to_host, to_wire=to_wire + ) - #generate complex converters for usrp1 format + #generate complex converters for usrp1 format (requires Cheetah) for width in 1, 2, 4: for cpu_type, do_scale in ( ('fc64', '*scale_factor'), 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/exception.cpp b/host/lib/exception.cpp index ea056bd3b..a9e36fd15 100644 --- a/host/lib/exception.cpp +++ b/host/lib/exception.cpp @@ -43,3 +43,8 @@ make_exception_impl("EnvironmentError", environment_error, exception) make_exception_impl("IOError", io_error, environment_error) make_exception_impl("OSError", os_error, environment_error) make_exception_impl("SystemError", system_error, exception) + +usb_error::usb_error(int code, const std::string &what): + runtime_error(str(boost::format("%s %d: %s") % "USBError" % code % what)), _code(code) {} +usb_error *usb_error::dynamic_clone(void) const{return new usb_error(*this);} \ +void usb_error::dynamic_throw(void) const{throw *this;} diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 0baf8dc76..f92117a9e 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -71,7 +71,18 @@ private: timeval tv; tv.tv_sec = 0; tv.tv_usec = 100000; - libusb_handle_events_timeout(context, &tv); + int ret = libusb_handle_events_timeout(context, &tv); + switch (ret) + { + case LIBUSB_SUCCESS: + case LIBUSB_ERROR_TIMEOUT: + break; + case LIBUSB_ERROR_NO_DEVICE: + throw uhd::io_error(libusb_strerror(LIBUSB_ERROR_NO_DEVICE)); + default: + UHD_MSG(error) << __FUNCTION__ << ": " << libusb_strerror((libusb_error)ret) << std::endl; + break; + } } }; @@ -251,6 +262,21 @@ public: _claimed.push_back(interface); } + void clear_endpoints(unsigned char recv_endpoint, unsigned char send_endpoint) + { + int ret; + ret = libusb_clear_halt(this->get(), recv_endpoint | 0x80); + UHD_LOG << "usb device handle: recv endpoint clear: " << libusb_error_name(ret) << std::endl; + ret = libusb_clear_halt(this->get(), send_endpoint | 0x00); + UHD_LOG << "usb device handle: send endpoint clear: " << libusb_error_name(ret) << std::endl; + } + + void reset_device(void) + { + int ret = libusb_reset_device(this->get()); + UHD_LOG << "usb device handle: dev Reset: " << libusb_error_name(ret) << std::endl; + } + private: libusb::device::sptr _dev; //always keep a reference to device libusb_device_handle *_handle; diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp index b00946614..2ff1291d9 100644 --- a/host/lib/transport/libusb1_base.hpp +++ b/host/lib/transport/libusb1_base.hpp @@ -24,6 +24,29 @@ #include <uhd/transport/usb_device_handle.hpp> #include <libusb.h> +//! Define LIBUSB_CALL when its missing (non-windows) +#ifndef LIBUSB_CALL + #define LIBUSB_CALL +#endif /*LIBUSB_CALL*/ + +//! libusb_handle_events_timeout_completed is only in newer API +#ifndef HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED + #define libusb_handle_events_timeout_completed(ctx, tx, completed) \ + libusb_handle_events_timeout(ctx, tx) +#endif /* HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED */ + +//! libusb_error_name is only in newer API +#ifndef HAVE_LIBUSB_ERROR_NAME + #define libusb_error_name(code) \ + str(boost::format("LIBUSB_ERROR_CODE %d") % code) +#endif /* HAVE_LIBUSB_ERROR_NAME */ + +//! libusb_strerror is only in newer API +#ifndef HAVE_LIBUSB_STRERROR + #define libusb_strerror(code) \ + libusb_error_name(code) +#endif /* HAVE_LIBUSB_STRERROR */ + /*********************************************************************** * Libusb object oriented smart pointer wrappers: * The following wrappers provide allocation and automatic deallocation @@ -135,6 +158,10 @@ namespace libusb { * Control interface: 0 */ virtual void claim_interface(int) = 0; + + virtual void clear_endpoints(unsigned char recv_endpoint, unsigned char send_endpoint) = 0; + + virtual void reset_device(void) = 0; }; /*! diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 1ac02d16f..6925e7659 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -43,23 +43,6 @@ using namespace uhd::transport; static const size_t DEFAULT_NUM_XFERS = 16; //num xfers static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes -//! Define LIBUSB_CALL when its missing (non-windows) -#ifndef LIBUSB_CALL - #define LIBUSB_CALL -#endif /*LIBUSB_CALL*/ - -//! libusb_handle_events_timeout_completed is only in newer API -#ifndef HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED - #define libusb_handle_events_timeout_completed(ctx, tx, completed) \ - libusb_handle_events_timeout(ctx, tx) -#endif - -//! libusb_error_name is only in newer API -#ifndef HAVE_LIBUSB_ERROR_NAME - #define libusb_error_name(code) \ - str(boost::format("LIBUSB_ERROR_CODE %d") % code) -#endif - //! type for sharing the release queue with managed buffers class libusb_zero_copy_mb; typedef boost::shared_ptr<bounded_buffer<libusb_zero_copy_mb *> > mb_queue_sptr; @@ -155,8 +138,9 @@ public: result.is_recv = _is_recv; #endif const int ret = libusb_submit_transfer(_lut); - if (ret != 0) throw uhd::runtime_error(str(boost::format( - "usb %s submit failed: %s") % _name % libusb_error_name(ret))); + if (ret != LIBUSB_SUCCESS) + throw uhd::runtime_error(str(boost::format("usb %s submit failed: %s") + % _name % libusb_strerror((libusb_error)ret))); } template <typename buffer_type> @@ -164,8 +148,9 @@ public: { if (wait_for_completion(timeout)) { - if (result.status != LIBUSB_TRANSFER_COMPLETED) throw uhd::runtime_error(str(boost::format( - "usb %s transfer status: %d") % _name % int(result.status))); + if (result.status != LIBUSB_TRANSFER_COMPLETED) + throw uhd::runtime_error(str(boost::format("usb %s transfer status: %d") + % _name % libusb_error_name(result.status))); result.completed = 0; return make(reinterpret_cast<buffer_type *>(this), _lut->buffer, (_is_recv)? result.actual_length : _frame_size); } @@ -219,7 +204,8 @@ public: _num_frames(num_frames), _frame_size(frame_size), _buffer_pool(buffer_pool::make(_num_frames, _frame_size)), - _enqueued(_num_frames), _released(_num_frames) + _enqueued(_num_frames), _released(_num_frames), + _status(STATUS_RUNNING) { const bool is_recv = (endpoint & 0x80) != 0; const std::string name = str(boost::format("%s%d") % ((is_recv)? "rx" : "tx") % int(endpoint & 0x7f)); @@ -304,18 +290,24 @@ public: UHD_INLINE typename buffer_type::sptr get_buff(double timeout) { typename buffer_type::sptr buff; - libusb_zero_copy_mb *front = NULL; - boost::mutex::scoped_lock lock(_mutex); + + if (_status == STATUS_ERROR) + return buff; + + // Serialize access to buffers + boost::mutex::scoped_lock get_buff_lock(_get_buff_mutex); + + boost::mutex::scoped_lock queue_lock(_queue_mutex); if (_enqueued.empty()) { - _cond.timed_wait(lock, boost::posix_time::microseconds(long(timeout*1e6))); + _buff_ready_cond.timed_wait(queue_lock, boost::posix_time::microseconds(long(timeout*1e6))); } if (_enqueued.empty()) return buff; - front = _enqueued.front(); + libusb_zero_copy_mb *front = _enqueued.front(); - lock.unlock(); + queue_lock.unlock(); buff = front->get_new<buffer_type>(timeout); - lock.lock(); + queue_lock.lock(); if (buff) _enqueued.pop_front(); this->submit_what_we_can(); @@ -333,28 +325,39 @@ private: buffer_pool::sptr _buffer_pool; std::vector<boost::shared_ptr<libusb_zero_copy_mb> > _mb_pool; - boost::mutex _mutex; - boost::condition_variable _cond; + boost::mutex _queue_mutex; + boost::condition_variable _buff_ready_cond; + boost::mutex _get_buff_mutex; //! why 2 queues? there is room in the future to have > N buffers but only N in flight boost::circular_buffer<libusb_zero_copy_mb *> _enqueued, _released; + enum {STATUS_RUNNING, STATUS_ERROR} _status; + void enqueue_buffer(libusb_zero_copy_mb *mb) { - boost::mutex::scoped_lock l(_mutex); + boost::mutex::scoped_lock l(_queue_mutex); _released.push_back(mb); this->submit_what_we_can(); - l.unlock(); - _cond.notify_one(); + _buff_ready_cond.notify_one(); } void submit_what_we_can(void) { + if (_status == STATUS_ERROR) + return; while (not _released.empty() and not _enqueued.full()) { - _released.front()->submit(); - _enqueued.push_back(_released.front()); - _released.pop_front(); + try { + _released.front()->submit(); + _enqueued.push_back(_released.front()); + _released.pop_front(); + } + catch (uhd::runtime_error& e) + { + _status = STATUS_ERROR; + throw e; + } } } diff --git a/host/lib/transport/udp_zero_copy.cpp b/host/lib/transport/udp_zero_copy.cpp index adc7d5585..70fb5b552 100644 --- a/host/lib/transport/udp_zero_copy.cpp +++ b/host/lib/transport/udp_zero_copy.cpp @@ -87,7 +87,10 @@ public: if (wait_for_recv_ready(_sock_fd, timeout)){ _len = ::recv(_sock_fd, (char *)_mem, _frame_size, 0); - UHD_ASSERT_THROW(_len > 0); // TODO: Handle case of recv error + if (_len == 0) + throw uhd::io_error("socket closed"); + if (_len < 0) + throw uhd::io_error(str(boost::format("recv error on socket: %s") % strerror(errno))); index++; //advances the caller's buffer return make(this, _mem, size_t(_len)); } @@ -126,6 +129,10 @@ public: boost::this_thread::sleep(boost::posix_time::microseconds(1)); continue; //try to send again } + if (ret == -1) + { + throw uhd::io_error(str(boost::format("send error on socket: %s") % strerror(errno))); + } UHD_ASSERT_THROW(ret == ssize_t(size())); } _claimer.release(); diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt index 5e97628f0..891977065 100644 --- a/host/lib/types/CMakeLists.txt +++ b/host/lib/types/CMakeLists.txt @@ -94,3 +94,14 @@ 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}/device_addrs_c.cpp + ${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/device_addrs_c.cpp b/host/lib/types/device_addrs_c.cpp new file mode 100644 index 000000000..3a24551d3 --- /dev/null +++ b/host/lib/types/device_addrs_c.cpp @@ -0,0 +1,78 @@ +// +// 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/device_addrs.h> + +uhd_error uhd_device_addrs_make( + uhd_device_addrs_handle *h +){ + UHD_SAFE_C( + (*h) = new uhd_device_addrs_t; + ) +} + +uhd_error uhd_device_addrs_free( + uhd_device_addrs_handle *h +){ + UHD_SAFE_C( + delete (*h); + (*h) = NULL; + ) +} + +uhd_error uhd_device_addrs_push_back( + uhd_device_addrs_handle h, + const char* value +){ + UHD_SAFE_C_SAVE_ERROR(h, + h->device_addrs_cpp.push_back(uhd::device_addr_t(value)); + ) +} + +uhd_error uhd_device_addrs_at( + uhd_device_addrs_handle h, + size_t index, + char* value_out, + size_t strbuffer_len +){ + UHD_SAFE_C_SAVE_ERROR(h, + memset(value_out, '\0', strbuffer_len); + + std::string value_cpp = h->device_addrs_cpp.at(index).to_string(); + strncpy(value_out, value_cpp.c_str(), strbuffer_len); + ) +} + +uhd_error uhd_device_addrs_size( + uhd_device_addrs_handle h, + size_t *size_out +){ + UHD_SAFE_C_SAVE_ERROR(h, + *size_out = h->device_addrs_cpp.size(); + ) +} + +uhd_error uhd_device_addrs_last_error( + uhd_device_addrs_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/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/b200/b200_image_loader.cpp b/host/lib/usrp/b200/b200_image_loader.cpp index 87010244c..9eaeeff63 100644 --- a/host/lib/usrp/b200/b200_image_loader.cpp +++ b/host/lib/usrp/b200/b200_image_loader.cpp @@ -40,27 +40,50 @@ static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t & bool user_specified){ std::vector<usb_device_handle::sptr> dev_handles = get_b200_device_handles(image_loader_args.args); + std::vector<usb_device_handle::sptr> applicable_dev_handles; b200_iface::sptr iface; + mboard_eeprom_t eeprom; // Internal use if(dev_handles.size() > 0){ BOOST_FOREACH(usb_device_handle::sptr dev_handle, dev_handles){ if(dev_handle->firmware_loaded()){ iface = b200_iface::make(usb_control::make(dev_handle,0)); - mb_eeprom = mboard_eeprom_t(*iface, "B200"); + eeprom = mboard_eeprom_t(*iface, "B200"); if(user_specified){ if(image_loader_args.args.has_key("serial") and - mb_eeprom.get("serial") != image_loader_args.args.get("serial")){ + eeprom.get("serial") != image_loader_args.args.get("serial")){ continue; } if(image_loader_args.args.has_key("name") and - mb_eeprom.get("name") != image_loader_args.args.get("name")){ + eeprom.get("name") != image_loader_args.args.get("name")){ continue; } - return iface; + applicable_dev_handles.push_back(dev_handle); } - else return iface; // Just return first found + else applicable_dev_handles.push_back(dev_handle); } } + + // At this point, we should have a single B2XX + if(applicable_dev_handles.size() == 1){ + mb_eeprom = eeprom; + return iface; + } + else if(applicable_dev_handles.size() > 1){ + std::string err_msg = "Could not resolve given args to a single B2XX device.\n" + "Applicable devices:\n"; + + BOOST_FOREACH(usb_device_handle::sptr dev_handle, applicable_dev_handles){ + eeprom = mboard_eeprom_t(*b200_iface::make(usb_control::make(dev_handle,0)), "B200"); + err_msg += str(boost::format(" * %s (serial=%s)\n") + % B2X0_STR_NAMES.get(get_b200_type(mb_eeprom), "B2XX") + % mb_eeprom.get("serial")); + } + + err_msg += "\nSpecify one of these devices with the given args to load an image onto it."; + + throw uhd::runtime_error(err_msg); + } } // No applicable devices found, return empty sptr so we can exit diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index b45529c1a..f5129bc24 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -37,6 +37,8 @@ #include <ctime> #include <cmath> +#include "../../transport/libusb1_base.hpp" + using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; @@ -125,8 +127,7 @@ static device_addrs_t b200_find(const device_addr_t &hint) // so that re-enumeration after fw load can occur successfully. // This requirement is a courtesy of libusb1.0 on windows. size_t found = 0; - std::vector<usb_device_handle::sptr> b200_device_handles = get_b200_device_handles(hint); - BOOST_FOREACH(usb_device_handle::sptr handle, b200_device_handles) { + BOOST_FOREACH(usb_device_handle::sptr handle, get_b200_device_handles(hint)) { //extract the firmware path for the b200 std::string b200_fw_image; try{ @@ -157,7 +158,7 @@ static device_addrs_t b200_find(const device_addr_t &hint) //search for the device until found or timeout while (boost::get_system_time() < timeout_time and b200_addrs.empty() and found != 0) { - BOOST_FOREACH(usb_device_handle::sptr handle, b200_device_handles) + BOOST_FOREACH(usb_device_handle::sptr handle, get_b200_device_handles(hint)) { usb_control::sptr control; try{control = usb_control::make(handle, 0);} @@ -195,7 +196,24 @@ static device_addrs_t b200_find(const device_addr_t &hint) **********************************************************************/ static device::sptr b200_make(const device_addr_t &device_addr) { - return device::sptr(new b200_impl(device_addr)); + uhd::transport::usb_device_handle::sptr handle; + + // We try twice, because the first time, the link might be in a bad state + // and we might need to reset the link, but if that didn't help, trying + // a third time is pointless. + try { + return device::sptr(new b200_impl(device_addr, handle)); + } + catch (const uhd::usb_error &e) { + libusb::device_handle::sptr dev_handle(libusb::device_handle::get_cached_handle( + boost::static_pointer_cast<libusb::special_handle>(handle)->get_device() + )); + dev_handle->clear_endpoints(B200_USB_CTRL_RECV_ENDPOINT, B200_USB_CTRL_SEND_ENDPOINT); + dev_handle->clear_endpoints(B200_USB_DATA_RECV_ENDPOINT, B200_USB_DATA_SEND_ENDPOINT); + dev_handle->reset_device(); + } + + return device::sptr(new b200_impl(device_addr, handle)); } UHD_STATIC_BLOCK(register_b200_device) @@ -206,7 +224,7 @@ UHD_STATIC_BLOCK(register_b200_device) /*********************************************************************** * Structors **********************************************************************/ -b200_impl::b200_impl(const device_addr_t &device_addr) : +b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::sptr &handle) : _revision(0), _tick_rate(0.0) // Forces a clock initialization at startup { @@ -263,7 +281,6 @@ b200_impl::b200_impl(const device_addr_t &device_addr) : std::vector<usb_device_handle::sptr> device_list = usb_device_handle::get_device_list(vid_pid_pair_list); //locate the matching handle in the device list - usb_device_handle::sptr handle; BOOST_FOREACH(usb_device_handle::sptr dev_handle, device_list) { if (dev_handle->get_serial() == device_addr["serial"]){ handle = dev_handle; @@ -361,10 +378,11 @@ b200_impl::b200_impl(const device_addr_t &device_addr) : ctrl_xport_args["send_frame_size"] = min_frame_size; ctrl_xport_args["num_send_frames"] = "16"; + // This may throw a uhd::usb_error, which will be caught by b200_make(). _ctrl_transport = usb_zero_copy::make( handle, - 4, 8, //interface, endpoint - 3, 4, //interface, endpoint + B200_USB_CTRL_RECV_INTERFACE, B200_USB_CTRL_RECV_ENDPOINT, //interface, endpoint + B200_USB_CTRL_SEND_INTERFACE, B200_USB_CTRL_SEND_ENDPOINT, //interface, endpoint ctrl_xport_args ); while (_ctrl_transport->get_recv_buff(0.0)){} //flush ctrl xport @@ -443,10 +461,11 @@ b200_impl::b200_impl(const device_addr_t &device_addr) : data_xport_args["send_frame_size"] = device_addr.get("send_frame_size", "8192"); data_xport_args["num_send_frames"] = device_addr.get("num_send_frames", "16"); + // This may throw a uhd::usb_error, which will be caught by b200_make(). _data_transport = usb_zero_copy::make( handle, // identifier - 2, 6, // IN interface, endpoint - 1, 2, // OUT interface, endpoint + B200_USB_DATA_RECV_INTERFACE, B200_USB_DATA_RECV_ENDPOINT, //interface, endpoint + B200_USB_DATA_SEND_INTERFACE, B200_USB_DATA_SEND_ENDPOINT, //interface, endpoint data_xport_args // param hints ); while (_data_transport->get_recv_buff(0.0)){} //flush ctrl xport diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index 52ecb98f2..cbd51426d 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -78,6 +78,16 @@ static const boost::uint32_t B200_RX_GPS_UART_SID = FLIP_SID(B200_TX_GPS_UART_SI static const boost::uint32_t B200_LOCAL_CTRL_SID = 0x00000040; static const boost::uint32_t B200_LOCAL_RESP_SID = FLIP_SID(B200_LOCAL_CTRL_SID); +static const unsigned char B200_USB_CTRL_RECV_INTERFACE = 4; +static const unsigned char B200_USB_CTRL_RECV_ENDPOINT = 8; +static const unsigned char B200_USB_CTRL_SEND_INTERFACE = 3; +static const unsigned char B200_USB_CTRL_SEND_ENDPOINT = 4; + +static const unsigned char B200_USB_DATA_RECV_INTERFACE = 2; +static const unsigned char B200_USB_DATA_RECV_ENDPOINT = 6; +static const unsigned char B200_USB_DATA_SEND_INTERFACE = 1; +static const unsigned char B200_USB_DATA_SEND_ENDPOINT = 2; + /* * VID/PID pairs for all B2xx products */ @@ -96,7 +106,7 @@ class b200_impl : public uhd::device { public: //structors - b200_impl(const uhd::device_addr_t &); + b200_impl(const uhd::device_addr_t &, uhd::transport::usb_device_handle::sptr &handle); ~b200_impl(void); //the io interface diff --git a/host/lib/usrp/common/ad936x_manager.cpp b/host/lib/usrp/common/ad936x_manager.cpp index b060880cd..8c8897803 100644 --- a/host/lib/usrp/common/ad936x_manager.cpp +++ b/host/lib/usrp/common/ad936x_manager.cpp @@ -34,7 +34,7 @@ const uint32_t ad936x_manager::DEFAULT_DECIM = 128; const uint32_t ad936x_manager::DEFAULT_INTERP = 128; const bool ad936x_manager::DEFAULT_AUTO_DC_OFFSET = true; const bool ad936x_manager::DEFAULT_AUTO_IQ_BALANCE = true; -const bool ad936x_manager::DEFAULT_AGC_ENABLE = true; +const bool ad936x_manager::DEFAULT_AGC_ENABLE = false; class ad936x_manager_impl : public ad936x_manager { 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/e300/CMakeLists.txt b/host/lib/usrp/e300/CMakeLists.txt index 26e34294a..ae817c620 100644 --- a/host/lib/usrp/e300/CMakeLists.txt +++ b/host/lib/usrp/e300/CMakeLists.txt @@ -42,14 +42,14 @@ IF(ENABLE_E300) ${CMAKE_CURRENT_SOURCE_DIR}/e300_remote_codec_ctrl.cpp ) LIBUHD_APPEND_SOURCES(${E300_SOURCES}) - IF(UDEV_FOUND) + IF(UDEV_FOUND AND NOT E300_FORCE_NETWORK) INCLUDE_DIRECTORIES(${UDEV_INCLUDE_DIR}) LIBUHD_APPEND_LIBS(${UDEV_LIBS}) SET_SOURCE_FILES_PROPERTIES( ${E300_SOURCES} PROPERTIES COMPILE_DEFINITIONS "E300_NATIVE=1" ) - ENDIF(UDEV_FOUND) + ENDIF(UDEV_FOUND AND NOT E300_FORCE_NETWORK) IF(ENABLE_GPSD) SET_SOURCE_FILES_PROPERTIES( diff --git a/host/lib/usrp/e300/e300_common.cpp b/host/lib/usrp/e300/e300_common.cpp index 29117e21f..216713bc6 100644 --- a/host/lib/usrp/e300/e300_common.cpp +++ b/host/lib/usrp/e300/e300_common.cpp @@ -29,6 +29,7 @@ #include <fstream> #include <string> +#ifdef E300_NATIVE namespace uhd { namespace usrp { namespace e300 { namespace common { @@ -90,3 +91,18 @@ UHD_STATIC_BLOCK(register_e300_image_loader) { } }}} + +#else +namespace uhd { namespace usrp { namespace e300 { + +namespace common { + +void load_fpga_image(const std::string&) +{ + throw uhd::assertion_error("load_fpga_image() !E300_NATIVE"); +} + +} + +}}} +#endif diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index 6eb63c786..5bef783f6 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -505,14 +505,14 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) this->_setup_radio(instance); // Radio 0 loopback through AD9361 - _codec_mgr->loopback_self_test(_radio_perifs[0].ctrl, TOREG(SR_CODEC_IDLE), RB64_CODEC_READBACK); + _codec_mgr->loopback_self_test(_radio_perifs[0].ctrl, radio::sr_addr(radio::CODEC_IDLE), radio::RB64_CODEC_READBACK); // Radio 1 loopback through AD9361 - _codec_mgr->loopback_self_test(_radio_perifs[1].ctrl, TOREG(SR_CODEC_IDLE), RB64_CODEC_READBACK); + _codec_mgr->loopback_self_test(_radio_perifs[1].ctrl, radio::sr_addr(radio::CODEC_IDLE), radio::RB64_CODEC_READBACK); //////////////////////////////////////////////////////////////////// // internal gpios //////////////////////////////////////////////////////////////////// - gpio_core_200::sptr fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO); + gpio_core_200::sptr fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, radio::sr_addr(radio::FP_GPIO), radio::RB32_FP_GPIO); BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map) { _tree->create<boost::uint32_t>(mb_path / "gpio" / "INT0" / attr.second) @@ -749,8 +749,8 @@ void e300_impl::_register_loopback_self_test(wb_iface::sptr iface) for (size_t i = 0; i < 100; i++) { boost::hash_combine(hash, i); - iface->poke32(TOREG(SR_TEST), boost::uint32_t(hash)); - test_fail = iface->peek32(RB32_TEST) != boost::uint32_t(hash); + iface->poke32(radio::sr_addr(radio::TEST), boost::uint32_t(hash)); + test_fail = iface->peek32(radio::RB32_TEST) != boost::uint32_t(hash); if (test_fail) break; //exit loop on any failure } UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl; @@ -998,20 +998,20 @@ void e300_impl::_setup_radio(const size_t dspno) //////////////////////////////////////////////////////////////////// // Set up peripherals //////////////////////////////////////////////////////////////////// - perif.atr = gpio_core_200_32wo::make(perif.ctrl, TOREG(SR_GPIO)); - perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, TOREG(SR_RX_FRONT)); + perif.atr = gpio_core_200_32wo::make(perif.ctrl, radio::sr_addr(radio::GPIO)); + perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, radio::sr_addr(radio::RX_FRONT)); perif.rx_fe->set_dc_offset(rx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE); perif.rx_fe->set_dc_offset_auto(rx_frontend_core_200::DEFAULT_DC_OFFSET_ENABLE); perif.rx_fe->set_iq_balance(rx_frontend_core_200::DEFAULT_IQ_BALANCE_VALUE); - perif.tx_fe = tx_frontend_core_200::make(perif.ctrl, TOREG(SR_TX_FRONT)); + perif.tx_fe = tx_frontend_core_200::make(perif.ctrl, radio::sr_addr(radio::TX_FRONT)); perif.tx_fe->set_dc_offset(tx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE); perif.tx_fe->set_iq_balance(tx_frontend_core_200::DEFAULT_IQ_BALANCE_VALUE); - perif.framer = rx_vita_core_3000::make(perif.ctrl, TOREG(SR_RX_CTRL)); - perif.ddc = rx_dsp_core_3000::make(perif.ctrl, TOREG(SR_RX_DSP)); + perif.framer = rx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_CTRL)); + perif.ddc = rx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_DSP)); perif.ddc->set_link_rate(10e9/8); //whatever perif.ddc->set_freq(e300::DEFAULT_DDC_FREQ); - perif.deframer = tx_vita_core_3000::make(perif.ctrl, TOREG(SR_TX_CTRL)); - perif.duc = tx_dsp_core_3000::make(perif.ctrl, TOREG(SR_TX_DSP)); + perif.deframer = tx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_CTRL)); + perif.duc = tx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_DSP)); perif.duc->set_link_rate(10e9/8); //whatever perif.duc->set_freq(e300::DEFAULT_DUC_FREQ); @@ -1019,9 +1019,9 @@ void e300_impl::_setup_radio(const size_t dspno) // create time control objects //////////////////////////////////////////////////////////////////// time_core_3000::readback_bases_type time64_rb_bases; - time64_rb_bases.rb_now = RB64_TIME_NOW; - time64_rb_bases.rb_pps = RB64_TIME_PPS; - perif.time64 = time_core_3000::make(perif.ctrl, TOREG(SR_TIME), time64_rb_bases); + time64_rb_bases.rb_now = radio::RB64_TIME_NOW; + time64_rb_bases.rb_pps = radio::RB64_TIME_PPS; + perif.time64 = time_core_3000::make(perif.ctrl, radio::sr_addr(radio::TIME), time64_rb_bases); //////////////////////////////////////////////////////////////////// // front end corrections @@ -1074,12 +1074,9 @@ void e300_impl::_setup_radio(const size_t dspno) _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "lo_locked") .publish(boost::bind(&e300_impl::_get_fe_pll_lock, this, dir == TX_DIRECTION)) ; - - // Network mode currently doesn't support the filter API, so - // prevent it from using it: - if (_xport_path != AXI) { - _tree->remove(rf_fe_path / "filters"); - } + _tree->access<double>(rf_fe_path / "freq" / "value") + .subscribe(boost::bind(&e300_impl::_update_fe_lo_freq, this, key, _1)) + ; // Antenna Setup if (dir == RX_DIRECTION) { diff --git a/host/lib/usrp/e300/e300_regs.hpp b/host/lib/usrp/e300/e300_regs.hpp index 5736ebfd4..846c759a4 100644 --- a/host/lib/usrp/e300/e300_regs.hpp +++ b/host/lib/usrp/e300/e300_regs.hpp @@ -18,36 +18,48 @@ #ifndef INCLUDED_E300_REGS_HPP #define INCLUDED_E300_REGS_HPP -#include <boost/cstdint.hpp> +#include <stdint.h> +#include <uhd/config.hpp> -#define TOREG(x) ((x)*4) +namespace uhd { namespace usrp { namespace e300 { namespace radio { -#define localparam static const int +static UHD_INLINE uint32_t sr_addr(const uint32_t offset) +{ + return offset * 4; +} + +static const uint32_t DACSYNC = 5; +static const uint32_t LOOPBACK = 6; +static const uint32_t TEST = 7; +static const uint32_t SPI = 8; +static const uint32_t GPIO = 16; +static const uint32_t MISC_OUTS = 24; +static const uint32_t READBACK = 32; +static const uint32_t TX_CTRL = 64; +static const uint32_t RX_CTRL = 96; +static const uint32_t TIME = 128; +static const uint32_t RX_DSP = 144; +static const uint32_t TX_DSP = 184; +static const uint32_t LEDS = 195; +static const uint32_t FP_GPIO = 200; +static const uint32_t RX_FRONT = 208; +static const uint32_t TX_FRONT = 216; +static const uint32_t CODEC_IDLE = 250; -localparam SR_TEST = 7; -localparam SR_SPI = 8; -localparam SR_GPIO = 16; -localparam SR_MISC_OUTS = 24; -localparam SR_READBACK = 32; -localparam SR_TX_CTRL = 64; -localparam SR_RX_CTRL = 96; -localparam SR_TIME = 128; -localparam SR_RX_DSP = 144; -localparam SR_TX_DSP = 184; -localparam SR_LEDS = 195; -localparam SR_FP_GPIO = 200; -localparam SR_RX_FRONT = 208; -localparam SR_TX_FRONT = 216; -localparam SR_CODEC_IDLE = 250; +static const uint32_t RB32_GPIO = 0; +static const uint32_t RB32_SPI = 4; +static const uint32_t RB64_TIME_NOW = 8; +static const uint32_t RB64_TIME_PPS = 16; +static const uint32_t RB32_TEST = 24; +static const uint32_t RB32_RX = 28; +static const uint32_t RB32_FP_GPIO = 32; +static const uint32_t RB32_MISC_INS = 36; +static const uint32_t RB64_CODEC_READBACK = 40; +static const uint32_t RB32_RADIO_NUM = 48; +}}}} // namespace -localparam RB32_SPI = 4; -localparam RB64_TIME_NOW = 8; -localparam RB64_TIME_PPS = 16; -localparam RB32_TEST = 24; -localparam RB32_FP_GPIO = 32; -localparam RB64_CODEC_READBACK = 40; -localparam RB32_RADIO_NUM = 48; +#define localparam static const int localparam ST_RX_ENABLE = 20; localparam ST_TX_ENABLE = 19; diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp index 9708634dd..1e0895393 100644 --- a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp +++ b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp @@ -227,7 +227,7 @@ public: //! List all available filters by name std::vector<std::string> get_filter_names(const std::string &) { - UHD_THROW_INVALID_CODE_PATH(); + return std::vector<std::string>(); } //! Return a list of all filters @@ -239,7 +239,7 @@ public: //! Write back a filter void set_filter(const std::string &, const std::string &, const filter_info_base::sptr) { - UHD_THROW_INVALID_CODE_PATH(); + UHD_MSG(warning) << "Attempting to set filter on E300 in network mode." << std::endl; } private: 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/usrp2/n200_image_loader.cpp b/host/lib/usrp/usrp2/n200_image_loader.cpp index ce956c22c..29bec8b4a 100644 --- a/host/lib/usrp/usrp2/n200_image_loader.cpp +++ b/host/lib/usrp/usrp2/n200_image_loader.cpp @@ -210,36 +210,62 @@ static uhd::device_addr_t n200_find(const image_loader::image_loader_args_t &ima image_loader_args.args.has_key("name"); uhd::device_addrs_t found = usrp2_find(image_loader_args.args); - if(found.size() > 0){ - uhd::device_addr_t ret = found[0]; - - /* - * Make sure the device found is an N-Series and not a USRP2. A USRP2 - * will not respond to this query. If the user supplied specific - * arguments that led to a USRP2, throw an error. - */ - udp_simple::sptr rev_xport = udp_simple::make_connected( - ret["addr"], - BOOST_STRINGIZE(N200_UDP_FW_UPDATE_PORT) - ); + if(found.size() > 0){ + uhd::device_addrs_t n200_found; + udp_simple::sptr rev_xport; n200_fw_update_data_t pkt_out; boost::uint8_t data_in[udp_simple::mtu]; const n200_fw_update_data_t *pkt_in = reinterpret_cast<const n200_fw_update_data_t*>(data_in); + size_t len = 0; - size_t len = n200_send_and_recv(rev_xport, GET_HW_REV_CMD, &pkt_out, data_in); - if(n200_response_matches(pkt_in, GET_HW_REV_ACK, len)){ - boost::uint32_t rev = ntohl(pkt_in->data.hw_rev); - ret["hw_rev"] = n200_filename_map.get(rev, "n2xx"); - return ret; + /* + * Filter out any USRP2 devices by sending a query over the + * UDP update port. Only N-Series devices will respond to + * this query. If the user supplied specific arguments that + * led to a USRP2, throw an error. + */ + BOOST_FOREACH(const uhd::device_addr_t &dev, found){ + rev_xport = udp_simple::make_connected( + dev.get("addr"), + BOOST_STRINGIZE(N200_UDP_FW_UPDATE_PORT) + ); + + len = n200_send_and_recv(rev_xport, GET_HW_REV_CMD, &pkt_out, data_in); + if(n200_response_matches(pkt_in, GET_HW_REV_ACK, len)){ + boost::uint32_t rev = ntohl(pkt_in->data.hw_rev); + std::string hw_rev = n200_filename_map.get(rev, "n2xx"); + + n200_found.push_back(dev); + n200_found[n200_found.size()-1]["hw_rev"] = hw_rev; + } + else if(len > offsetof(n200_fw_update_data_t, data) and ntohl(pkt_in->id) != GET_HW_REV_ACK){ + throw uhd::runtime_error(str(boost::format("Received invalid reply %d from device.") + % ntohl(pkt_in->id))); + } + else if(user_specified){ + // At this point, we haven't received any response, so assume it's a USRP2 + print_usrp2_error(image_loader_args); + } } - else if(len > offsetof(n200_fw_update_data_t, data) and ntohl(pkt_in->id) != GET_HW_REV_ACK){ - throw uhd::runtime_error(str(boost::format("Received invalid reply %d from device.") - % ntohl(pkt_in->id))); + + // At this point, we should have a single N-Series device + if(n200_found.size() == 1){ + return n200_found[0]; } - else if(user_specified){ - // At this point, we haven't received any response, so assume it's a USRP2 - print_usrp2_error(image_loader_args); + else if(n200_found.size() > 1){ + std::string err_msg = "Could not resolve given args to a single N-Series device.\n" + "Applicable devices:\n"; + + BOOST_FOREACH(const uhd::device_addr_t &dev, n200_found){ + err_msg += str(boost::format("* %s (addr=%s)\n") + % dev.get("hw_rev") + % dev.get("addr")); + } + + err_msg += "\nSpecify one of these devices with the given args to load an image onto it."; + + throw uhd::runtime_error(err_msg); } } @@ -259,7 +285,7 @@ static void n200_validate_firmware_image(n200_session_t &session){ session.max_size = N200_FW_MAX_SIZE_BYTES; if(session.size > session.max_size){ - throw uhd::runtime_error(str(boost::format("The specified FPGA image is too large: %d vs. %d") + throw uhd::runtime_error(str(boost::format("The specified firmware image is too large: %d vs. %d") % session.size % session.max_size)); } @@ -559,11 +585,15 @@ static std::string nice_name(const std::string &fw_rev){ } static bool n200_image_loader(const image_loader::image_loader_args_t &image_loader_args){ + if(!image_loader_args.load_firmware and !image_loader_args.load_fpga){ + return false; + } + // See if any N2x0 with the given args is found // This will throw if specific args lead to a USRP2 n200_session_t session; session.dev_addr = n200_find(image_loader_args); - if(session.dev_addr.size() == 0 or (!image_loader_args.load_firmware and !image_loader_args.load_fpga)){ + if(session.dev_addr.size() == 0){ return false; } diff --git a/host/lib/usrp/usrp_c.cpp b/host/lib/usrp/usrp_c.cpp new file mode 100644 index 000000000..829014829 --- /dev/null +++ b/host/lib/usrp/usrp_c.cpp @@ -0,0 +1,1523 @@ +/* + * 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_find_mutex; +uhd_error uhd_usrp_find( + uhd_device_addrs_handle h, + const char* args, + size_t *num_found +){ + UHD_SAFE_C_SAVE_ERROR(h, + boost::mutex::scoped_lock _lock(_usrp_find_mutex); + + h->device_addrs_cpp = uhd::device::find(std::string(args), uhd::device::USRP); + *num_found = h->device_addrs_cpp.size(); + ) +} + +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/x300/x300_adc_dac_utils.cpp b/host/lib/usrp/x300/x300_adc_dac_utils.cpp index b1483b3a5..e08825749 100644 --- a/host/lib/usrp/x300/x300_adc_dac_utils.cpp +++ b/host/lib/usrp/x300/x300_adc_dac_utils.cpp @@ -41,7 +41,7 @@ void x300_impl::synchronize_dacs(const std::vector<radio_perifs_t*>& radios) //Get a rough estimate of the cumulative command latency boost::posix_time::ptime t_start = boost::posix_time::microsec_clock::local_time(); for (size_t i = 0; i < radios.size(); i++) { - radios[i]->ctrl->peek64(RB64_TIME_NOW); //Discard value. We are just timing the call + radios[i]->ctrl->peek64(uhd::usrp::radio::RB64_TIME_NOW); //Discard value. We are just timing the call } boost::posix_time::time_duration t_elapsed = boost::posix_time::microsec_clock::local_time() - t_start; @@ -56,7 +56,7 @@ void x300_impl::synchronize_dacs(const std::vector<radio_perifs_t*>& radios) //Send the sync command for (size_t i = 0; i < radios.size(); i++) { radios[i]->ctrl->set_time(sync_time); - radios[i]->ctrl->poke32(TOREG(SR_DACSYNC), 0x1); //Arm FRAMEP/N sync pulse + radios[i]->ctrl->poke32(uhd::usrp::radio::sr_addr(uhd::usrp::radio::DACSYNC), 0x1); //Arm FRAMEP/N sync pulse radios[i]->ctrl->set_time(uhd::time_spec_t(0.0)); //Clear command time } @@ -73,7 +73,7 @@ void x300_impl::synchronize_dacs(const std::vector<radio_perifs_t*>& radios) static void check_adc(uhd::wb_iface::sptr iface, const boost::uint32_t val, const boost::uint32_t i) { - boost::uint32_t adc_rb = iface->peek32(RB32_RX); + boost::uint32_t adc_rb = iface->peek32(uhd::usrp::radio::RB32_RX); adc_rb ^= 0xfffc0000; //adapt for I inversion in FPGA if (val != adc_rb) { throw uhd::runtime_error( diff --git a/host/lib/usrp/x300/x300_image_loader.cpp b/host/lib/usrp/x300/x300_image_loader.cpp index 321309868..9ec8a2e13 100644 --- a/host/lib/usrp/x300/x300_image_loader.cpp +++ b/host/lib/usrp/x300/x300_image_loader.cpp @@ -158,17 +158,31 @@ static void x300_validate_image(x300_session_t &session){ static void x300_setup_session(x300_session_t &session, const device_addr_t &args, const std::string &filepath){ - device_addr_t find_args; - find_args["type"] = "x300"; - if(args.has_key("name")) find_args["name"] = args["name"]; - if(args.has_key("serial")) find_args["serial"] = args["serial"]; - if(args.has_key("ip-addr")) find_args["addr"] = args["ip-addr"]; - else if(args.has_key("resource")) find_args["resource"] = args["resource"]; - device_addrs_t devs = x300_find(args); - session.found = (devs.size() > 0); - if(!session.found) return; + if(devs.size() == 0){ + session.found = false; + return; + } + else if(devs.size() > 1){ + std::string err_msg = "Could not resolve given args to a single X-Series device.\n" + "Applicable devices:\n"; + + BOOST_FOREACH(const uhd::device_addr_t &dev, devs){ + std::string identifier = dev.has_key("addr") ? "addr" + : "resource"; + + err_msg += str(boost::format(" * %s (%s=%s)\n") + % dev.get("product", "X3XX") + % identifier + % dev.get(identifier)); + } + + err_msg += "\nSpecify one of these devices with the given args to load an image onto it."; + + throw uhd::runtime_error(err_msg); + } + session.found = true; session.dev_addr = devs[0]; session.ethernet = session.dev_addr.has_key("addr"); if(session.ethernet){ diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 437fec82d..229bf7b23 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -29,6 +29,7 @@ #include <uhd/transport/if_addrs.hpp> #include <boost/foreach.hpp> #include <boost/bind.hpp> +#include <boost/make_shared.hpp> #include <boost/functional/hash.hpp> #include <boost/assign/list_of.hpp> #include <fstream> @@ -410,7 +411,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) //Tell the quirks object which FIFOs carry TX stream data const boost::uint32_t tx_data_fifos[2] = {X300_RADIO_DEST_PREFIX_TX, X300_RADIO_DEST_PREFIX_TX + 3}; - mb.rio_fpga_interface->get_kernel_proxy()->get_rio_quirks().register_tx_streams(tx_data_fifos); + mb.rio_fpga_interface->get_kernel_proxy()->get_rio_quirks().register_tx_streams(tx_data_fifos, 2); _tree->create<double>(mb_path / "link_max_rate").set(X300_MAX_RATE_PCIE); } @@ -748,7 +749,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) //////////////////////////////////////////////////////////////////// // front panel gpio //////////////////////////////////////////////////////////////////// - mb.fp_gpio = gpio_core_200::make(mb.radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO); + mb.fp_gpio = gpio_core_200::make(mb.radio_perifs[0].ctrl, radio::sr_addr(radio::GPIO), radio::RB32_FP_GPIO); BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map) { _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr.second) @@ -943,30 +944,30 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con //////////////////////////////////////////////////////////////// // Setup peripherals //////////////////////////////////////////////////////////////// - perif.spi = spi_core_3000::make(perif.ctrl, TOREG(SR_SPI), RB32_SPI); + perif.spi = spi_core_3000::make(perif.ctrl, radio::sr_addr(radio::SPI), radio::RB32_SPI); perif.adc = x300_adc_ctrl::make(perif.spi, DB_ADC_SEN); perif.dac = x300_dac_ctrl::make(perif.spi, DB_DAC_SEN, mb.clock->get_master_clock_rate()); - perif.leds = gpio_core_200_32wo::make(perif.ctrl, TOREG(SR_LEDS)); - perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, TOREG(SR_RX_FRONT)); + perif.leds = gpio_core_200_32wo::make(perif.ctrl, radio::sr_addr(radio::LEDS)); + perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, radio::sr_addr(radio::RX_FRONT)); perif.rx_fe->set_dc_offset(rx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE); perif.rx_fe->set_dc_offset_auto(rx_frontend_core_200::DEFAULT_DC_OFFSET_ENABLE); - perif.tx_fe = tx_frontend_core_200::make(perif.ctrl, TOREG(SR_TX_FRONT)); + perif.tx_fe = tx_frontend_core_200::make(perif.ctrl, radio::sr_addr(radio::TX_FRONT)); perif.tx_fe->set_dc_offset(tx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE); perif.tx_fe->set_iq_balance(tx_frontend_core_200::DEFAULT_IQ_BALANCE_VALUE); - perif.framer = rx_vita_core_3000::make(perif.ctrl, TOREG(SR_RX_CTRL)); - perif.ddc = rx_dsp_core_3000::make(perif.ctrl, TOREG(SR_RX_DSP)); + perif.framer = rx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_CTRL)); + perif.ddc = rx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_DSP)); perif.ddc->set_link_rate(10e9/8); //whatever - perif.deframer = tx_vita_core_3000::make(perif.ctrl, TOREG(SR_TX_CTRL)); - perif.duc = tx_dsp_core_3000::make(perif.ctrl, TOREG(SR_TX_DSP)); + perif.deframer = tx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_CTRL)); + perif.duc = tx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_DSP)); perif.duc->set_link_rate(10e9/8); //whatever //////////////////////////////////////////////////////////////////// // create time control objects //////////////////////////////////////////////////////////////////// time_core_3000::readback_bases_type time64_rb_bases; - time64_rb_bases.rb_now = RB64_TIME_NOW; - time64_rb_bases.rb_pps = RB64_TIME_PPS; - perif.time64 = time_core_3000::make(perif.ctrl, TOREG(SR_TIME), time64_rb_bases); + time64_rb_bases.rb_now = radio::RB64_TIME_NOW; + time64_rb_bases.rb_pps = radio::RB64_TIME_PPS; + perif.time64 = time_core_3000::make(perif.ctrl, radio::sr_addr(radio::TIME), time64_rb_bases); //Capture delays are calibrated every time. The status is only printed is the user //asks to run the xfer self cal using "self_cal_adc_delay" @@ -1030,7 +1031,7 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con //create a new dboard interface x300_dboard_iface_config_t db_config; - db_config.gpio = gpio_core_200::make(perif.ctrl, TOREG(SR_GPIO), RB32_GPIO); + db_config.gpio = gpio_core_200::make(perif.ctrl, radio::sr_addr(radio::GPIO), radio::RB32_GPIO); db_config.spi = perif.spi; db_config.rx_spi_slaveno = DB_RX_SEN; db_config.tx_spi_slaveno = DB_TX_SEN; @@ -1343,8 +1344,8 @@ void x300_impl::register_loopback_self_test(wb_iface::sptr iface) for (size_t i = 0; i < 100; i++) { boost::hash_combine(hash, i); - iface->poke32(TOREG(SR_TEST), boost::uint32_t(hash)); - test_fail = iface->peek32(RB32_TEST) != boost::uint32_t(hash); + iface->poke32(radio::sr_addr(radio::TEST), boost::uint32_t(hash)); + test_fail = iface->peek32(radio::RB32_TEST) != boost::uint32_t(hash); if (test_fail) break; //exit loop on any failure } UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl; diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp index 350845f28..eba30abb5 100644 --- a/host/lib/usrp/x300/x300_regs.hpp +++ b/host/lib/usrp/x300/x300_regs.hpp @@ -18,40 +18,47 @@ #ifndef INCLUDED_X300_REGS_HPP #define INCLUDED_X300_REGS_HPP +#include <uhd/config.hpp> #include <stdint.h> -#include <boost/cstdint.hpp> #include <uhd/utils/soft_register.hpp> -#define TOREG(x) ((x)*4) +namespace uhd { namespace usrp { namespace radio { + +static UHD_INLINE uint32_t sr_addr(const uint32_t offset) +{ + return offset * 4; +} + +static const uint32_t DACSYNC = 5; +static const uint32_t LOOPBACK = 6; +static const uint32_t TEST = 7; +static const uint32_t SPI = 8; +static const uint32_t GPIO = 16; +static const uint32_t MISC_OUTS = 24; +static const uint32_t READBACK = 32; +static const uint32_t TX_CTRL = 64; +static const uint32_t RX_CTRL = 96; +static const uint32_t TIME = 128; +static const uint32_t RX_DSP = 144; +static const uint32_t TX_DSP = 184; +static const uint32_t LEDS = 195; +static const uint32_t FP_GPIO = 200; +static const uint32_t RX_FRONT = 208; +static const uint32_t TX_FRONT = 216; + +static const uint32_t RB32_GPIO = 0; +static const uint32_t RB32_SPI = 4; +static const uint32_t RB64_TIME_NOW = 8; +static const uint32_t RB64_TIME_PPS = 16; +static const uint32_t RB32_TEST = 24; +static const uint32_t RB32_RX = 28; +static const uint32_t RB32_FP_GPIO = 32; +static const uint32_t RB32_MISC_INS = 36; + +}}} // namespace #define localparam static const int -localparam SR_DACSYNC = 5; -localparam SR_LOOPBACK = 6; -localparam SR_TEST = 7; -localparam SR_SPI = 8; -localparam SR_GPIO = 16; -localparam SR_MISC_OUTS = 24; -localparam SR_READBACK = 32; -localparam SR_TX_CTRL = 64; -localparam SR_RX_CTRL = 96; -localparam SR_TIME = 128; -localparam SR_RX_DSP = 144; -localparam SR_TX_DSP = 184; -localparam SR_LEDS = 195; -localparam SR_FP_GPIO = 200; -localparam SR_RX_FRONT = 208; -localparam SR_TX_FRONT = 216; - -localparam RB32_GPIO = 0; -localparam RB32_SPI = 4; -localparam RB64_TIME_NOW = 8; -localparam RB64_TIME_PPS = 16; -localparam RB32_TEST = 24; -localparam RB32_RX = 28; -localparam RB32_FP_GPIO = 32; -localparam RB32_MISC_INS = 36; - localparam BL_ADDRESS = 0; localparam BL_DATA = 1; @@ -247,7 +254,7 @@ namespace uhd { namespace usrp { namespace x300 { UHD_DEFINE_SOFT_REG_FIELD(ADC_DATA_DLY_VAL, /*width*/ 5, /*shift*/ 4); //[8:4] UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER_ENABLED, /*width*/ 1, /*shift*/ 9); //[9] - misc_outs_reg_t(): uhd::soft_reg32_wo_t(TOREG(SR_MISC_OUTS)) { + misc_outs_reg_t(): uhd::soft_reg32_wo_t(uhd::usrp::radio::sr_addr(uhd::usrp::radio::MISC_OUTS)) { //Initial values set(DAC_ENABLED, 0); set(DAC_RESET_N, 0); @@ -269,7 +276,7 @@ namespace uhd { namespace usrp { namespace x300 { UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER1_Q_ERROR, /*width*/ 1, /*shift*/ 6); //[6] UHD_DEFINE_SOFT_REG_FIELD(ADC_CHECKER1_I_ERROR, /*width*/ 1, /*shift*/ 7); //[7] - misc_ins_reg_t(): uhd::soft_reg32_ro_t(RB32_MISC_INS) { } + misc_ins_reg_t(): uhd::soft_reg32_ro_t(uhd::usrp::radio::RB32_MISC_INS) { } } misc_ins_reg; radio_regmap_t(int radio_num) : soft_regmap_t("radio" + boost::lexical_cast<std::string>(radio_num) + "_regmap") { 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/octoclock/octoclock_image_loader.cpp b/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp index c88177f0f..e8c50e029 100644 --- a/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp +++ b/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp @@ -51,7 +51,7 @@ using namespace uhd::transport; * OctoClock burn session */ typedef struct { - bool valid; + bool found; uhd::device_addr_t dev_addr; std::string given_filepath; std::string actual_filepath; // If using a .hex, this is the converted .bin @@ -113,18 +113,43 @@ static void octoclock_validate_firmware_image(octoclock_session_t &session){ : (session.size / OCTOCLOCK_BLOCK_SIZE); octoclock_calculate_crc(session); - session.valid = true; } static void octoclock_setup_session(octoclock_session_t &session, + const uhd::device_addr_t &args, const std::string &filepath){ + // See if we can find an OctoClock with the given args + device_addrs_t devs = octoclock_find(args); + if(devs.size() == 0){ + session.found = false; + return; + } + else if(devs.size() > 1){ + std::string err_msg = "Could not resolve given args to a single OctoClock device.\n" + "Applicable devices:\n"; + + BOOST_FOREACH(const uhd::device_addr_t &dev, devs){ + std::string name = (dev["type"] == "octoclock") ? str(boost::format("OctoClock r%d") + % dev.get("revision","4")) + : "OctoClock Bootloader"; + err_msg += str(boost::format(" * %s (addr=%s)\n") + % name + % dev.get("addr")); + } + + err_msg += "\nSpecify one of these devices with the given args to load an image onto it."; + + throw uhd::runtime_error(err_msg); + } + + session.dev_addr = devs[0]; + // If no filepath is given, use the default if(filepath == ""){ - session.given_filepath = find_image_path(str(boost::format("octoclock_r%d_fw.hex") - % boost::lexical_cast<std::string>( - session.dev_addr.get("revision","4") - ))); + session.given_filepath = find_image_path(str(boost::format("octoclock_r%s_fw.hex") + % session.dev_addr.get("revision","4") + )); } else session.given_filepath = filepath; @@ -287,7 +312,7 @@ static void octoclock_verify(octoclock_session_t &session){ } static void octoclock_finalize(octoclock_session_t &session){ - + octoclock_packet_t pkt_out; pkt_out.sequence = htonx<boost::uint32_t>(std::rand()); const octoclock_packet_t* pkt_in = reinterpret_cast<const octoclock_packet_t*>(session.data_in); @@ -305,15 +330,12 @@ static void octoclock_finalize(octoclock_session_t &session){ } bool octoclock_image_loader(const image_loader::image_loader_args_t &image_loader_args){ - // See if we can find an OctoClock with the given args - device_addrs_t devs = octoclock_find(image_loader_args.args); - if(devs.size() == 0 or !image_loader_args.load_firmware) return false; - octoclock_session_t session; - session.dev_addr = devs[0]; octoclock_setup_session(session, + image_loader_args.args, image_loader_args.firmware_path ); + if(!session.found or !image_loader_args.load_firmware) return false; std::cout << boost::format("Unit: OctoClock (%s)") % session.dev_addr["addr"] @@ -329,7 +351,7 @@ bool octoclock_image_loader(const image_loader::image_loader_args_t &image_loade UHD_STATIC_BLOCK(register_octoclock_image_loader){ std::string recovery_instructions = "Aborting. Your OctoClock firmware is now corrupt. The bootloader\n" - "is functional, but the device will not have functional clock distribution." + "is functional, but the device will not have functional clock distribution.\n" "Run this utility again to restore functionality or refer to:\n\n" "http://files.ettus.com/manual/page_octoclock.html\n\n" "for alternative setups."; 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..dc5913534 --- /dev/null +++ b/host/lib/usrp_clock/usrp_clock_c.cpp @@ -0,0 +1,189 @@ +/* + * 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_find_mutex; +uhd_error uhd_usrp_clock_find( + uhd_device_addrs_handle h, + const char* args, + size_t *num_found +){ + UHD_SAFE_C_SAVE_ERROR(h, + boost::mutex::scoped_lock lock(_usrp_clock_find_mutex); + + h->device_addrs_cpp = uhd::device::find(std::string(args), uhd::device::CLOCK); + *num_found = h->device_addrs_cpp.size(); + ) +} + +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..ac0486f2e 100644 --- a/host/tests/CMakeLists.txt +++ b/host/tests/CMakeLists.txt @@ -53,6 +53,17 @@ 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 + device_addrs_c_test.c + 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/convert_test.cpp b/host/tests/convert_test.cpp index 8ef1e74cc..d71d756dd 100644 --- a/host/tests/convert_test.cpp +++ b/host/tests/convert_test.cpp @@ -415,3 +415,43 @@ BOOST_AUTO_TEST_CASE(test_convert_types_sc16_and_sc8){ test_convert_types_sc16(nsamps, id, 256); } } + +/*********************************************************************** + * Test short conversion + **********************************************************************/ +static void test_convert_types_u8( + size_t nsamps, convert::id_type &id +){ + //fill the input samples + std::vector<boost::uint8_t> input(nsamps), output(nsamps); + //BOOST_FOREACH(boost::uint8_t &in, input) in = boost::uint8_t(std::rand() & 0xFF); + boost::uint32_t d = 48; + BOOST_FOREACH(boost::uint8_t &in, input) in = d++; + + //run the loopback and test + convert::id_type in_id = id; + convert::id_type out_id = id; + std::swap(out_id.input_format, out_id.output_format); + std::swap(out_id.num_inputs, out_id.num_outputs); + loopback(nsamps, in_id, out_id, input, output); + BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} + +BOOST_AUTO_TEST_CASE(test_convert_types_u8_and_u8){ + convert::id_type id; + id.input_format = "u8"; + id.num_inputs = 1; + id.num_outputs = 1; + + //try various lengths to test edge cases + id.output_format = "u8_item32_le"; + for (size_t nsamps = 1; nsamps < 16; nsamps++){ + test_convert_types_u8(nsamps, id); + } + + //try various lengths to test edge cases + id.output_format = "u8_item32_be"; + for (size_t nsamps = 1; nsamps < 16; nsamps++){ + test_convert_types_u8(nsamps, id); + } +} diff --git a/host/tests/device_addrs_c_test.c b/host/tests/device_addrs_c_test.c new file mode 100644 index 000000000..e84068a75 --- /dev/null +++ b/host/tests/device_addrs_c_test.c @@ -0,0 +1,90 @@ +// +// 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_device_addrs_handle device_addrs; + size_t size; + char str_buffer[BUFFER_SIZE]; + + return_code = EXIT_SUCCESS; + + // Create device_addrs + UHD_TEST_EXECUTE_OR_GOTO(end_of_test, + uhd_device_addrs_make(&device_addrs) + ) + + // Add values + UHD_TEST_EXECUTE_OR_GOTO(free_device_addrs, + uhd_device_addrs_push_back(device_addrs, "key1=value1,key2=value2") + ) + UHD_TEST_EXECUTE_OR_GOTO(free_device_addrs, + uhd_device_addrs_push_back(device_addrs, "key3=value3,key4=value4") + ) + + // Check size + UHD_TEST_EXECUTE_OR_GOTO(free_device_addrs, + uhd_device_addrs_size(device_addrs, &size) + ) + if(size != 2){ + return_code = EXIT_FAILURE; + fprintf(stderr, "%s:%d: Invalid size: %lu vs. 2", + __FILE__, __LINE__,size); + goto free_device_addrs; + } + + // Make sure we get right value + UHD_TEST_EXECUTE_OR_GOTO(free_device_addrs, + uhd_device_addrs_at(device_addrs, 1, str_buffer, BUFFER_SIZE) + ) + if(strcmp(str_buffer, "key3=value3,key4=value4")){ + return_code = EXIT_FAILURE; + fprintf(stderr, "%s:%d: Mismatched daughterboard serial: \"%s\" vs. \"key3=value3,key4=value4\"\n", + __FILE__, __LINE__, + str_buffer); + } + + free_device_addrs: + if(return_code){ + uhd_device_addrs_last_error(device_addrs, str_buffer, BUFFER_SIZE); + fprintf(stderr, "device_addrs error: %s\n", str_buffer); + } + uhd_device_addrs_free(&device_addrs); + + end_of_test: + if(!return_code){ + printf("\nNo errors detected\n"); + } + return return_code; +} diff --git a/host/tests/eeprom_c_test.c b/host/tests/eeprom_c_test.c new file mode 100644 index 000000000..1b29dfd44 --- /dev/null +++ b/host/tests/eeprom_c_test.c @@ -0,0 +1,157 @@ +// +// 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); + } + uhd_dboard_eeprom_free(&db_eeprom); + + 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); + } + uhd_mboard_eeprom_free(&mb_eeprom); + + 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; +} diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 530bcf087..06bee48cd 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -34,11 +34,11 @@ SET(x3xx_burner_sources ) find_package(UDev) -IF(ENABLE_E300) +IF(ENABLE_E300 AND NOT E300_FORCE_NETWORK) IF(UDEV_FOUND) LIST(APPEND util_runtime_sources usrp_e3x0_network_mode.cpp) ENDIF(UDEV_FOUND) -ENDIF(ENABLE_E300) +ENDIF(ENABLE_E300 AND NOT E300_FORCE_NETWORK) #for each source: build an executable and install FOREACH(util_source ${util_runtime_sources}) diff --git a/host/utils/b2xx_side_channel.py b/host/utils/b2xx_side_channel.py index 7b1e980eb..070f5684c 100755 --- a/host/utils/b2xx_side_channel.py +++ b/host/utils/b2xx_side_channel.py @@ -16,25 +16,27 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # +""" +Tool to read log buffers from the FX3. Use to debug USB connection issues. +Requires PyUSB 1.0. +""" import sys import time import struct - from optparse import OptionParser +import serial try: import usb.core import usb.util except Exception as e: - print "Failed to import module 'usb'." - print "Please make sure you have PyUSB installed and in your PYTHONPATH." - print "PyUSB PyPI website: https://pypi.python.org/pypi/pyusb" - print "To install, download from the website or use 'pip install pysusb'" + print("Failed to import module 'usb'.") + print("Please make sure you have PyUSB installed and in your PYTHONPATH.") + print("PyUSB PyPI website: https://pypi.python.org/pypi/pyusb") + print("To install, download from the website or use 'pip install pyusb'") exit(1) -import serial - VRT_OUT = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_OUT VRT_IN = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_IN @@ -62,7 +64,7 @@ VRQS[B200_VREQ_FLUSH_DATA_EPS] = 'B200_VREQ_FLUSH_DATA_EPS' B200_VREQ_AD9361_LOOPBACK = 0x92 VRQS[B200_VREQ_AD9361_LOOPBACK] = 'B200_VREQ_AD9361_LOOPBACK' -COUNTER_MAGIC = 0x10024001 +COUNTER_MAGIC = 0x10024001 """ typedef struct Counters { int magic; @@ -162,6 +164,10 @@ USB_PHY_ERROR_REGISTERS = [ USB_ERROR_COUNTERS += USB_PHY_ERROR_REGISTERS +PIB_COUNTERS = [ + 'socket_inactive' +] + COUNTERS = [ 'magic', @@ -177,7 +183,13 @@ COUNTERS = [ 'heap_size', - 'resume_count' + 'resume_count', + 'state_transition_count', + 'invalid_gpif_state', + ('thread_0', PIB_COUNTERS), + ('thread_1', PIB_COUNTERS), + ('thread_2', PIB_COUNTERS), + ('thread_3', PIB_COUNTERS), ] USB_EVENTS = {} @@ -243,6 +255,101 @@ LTSSM_STATES[0x1c] = ['111XX', "(none)"] LTSSM_STATES[0x1f] = ['111XX', "(none)"] LTSSM_STATES[0x2c] = ['101100', "Cypress/Intel workaround"] +CF_NONE = 0 +CF_TX_SWING = 1 << 0 +CF_TX_DEEMPHASIS = 1 << 1 +CF_DISABLE_USB2 = 1 << 2 +CF_ENABLE_AS_SUPERSPEED = 1 << 3 +CF_PPORT_DRIVE_STRENGTH = 1 << 4 +CF_DMA_BUFFER_SIZE = 1 << 5 +CF_DMA_BUFFER_COUNT = 1 << 6 +CF_MANUAL_DMA = 1 << 7 +CF_SB_BAUD_DIV = 1 << 8 + +CF_RE_ENUM = 1 << 31 + +""" +typedef struct Config { + int tx_swing; // [90] [65] 45 + int tx_deemphasis; // 0x11 + int disable_usb2; // 0 + int enable_as_superspeed; // 1 + int pport_drive_strength; // CY_U3P_DS_THREE_QUARTER_STRENGTH + int dma_buffer_size; // [USB3] (max) + int dma_buffer_count; // [USB3] 1 + int manual_dma; // 0 + int sb_baud_div; // 434*2 +} CONFIG, *PCONFIG; + +typedef struct ConfigMod { + int flags; + CONFIG config; +} CONFIG_MOD, *PCONFIG_MOD; +""" + +class Config(): + def __init__(self, + tx_swing=None, tx_deemphasis=None, disable_usb2=None, enable_as_superspeed=None, + pport_drive_strength=None, + dma_buffer_size=None, dma_buffer_count=None, manual_dma=None, + sb_baud_div=None, + raw=None): + self.tx_swing = tx_swing + self.tx_deemphasis = tx_deemphasis + self.disable_usb2 = disable_usb2 + self.enable_as_superspeed = enable_as_superspeed + self.pport_drive_strength = pport_drive_strength + self.dma_buffer_size = dma_buffer_size + self.dma_buffer_count = dma_buffer_count + self.manual_dma = manual_dma + self.sb_baud_div = sb_baud_div + self._count = 9 + + if raw: + (self.tx_swing, + self.tx_deemphasis, + self.disable_usb2, + self.enable_as_superspeed, + self.pport_drive_strength, + self.dma_buffer_size, + self.dma_buffer_count, + self.manual_dma, + self.sb_baud_div) = struct.unpack("i"*self._count, raw) + def pack(self): + return struct.pack("i"*self._count, + self.tx_swing, + self.tx_deemphasis, + self.disable_usb2, + self.enable_as_superspeed, + self.pport_drive_strength, + self.dma_buffer_size, + self.dma_buffer_count, + self.manual_dma, + self.sb_baud_div) + def __str__(self): + return self.to_string() + def to_string(self, flags=-1): + s = "" + if flags & CF_TX_SWING: + s += "tx_swing = %s\n" % (self.tx_swing) + if flags & CF_TX_DEEMPHASIS: + s += "tx_deemphasis = %s\n" % (self.tx_deemphasis) + if flags & CF_DISABLE_USB2: + s += "disable_usb2 = %s\n" % (self.disable_usb2) + if flags & CF_ENABLE_AS_SUPERSPEED: + s += "enable_as_superspeed = %s\n" % (self.enable_as_superspeed) + if flags & CF_PPORT_DRIVE_STRENGTH: + s += "pport_drive_strength = %s\n" % (self.pport_drive_strength) + if flags & CF_DMA_BUFFER_SIZE: + s += "dma_buffer_size = %s\n" % (self.dma_buffer_size) + if flags & CF_DMA_BUFFER_COUNT: + s += "dma_buffer_count = %s\n" % (self.dma_buffer_count) + if flags & CF_MANUAL_DMA: + s += "manual_dma = %s\n" % (self.manual_dma) + if flags & CF_SB_BAUD_DIV: + s += "sb_baud_div = %s\n" % (self.sb_baud_div) + return s + def _parse_usb_event_log(data): l = [] for d in data: @@ -252,11 +359,11 @@ def _parse_usb_event_log(data): #l += [(USB_EVENTS[0x80][0] + "+%i" % (d & ~0x80), USB_EVENTS[0x80][1])] ltssm_key = (d & ~0x80) ltssm_val = "(unknown)" - if LTSSM_STATES.has_key(ltssm_key): + if ltssm_key in LTSSM_STATES: ltssm_val = LTSSM_STATES[ltssm_key][1] ltssm_val = "LTSSM: " + ltssm_val l += [(USB_EVENTS[0x80][0] + "+%i" % (d & ~0x80), ltssm_val)] - elif USB_EVENTS.has_key(d): + elif d in USB_EVENTS: l += [USB_EVENTS[d]] #else: # l += [("?", "?")] @@ -313,8 +420,8 @@ class counter_set(): try: vals = struct.unpack(self._fmt_str, data) self._update(vals) - except Exception, e: - print e + except Exception as e: + print(("While updating counter set '%s':" % self._name), e) def __str__(self): return self.to_string() @@ -346,7 +453,7 @@ class usb_device(): self.timeout = 2000 def open(self, idVendor, idProduct): - print "Finding %04x:%04x..." % (idVendor, idProduct) + print("Finding %04x:%04x..." % (idVendor, idProduct)) self.dev = usb.core.find(idVendor=idVendor, idProduct=idProduct) if self.dev is None: raise ValueError('Device not found: %04x:%04x' % (idVendor, idProduct)) @@ -362,7 +469,7 @@ class usb_device(): #self.dev.set_configuration() # This will throw as device is already claimed - print "Opened %04x:%04x" % (idVendor, idProduct) + print("Opened %04x:%04x" % (idVendor, idProduct)) #self.dev.ctrl_transfer(0x21, 0x09, 0, 0, [0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00] ) #self.dev.ctrl_transfer(bmRequestType, bRequest, wValue=0, wIndex=0, data_or_wLength = None, timeout = None @@ -379,40 +486,41 @@ class usb_device(): l = [] try: l = self.dev.ctrl_transfer(VRT_IN, B200_VREQ_GET_USB_SPEED, 0, 0, 1) - except usb.core.USBError, e: + except usb.core.USBError as e: if e.errno == 32: - print e + print(e) + print("Is the firmware loaded?") sys.exit(0) if len(l) > 0: self.usb_speed = l[0] - print "Operating at USB", self.usb_speed + print("Operating at USB", self.usb_speed) break else: - print "Retrying..." + print("Retrying...") #if self.usb_speed == 3: # self.max_buffer_size = 512 - print "Max buffer size:", self.max_buffer_size - print + print("Max buffer size:", self.max_buffer_size) + print() def _handle_error(self, e, vrt): if e.errno == 19: # No such device raise e vrt_str = "0x%02x" % (vrt) - if VRQS.has_key(vrt): + if vrt in VRQS: vrt_str += " (%s)" % (VRQS[vrt]) - print "%s: %s" % (vrt_str, str(e)) + print("%s: %s" % (vrt_str, str(e))) def vrt_get(self, vrt): try: return self.dev.ctrl_transfer(VRT_IN, vrt, 0, 0, self.max_buffer_size, self.timeout) - except usb.core.USBError, e: + except usb.core.USBError as e: self._handle_error(e, vrt) return [] def vrt_set(self, vrt, data=""): try: return self.dev.ctrl_transfer(VRT_OUT, vrt, 0, 0, data, self.timeout) - except usb.core.USBError, e: + except usb.core.USBError as e: self._handle_error(e, vrt) return None @@ -428,7 +536,11 @@ class usb_device(): last = 0 while raw[last] != 0: try: - idx = raw.index(0, last) + try: + idx = raw.index(0, last) + except ValueError as e: + print("No null termination in log buffer (length: %d, last null: %d)" % (len(raw), last)) + break self.log_index += 1 line = "".join(map(chr, raw[last:idx])) #print "[%05i %05i] %s" % (self.log_index, self.log_read_count, line) @@ -439,8 +551,8 @@ class usb_device(): last = idx + 1 if last >= len(raw): break - except Exception, e: - print e + except Exception as e: + print("Exception while parsing log buffer:", e) break return lines @@ -450,8 +562,8 @@ class usb_device(): return for l in lines: #print l - print "[%05i %05i] %s" % (l[0], self.log_read_count, l[1]) - print + print("[%05i %05i] %s" % (l[0], self.log_read_count, l[1])) + print() def get_counters(self): data = self.vrt_get(B200_VREQ_GET_COUNTERS) @@ -462,8 +574,8 @@ class usb_device(): def print_counters(self): self.get_counters() - print "[%05i]" % (self.counters_read_count) - print self.counters + print("[%05i]" % (self.counters_read_count)) + print(self.counters) def get_usb_event_log(self): data = self.vrt_get(B200_VREQ_GET_USB_EVENT_LOG) @@ -480,8 +592,8 @@ class usb_device(): l = self.get_usb_event_log() if len(l) == 0: return - print "\n".join(map(lambda x: ("[%05i] " % (self.usb_event_log_read_count)) + x[0] + ":\t" + x[1], l)) - print + print("\n".join([("[%05i] " % (self.usb_event_log_read_count)) + x[0] + ":\t" + x[1] for x in l])) + print() def run_log(dev, options): items = [ @@ -489,8 +601,8 @@ def run_log(dev, options): (options.counters, dev.print_counters), (options.usb_events, dev.print_usb_event_log) ] - items = filter(lambda x: x[0] > 0, items) - smallest_interval = min(map(lambda x: x[0], items)) + items = [x for x in items if x[0] > 0] + smallest_interval = min([x[0] for x in items]) time_now = time.time() last = [time_now]*len(items) @@ -506,7 +618,7 @@ def run_log(dev, options): if time_now < (time_last + items[i][0]): continue if options.clear_screen and not cleared: - print chr(27) + "[2J" + print(chr(27) + "[2J") cleared = True #print items[i][1] items[i][1]() @@ -535,9 +647,9 @@ def recv_serial_data(ser): data = data[0:-2] if data == "": #print "[Received an empty line]" - print + print() elif data[0] == ' ': - print time_now_str, data[1:] + print(time_now_str, data[1:]) elif data[0] == 'U': data = data[1:] cur_type = 0 @@ -553,20 +665,20 @@ def recv_serial_data(ser): i = ord(c) - ord('A') cur_type = 2 else: - print time_now_str, "[Unknown type: '%s' (0x%02x) in '%s']" % (c, ord(c), data) + print(time_now_str, "[Unknown type: '%s' (0x%02x) in '%s']" % (c, ord(c), data)) elif cur_type == 1: i = ord(c) - ord('a') if (i < 0) or (i >= len(USB_PHY_ERROR_REGISTERS)): - print time_now_str, "[Unknown PHY error register index: '%s' (0x%02x) (%d) in '%s']" % (c, ord(c), i, data) + print(time_now_str, "[Unknown PHY error register index: '%s' (0x%02x) (%d) in '%s']" % (c, ord(c), i, data)) else: - print time_now_str, USB_PHY_ERROR_REGISTERS[i] + print(time_now_str, USB_PHY_ERROR_REGISTERS[i]) cur_type = 0 elif cur_type == 2: i2 = ord(c) - ord('A') if (c < 'A') or (c > 'P'): - print time_now_str, "[Unknown second USB event part: '%s' (0x%02x) (%d) in '%s']" % (c, ord(c), i2, data) + print(time_now_str, "[Unknown second USB event part: '%s' (0x%02x) (%d) in '%s']" % (c, ord(c), i2, data)) else: i = (i << 4) | i2 usb_events += [i] @@ -578,11 +690,14 @@ def recv_serial_data(ser): if len(usb_events) > 0: usb_event_log_read_count += 1 l = _parse_usb_event_log(usb_events) - print "\n".join(map(lambda x: time_now_str + ("[%05i] " % (usb_event_log_read_count)) + x[0] + ":\t" + x[1], l)) + print("\n".join([time_now_str + ("[%05i] " % (usb_event_log_read_count)) + x[0] + ":\t" + x[1] for x in l])) + #print + data = "" def main(): parser = OptionParser(usage="%prog: [options]") #option_class=eng_option, + parser.add_option("-v", "--vid", type="string", default="0x2500", help="VID [default=%default]") parser.add_option("-p", "--pid", type="string", default="0x0020", help="PID [default=%default]") parser.add_option("-t", "--tty", type="string", default=None, help="TTY [default=%default]") @@ -597,26 +712,34 @@ def main(): parser.add_option("-R", "--reset-counters", action="store_true", default=False, help="Reset counters [default=%default]") parser.add_option("-f", "--flush-data-eps", action="store_true", default=False, help="Flush data endpoints [default=%default]") parser.add_option("-L", "--fe-loopback", type="int", default=None, help="Change AD9361 digital loopback [default=%default]") + (options, args) = parser.parse_args() if options.tty is not None and options.tty != "": while True: try: ser = serial.Serial(port=options.tty, baudrate=115200, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=None) # timeout: None (blocking), 0 (non-blocking) - print "Opened", options.tty + print("Opened", options.tty) + try: recv_serial_data(ser) except KeyboardInterrupt: break except Exception as e: - print e + print("Unable to open serial port:", e) break else: dev = usb_device() + while True: try: dev.open(idVendor=hex_to_int(options.vid), idProduct=hex_to_int(options.pid)) + raw_config = dev.vrt_get(B200_VREQ_GET_CONFIG) + current_config = Config(raw=raw_config) + print("Current config:") + print(current_config) + if options.flush_data_eps: dev.vrt_set(B200_VREQ_FLUSH_DATA_EPS) if options.sb_baud_div is not None: @@ -627,17 +750,68 @@ def main(): dev.vrt_set(B200_VREQ_CLEAR_COUNTERS) if options.fe_loopback is not None: dev.vrt_set(B200_VREQ_AD9361_LOOPBACK, struct.pack('B', int(options.fe_loopback))) + options.cmd = options.cmd.strip() if len(options.cmd) == 0: run_log(dev, options) - pass else: - pass + cmds = options.cmd.split(',') + flags = 0 + for cmd in cmds: + cmd = cmd.strip() + if len(cmd) == 0: + continue + parts = cmd.split(' ') + action = parts[0].lower() + try: + if action == "txswing": + current_config.tx_swing = int(parts[1]) + flags |= CF_TX_SWING + elif action == "txdeemph": + current_config.tx_deemphasis = int(parts[1]) + flags |= CF_TX_DEEMPHASIS + elif action == "ss": + current_config.enable_as_superspeed = int(parts[1]) + flags |= CF_ENABLE_AS_SUPERSPEED + elif action == "disableusb2": + current_config.disable_usb2 = int(parts[1]) + flags |= CF_DISABLE_USB2 + elif action == "pportdrive": + current_config.pport_drive_strength = int(parts[1]) + flags |= CF_PPORT_DRIVE_STRENGTH + elif action == "dmasize": + current_config.dma_buffer_size = int(parts[1]) + flags |= CF_DMA_BUFFER_SIZE + elif action == "dmacount": + current_config.dma_buffer_count = int(parts[1]) + flags |= CF_DMA_BUFFER_COUNT + elif action == "manualdma": + current_config.manual_dma = int(parts[1]) + flags |= CF_MANUAL_DMA + elif action == "sbbauddiv": + current_config.sb_baud_div = int(parts[1]) + flags |= CF_SB_BAUD_DIV + elif action == "reenum": + flags |= CF_RE_ENUM + else: + print("'%s' not implemented" % (action)) + except Exception as e: + print("Exception while handling action '%s'" % (action), e) + if flags != 0: + print("New config to be set:") + print(current_config.to_string(flags)) + #print current_config + #print "Update flags: 0x%x" % (flags) + new_config = struct.pack("I", flags) + current_config.pack() + dev.vrt_set(B200_VREQ_SET_CONFIG, new_config) + else: + print("Not updating config") break except usb.core.USBError as e: if e.errno == 19: # No such device pass - print e + print(e) break + return 0 if __name__ == '__main__': diff --git a/host/utils/uhd-usrp.rules b/host/utils/uhd-usrp.rules index 2f5198d64..10d68a290 100644 --- a/host/utils/uhd-usrp.rules +++ b/host/utils/uhd-usrp.rules @@ -1,5 +1,5 @@ # -# Copyright 2011 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,3 +23,5 @@ SUBSYSTEMS=="usb", ATTRS{idVendor}=="2500", ATTRS{idProduct}=="0002", MODE:="066 #B200 SUBSYSTEMS=="usb", ATTRS{idVendor}=="2500", ATTRS{idProduct}=="0020", MODE:="0666" +SUBSYSTEMS=="usb", ATTRS{idVendor}=="3923", ATTRS{idProduct}=="7813", MODE:="0666" +SUBSYSTEMS=="usb", ATTRS{idVendor}=="3923", ATTRS{idProduct}=="7814", MODE:="0666" diff --git a/host/utils/uhd_image_loader.cpp b/host/utils/uhd_image_loader.cpp index 39efc8f1e..5ea789ee2 100644 --- a/host/utils/uhd_image_loader.cpp +++ b/host/utils/uhd_image_loader.cpp @@ -91,6 +91,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ image_loader_args.firmware_path = vm["fw-path"].as<std::string>(); image_loader_args.fpga_path = vm["fpga-path"].as<std::string>(); + // Force user to specify a device + if(not image_loader_args.args.has_key("type")){ + throw uhd::runtime_error("You must specify a device type."); + } + // Clean up paths, if given if(image_loader_args.firmware_path != ""){ #ifndef UHD_PLATFORM_WIN32 diff --git a/tools/b200/b2x0_side_channel.py b/tools/b200/b2x0_side_channel.py deleted file mode 100755 index cf88bd35f..000000000 --- a/tools/b200/b2x0_side_channel.py +++ /dev/null @@ -1,650 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright 2013-2014 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/>. -# -""" -Tool to read log buffers from the FX3. Use to debug USB connection issues. -Requires PyUSB 1.0. -""" - -import sys -import time -import struct -from optparse import OptionParser -import serial - -try: - import usb.core - import usb.util -except Exception as e: - print "Failed to import usb - please have pyusb in your PYTHONPATH" - raise e - -VRT_OUT = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_OUT -VRT_IN = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_IN - -VRQS = {} -B200_VREQ_GET_LOG = 0x23 -VRQS[B200_VREQ_GET_LOG] = 'B200_VREQ_GET_LOG' -B200_VREQ_GET_COUNTERS = 0x24 -VRQS[B200_VREQ_GET_COUNTERS] = 'B200_VREQ_GET_COUNTERS' -B200_VREQ_CLEAR_COUNTERS = 0x25 -VRQS[B200_VREQ_CLEAR_COUNTERS] = 'B200_VREQ_CLEAR_COUNTERS' -B200_VREQ_GET_USB_EVENT_LOG = 0x26 -VRQS[B200_VREQ_GET_USB_EVENT_LOG] = 'B200_VREQ_GET_USB_EVENT_LOG' -B200_VREQ_SET_CONFIG = 0x27 -VRQS[B200_VREQ_SET_CONFIG] = 'B200_VREQ_SET_CONFIG' -B200_VREQ_GET_CONFIG = 0x28 -VRQS[B200_VREQ_GET_CONFIG] = 'B200_VREQ_GET_CONFIG' -B200_VREQ_GET_USB_SPEED = 0x80 -VRQS[B200_VREQ_GET_USB_SPEED] ='B200_VREQ_GET_USB_SPEED' -B200_VREQ_WRITE_SB = 0x29 -VRQS[B200_VREQ_WRITE_SB] = 'B200_VREQ_WRITE_SB' -B200_VREQ_SET_SB_BAUD_DIV = 0x30 -VRQS[B200_VREQ_SET_SB_BAUD_DIV] = 'B200_VREQ_SET_SB_BAUD_DIV' -B200_VREQ_FLUSH_DATA_EPS = 0x31 -VRQS[B200_VREQ_FLUSH_DATA_EPS] = 'B200_VREQ_FLUSH_DATA_EPS' -B200_VREQ_AD9361_LOOPBACK = 0x92 -VRQS[B200_VREQ_AD9361_LOOPBACK] = 'B200_VREQ_AD9361_LOOPBACK' - -COUNTER_MAGIC = 0x10024001 -""" -typedef struct Counters { - int magic; - - DMA_COUNTERS dma_to_host; - DMA_COUNTERS dma_from_host; - - int log_overrun_count; - - int usb_error_update_count; - USB_ERROR_COUNTERS usb_error_counters; - - int usb_ep_underrun_count; - - int heap_size; -} COUNTERS, *PCOUNTERS; - -typedef struct USBErrorCounters { - int phy_error_count; - int link_error_count; - - int PHY_LOCK_EV; - int TRAINING_ERROR_EV; - int RX_ERROR_CRC32_EV; - int RX_ERROR_CRC16_EV; - int RX_ERROR_CRC5_EV; - int PHY_ERROR_DISPARITY_EV; - int PHY_ERROR_EB_UND_EV; - int PHY_ERROR_EB_OVR_EV; - int PHY_ERROR_DECODE_EV; -} USB_ERROR_COUNTERS, *PUSB_ERROR_COUNTERS; - -typedef struct DMACounters { - int XFER_CPLT; - int SEND_CPLT; - int RECV_CPLT; - int PROD_EVENT; - int CONS_EVENT; - int ABORTED; - int ERROR; - int PROD_SUSP; - int CONS_SUSP; - - int BUFFER_MARKER; - int BUFFER_EOP; - int BUFFER_ERROR; - int BUFFER_OCCUPIED; - - int last_count; - int last_size; - - int last_sid; - int bad_sid_count; - - int resume_count; -} DMA_COUNTERS, *PDMA_COUNTERS; -""" -DMA_COUNTERS = [ - 'XFER_CPLT', - 'SEND_CPLT', - 'RECV_CPLT', - 'PROD_EVENT', - 'CONS_EVENT', - 'ABORTED', - 'ERROR', - 'PROD_SUSP', - 'CONS_SUSP', - - 'BUFFER_MARKER', - 'BUFFER_EOP', - 'BUFFER_ERROR', - 'BUFFER_OCCUPIED', - - 'last_count', - 'last_size', - - 'last_sid', - 'bad_sid_count' -] - -USB_ERROR_COUNTERS = [ - 'phy_error_count', - 'link_error_count' -] - -USB_PHY_ERROR_REGISTERS = [ - 'PHY_LOCK_EV', - 'TRAINING_ERROR_EV', - 'RX_ERROR_CRC32_EV', - 'RX_ERROR_CRC16_EV', - 'RX_ERROR_CRC5_EV', - 'PHY_ERROR_DISPARITY_EV', - 'PHY_ERROR_EB_UND_EV', - 'PHY_ERROR_EB_OVR_EV', - 'PHY_ERROR_DECODE_EV' -] - -USB_ERROR_COUNTERS += USB_PHY_ERROR_REGISTERS - -COUNTERS = [ - 'magic', - - ('dma_to_host', DMA_COUNTERS), - ('dma_from_host', DMA_COUNTERS), - - 'log_overrun_count', - - 'usb_error_update_count', - ('usb_error_counters', USB_ERROR_COUNTERS), - - 'usb_ep_underrun_count', - - 'heap_size', - - 'resume_count' -] - -USB_EVENTS = {} -USB_EVENTS[0x01] = ('CYU3P_USB_LOG_VBUS_OFF' , 'Indicates VBus turned off.') -USB_EVENTS[0x02] = ('CYU3P_USB_LOG_VBUS_ON' , 'Indicates VBus turned on.') -USB_EVENTS[0x03] = ('CYU3P_USB_LOG_USB2_PHY_OFF' , 'Indicates that the 2.0 PHY has been turned off.') -USB_EVENTS[0x04] = ('CYU3P_USB_LOG_USB3_PHY_OFF' , 'Indicates that the 3.0 PHY has been turned off.') -USB_EVENTS[0x05] = ('CYU3P_USB_LOG_USB2_PHY_ON' , 'Indicates that the 2.0 PHY has been turned on.') -USB_EVENTS[0x06] = ('CYU3P_USB_LOG_USB3_PHY_ON' , 'Indicates that the 3.0 PHY has been turned on.') -USB_EVENTS[0x10] = ('CYU3P_USB_LOG_USBSS_DISCONNECT' , 'Indicates that the USB 3.0 link has been disabled.') -USB_EVENTS[0x11] = ('CYU3P_USB_LOG_USBSS_RESET' , 'Indicates that a USB 3.0 reset (warm/hot) has happened.') -USB_EVENTS[0x12] = ('CYU3P_USB_LOG_USBSS_CONNECT' , 'Indicates that USB 3.0 Rx Termination has been detected.') -USB_EVENTS[0x14] = ('CYU3P_USB_LOG_USBSS_CTRL' , 'Indicates that a USB 3.0 control request has been received.') -USB_EVENTS[0x15] = ('CYU3P_USB_LOG_USBSS_STATUS' , 'Indicates completion of status stage for a 3.0 control request.') -USB_EVENTS[0x16] = ('CYU3P_USB_LOG_USBSS_ACKSETUP' , 'Indicates that the CyU3PUsbAckSetup API has been called.') -USB_EVENTS[0x21] = ('CYU3P_USB_LOG_LGO_U1' , 'Indicates that a LGO_U1 command has been received.') -USB_EVENTS[0x22] = ('CYU3P_USB_LOG_LGO_U2' , 'Indicates that a LGO_U2 command has been received.') -USB_EVENTS[0x23] = ('CYU3P_USB_LOG_LGO_U3' , 'Indicates that a LGO_U3 command has been received.') -USB_EVENTS[0x40] = ('CYU3P_USB_LOG_USB2_SUSP' , 'Indicates that a USB 2.0 suspend condition has been detected.') -USB_EVENTS[0x41] = ('CYU3P_USB_LOG_USB2_RESET' , 'Indicates that a USB 2.0 bus reset has been detected.') -USB_EVENTS[0x42] = ('CYU3P_USB_LOG_USB2_HSGRANT' , 'Indicates that the USB High-Speed handshake has been completed.') -USB_EVENTS[0x44] = ('CYU3P_USB_LOG_USB2_CTRL' , 'Indicates that a FS/HS control request has been received.') -USB_EVENTS[0x45] = ('CYU3P_USB_LOG_USB2_STATUS' , 'Indicates completion of status stage for a FS/HS control transfer.') -USB_EVENTS[0x50] = ('CYU3P_USB_LOG_USB_FALLBACK' , 'Indicates that the USB connection is dropping from 3.0 to 2.0') -USB_EVENTS[0x51] = ('CYU3P_USB_LOG_USBSS_ENABLE' , 'Indicates that a USB 3.0 connection is being attempted again.') -USB_EVENTS[0x52] = ('CYU3P_USB_LOG_USBSS_LNKERR' , 'The number of link errors has crossed the threshold.') -USB_EVENTS[0x80] = ('CYU3P_USB_LOG_LTSSM_CHG' , 'Base of values that indicate a USB 3.0 LTSSM state change.') - -LTSSM_STATES = {} -LTSSM_STATES[0x00] = ['00000', "SS.Disabled"] -LTSSM_STATES[0x01] = ['00001', "Rx.Detect.Reset"] -LTSSM_STATES[0x02] = ['00010', "Rx.Detect.Active"] -LTSSM_STATES[0x03] = ['00011', "Rx.Detect.Quiet"] -LTSSM_STATES[0x04] = ['00100', "SS.Inactive.Quiet"] -LTSSM_STATES[0x05] = ['00101', "SS.Inactive.Disconnect.Detect"] -LTSSM_STATES[0x06] = ['00110', "Hot Reset.Active"] -LTSSM_STATES[0x07] = ['00111', "Hot Reset.Exit"] -LTSSM_STATES[0x08] = ['01000', "Polling.LFPS"] -LTSSM_STATES[0x09] = ['01001', "Polling.RxEQ"] -LTSSM_STATES[0x0a] = ['01010', "Polling.Active"] -LTSSM_STATES[0x0b] = ['01011', "Polling.Configuration"] -LTSSM_STATES[0x0c] = ['01100', "Polling.Idle"] -LTSSM_STATES[0x0d] = ['01101', "(none)"] -#LTSSM_STATES[0x0X] = ['0111X', "(none)"] -LTSSM_STATES[0x0e] = ['0111X', "(none)"] -LTSSM_STATES[0x0f] = ['0111X', "(none)"] -LTSSM_STATES[0x10] = ['10000', "U0"] -LTSSM_STATES[0x11] = ['10001', "U1"] -LTSSM_STATES[0x12] = ['10010', "U2"] -LTSSM_STATES[0x13] = ['10011', "U3"] -LTSSM_STATES[0x14] = ['10100', "Loopback.Active"] -LTSSM_STATES[0x15] = ['10101', "Loopback.Exit"] -LTSSM_STATES[0x16] = ['10110', "(none)"] -LTSSM_STATES[0x17] = ['10111', "Compliance"] -LTSSM_STATES[0x18] = ['11000', "Recovery.Active"] -LTSSM_STATES[0x19] = ['11001', "Recovery.Configuration"] -LTSSM_STATES[0x1a] = ['11010', "Recovery.Idle"] -LTSSM_STATES[0x1b] = ['11011', "(none)"] -#LTSSM_STATES[0x1X] = ['111XX', "(none)"] -LTSSM_STATES[0x1c] = ['111XX', "(none)"] -LTSSM_STATES[0x1d] = ['111XX', "(none)"] -LTSSM_STATES[0x1c] = ['111XX', "(none)"] -LTSSM_STATES[0x1f] = ['111XX', "(none)"] -LTSSM_STATES[0x2c] = ['101100', "Cypress/Intel workaround"] - -def _parse_usb_event_log(data): - l = [] - for d in data: - if d == 0x14 or d == 0x15 or d == 0x16: # CTRL, STATUS, ACKSETUP - continue - elif (d & 0x80): - #l += [(USB_EVENTS[0x80][0] + "+%i" % (d & ~0x80), USB_EVENTS[0x80][1])] - ltssm_key = (d & ~0x80) - ltssm_val = "(unknown)" - if LTSSM_STATES.has_key(ltssm_key): - ltssm_val = LTSSM_STATES[ltssm_key][1] - ltssm_val = "LTSSM: " + ltssm_val - l += [(USB_EVENTS[0x80][0] + "+%i" % (d & ~0x80), ltssm_val)] - elif USB_EVENTS.has_key(d): - l += [USB_EVENTS[d]] - #else: - # l += [("?", "?")] - return l - -class counter_set(): - def __init__(self, counters, name='(top)'): - self._counters = counters - self._counter_names = [] - self._name = name - for c in counters: - o = 0 - default_value = False - if isinstance(c, str): - name = c - default_value = True - elif isinstance(c, tuple): - name = c[0] - o = counter_set(c[1]) - elif isinstance(c, dict): - raise Exception('Not implemented yet') - else: - raise Exception('Unknown counter format') - setattr(self, name, o) - self._counter_names += [(name, default_value)] - self._fmt_str = self._get_struct_format() - - def _get_struct_format(self): - fmt_str = "" - for name, default_value in self._counter_names: - if default_value: - fmt_str += "i" - else: - o = getattr(self, name) - fmt_str += o._get_struct_format() - return fmt_str - - def _update(self, data, parents=[]): - if len(data) == 0: - raise Exception('Ran out of data entering %s' % (self._name)) - #return [] - for name, default_value in self._counter_names: - if default_value: - if len(data) == 0: - raise Exception('Ran out of data setting %s in %s' % (name, self._name)) - setattr(self, name, data[0]) - data = data[1:] - else: - o = getattr(self, name) - data = o._update(data, parents+[self]) - return data - - def update(self, data): - try: - vals = struct.unpack(self._fmt_str, data) - self._update(vals) - except Exception, e: - print e - - def __str__(self): - return self.to_string() - - def to_string(self, parents=[]): - s = "" - cnt = 0 - for name, default_value in self._counter_names: - o = getattr(self, name) - if default_value: - if cnt > 0: - s += "\t" - s += "%s: %05i" % (name, o) - cnt += 1 - else: - if cnt > 0: - s += "\n" - s += "\t"*(len(parents) + 1) - s += o.to_string(parents+[self]) - cnt = 0 - s += "\n" - return s - -class usb_device(): - def __init__(self): - #self.max_buffer_size = 64 # Default to USB2 - self.max_buffer_size = 1024*4 # Apparently it'll frag bigger packets - self.counters = counter_set(COUNTERS) - self.timeout = 2000 - - def open(self, idVendor, idProduct): - print "Finding %04x:%04x..." % (idVendor, idProduct) - self.dev = usb.core.find(idVendor=idVendor, idProduct=idProduct) - if self.dev is None: - raise ValueError('Device not found: %04x:%04x' % (idVendor, idProduct)) - - self.log_index = 0 - self.log_read_count = 0 - self.usb_event_log_read_count = 0 - self.counters_read_count = 0 - - #if self.dev.is_kernel_driver_active(0): - # print "Detaching kernel driver..." - # self.dev.detach_kernel_driver(0) - - #self.dev.set_configuration() # This will throw as device is already claimed - - print "Opened %04x:%04x" % (idVendor, idProduct) - - #self.dev.ctrl_transfer(0x21, 0x09, 0, 0, [0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00] ) - #self.dev.ctrl_transfer(bmRequestType, bRequest, wValue=0, wIndex=0, data_or_wLength = None, timeout = None - - #res = self.dev.ctrl_transfer(VRT_IN, 0x83, 0, 0, 1024) - # Can give 1024 byte size for IN, result will be actual payload size - # Invalid VREQ results in usb.core.USBError 32 Pipe error - #print res - - #res = self.dev.ctrl_transfer(VRT_IN, B200_VREQ_GET_USB_SPEED, 0, 0, 1) - #self.usb_speed = res[0] - while True: - #l = self.vrt_get(B200_VREQ_GET_USB_SPEED) - l = [] - try: - l = self.dev.ctrl_transfer(VRT_IN, B200_VREQ_GET_USB_SPEED, 0, 0, 1) - except usb.core.USBError, e: - if e.errno == 32: - print e - sys.exit(0) - if len(l) > 0: - self.usb_speed = l[0] - print "Operating at USB", self.usb_speed - break - else: - print "Retrying..." - #if self.usb_speed == 3: - # self.max_buffer_size = 512 - print "Max buffer size:", self.max_buffer_size - print - - def _handle_error(self, e, vrt): - if e.errno == 19: # No such device - raise e - vrt_str = "0x%02x" % (vrt) - if VRQS.has_key(vrt): - vrt_str += " (%s)" % (VRQS[vrt]) - print "%s: %s" % (vrt_str, str(e)) - - def vrt_get(self, vrt): - try: - return self.dev.ctrl_transfer(VRT_IN, vrt, 0, 0, self.max_buffer_size, self.timeout) - except usb.core.USBError, e: - self._handle_error(e, vrt) - return [] - - def vrt_set(self, vrt, data=""): - try: - return self.dev.ctrl_transfer(VRT_OUT, vrt, 0, 0, data, self.timeout) - except usb.core.USBError, e: - self._handle_error(e, vrt) - return None - - def get_log(self, with_log_index=True): - lines = [] - raw = self.vrt_get(B200_VREQ_GET_LOG) - if len(raw) == 0: - return lines - if raw[0] == 0: - return lines - self.log_read_count += 1 - raw = list(raw) - last = 0 - while raw[last] != 0: - try: - idx = raw.index(0, last) - self.log_index += 1 - line = "".join(map(chr, raw[last:idx])) - #print "[%05i %05i] %s" % (self.log_index, self.log_read_count, line) - if with_log_index: - lines += [(self.log_index, line)] - else: - lines += [line] - last = idx + 1 - if last >= len(raw): - break - except Exception, e: - print e - break - return lines - - def print_log(self): - lines = self.get_log() - if len(lines) == 0: - return - for l in lines: - #print l - print "[%05i %05i] %s" % (l[0], self.log_read_count, l[1]) - print - - def get_counters(self): - data = self.vrt_get(B200_VREQ_GET_COUNTERS) - if len(data) == 0: - return - self.counters_read_count += 1 - self.counters.update(data) - - def print_counters(self): - self.get_counters() - print "[%05i]" % (self.counters_read_count) - print self.counters - - def get_usb_event_log(self): - data = self.vrt_get(B200_VREQ_GET_USB_EVENT_LOG) - if len(data) == 0: - return [] - if len(data) == self.max_buffer_size: # ZLP when no new events have been recorded - return [] - if len(data) > 64: - raise Exception("USB event log data len = %i" % (len(data))) - self.usb_event_log_read_count += 1 - return _parse_usb_event_log(data) - - def print_usb_event_log(self): - l = self.get_usb_event_log() - if len(l) == 0: - return - print "\n".join(map(lambda x: ("[%05i] " % (self.usb_event_log_read_count)) + x[0] + ":\t" + x[1], l)) - print - -def run_log(dev, options): - items = [ - (options.log, dev.print_log), - (options.counters, dev.print_counters), - (options.usb_events, dev.print_usb_event_log) - ] - items = filter(lambda x: x[0] > 0, items) - smallest_interval = min(map(lambda x: x[0], items)) - time_now = time.time() - last = [time_now]*len(items) - - try: - for i in items: - if i[0] < 0: - i[1]() - while True: - time_now = time.time() - cleared = False - for i in range(len(items)): - time_last = last[i] - if time_now < (time_last + items[i][0]): - continue - if options.clear_screen and not cleared: - print chr(27) + "[2J" - cleared = True - #print items[i][1] - items[i][1]() - last[i] = time.time() - time.sleep(smallest_interval) - except KeyboardInterrupt: - return - -def hex_to_int(s): - radix = 10 - s = s.lower() - if (len(s) > 1 and s[0] == 'x') or (len(s) > 2 and s[0:2] == "0x"): - radix = 16 - return int(s, radix) - -def recv_serial_data(ser): - data = "" - usb_event_log_read_count = 0 - time_start = time.time() - while True: - c = ser.read() - data += c - #if c == '\n': - if len(data) >= 2 and data[-2:] == "\r\n": - time_now_str = "[%06d]" % (int(time.time() - time_start)) - data = data[0:-2] - if data == "": - #print "[Received an empty line]" - print - elif data[0] == ' ': - print time_now_str, data[1:] - elif data[0] == 'U': - data = data[1:] - cur_type = 0 - i = 0 - usb_events = [] - while len(data) > 0: - c = data[0] - - if cur_type == 0: - if c == 'a': - cur_type = 1 - elif (c >= 'A') and (c <= 'P'): - i = ord(c) - ord('A') - cur_type = 2 - else: - print time_now_str, "[Unknown type: '%s' (0x%02x) in '%s']" % (c, ord(c), data) - - elif cur_type == 1: - i = ord(c) - ord('a') - if (i < 0) or (i >= len(USB_PHY_ERROR_REGISTERS)): - print time_now_str, "[Unknown PHY error register index: '%s' (0x%02x) (%d) in '%s']" % (c, ord(c), i, data) - else: - print time_now_str, USB_PHY_ERROR_REGISTERS[i] - cur_type = 0 - - elif cur_type == 2: - i2 = ord(c) - ord('A') - if (c < 'A') or (c > 'P'): - print time_now_str, "[Unknown second USB event part: '%s' (0x%02x) (%d) in '%s']" % (c, ord(c), i2, data) - else: - i = (i << 4) | i2 - usb_events += [i] - - cur_type = 0 - - data = data[1:] - - if len(usb_events) > 0: - usb_event_log_read_count += 1 - l = _parse_usb_event_log(usb_events) - print "\n".join(map(lambda x: time_now_str + ("[%05i] " % (usb_event_log_read_count)) + x[0] + ":\t" + x[1], l)) - #print - - data = "" - -def main(): - parser = OptionParser(usage="%prog: [options]") #option_class=eng_option, - - parser.add_option("-v", "--vid", type="string", default="0x2500", help="VID [default=%default]") - parser.add_option("-p", "--pid", type="string", default="0x0020", help="PID [default=%default]") - parser.add_option("-t", "--tty", type="string", default=None, help="TTY [default=%default]") - parser.add_option("-c", "--cmd", type="string", default="", help="Command (empty opens prompt)") - parser.add_option("-n", "--counters", type="float", default="5.0", help="Counter print interval [default=%default]") - parser.add_option("-l", "--log", type="float", default="0.25", help="Log print interval [default=%default]") - parser.add_option("-e", "--usb-events", type="float", default="0.25", help="USB event log print interval [default=%default]") - parser.add_option("-s", "--sb", type="string", default=None, help="Settings Bus write message [default=%default]") - parser.add_option("-d", "--sb-baud-div", type="int", default=None, help="Settings Bus baud rate divisor [default=%default]") - parser.add_option("-b", "--sb-baud", type="int", default=None, help="Settings Bus baud rate [default=%default]") - parser.add_option("-r", "--clear-screen", action="store_true", default=False, help="Clear screen [default=%default]") - parser.add_option("-R", "--reset-counters", action="store_true", default=False, help="Reset counters [default=%default]") - parser.add_option("-f", "--flush-data-eps", action="store_true", default=False, help="Flush data endpoints [default=%default]") - parser.add_option("-L", "--fe-loopback", type="int", default=None, help="Change AD9361 digital loopback [default=%default]") - - (options, args) = parser.parse_args() - - if options.tty is not None and options.tty != "": - while True: - try: - ser = serial.Serial(port=options.tty, baudrate=115200, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=None) # timeout: None (blocking), 0 (non-blocking) - print "Opened", options.tty - - try: - recv_serial_data(ser) - except KeyboardInterrupt: - break - except Exception, e: - print e - break - else: - dev = usb_device() - - while True: - try: - dev.open(idVendor=hex_to_int(options.vid), idProduct=hex_to_int(options.pid)) - if options.flush_data_eps: - dev.vrt_set(B200_VREQ_FLUSH_DATA_EPS) - if options.sb_baud_div is not None: - dev.vrt_set(B200_VREQ_SET_SB_BAUD_DIV, struct.pack('H', options.sb_baud_div)) - if options.sb is not None and len(options.sb) > 0: - dev.vrt_set(B200_VREQ_WRITE_SB, " " + options.sb) - if options.reset_counters: - dev.vrt_set(B200_VREQ_CLEAR_COUNTERS) - if options.fe_loopback is not None: - dev.vrt_set(B200_VREQ_AD9361_LOOPBACK, struct.pack('B', int(options.fe_loopback))) - if len(options.cmd) == 0: - run_log(dev, options) - pass - else: - pass - - break - except usb.core.USBError, e: - if e.errno == 19: # No such device - pass - print e - break - - return 0 - -if __name__ == '__main__': - main() diff --git a/tools/mega_fft/MegaFFT-3.7.grc b/tools/mega_fft/MegaFFT-3.7.grc index 500c7a8bb..be3b112d4 100644 --- a/tools/mega_fft/MegaFFT-3.7.grc +++ b/tools/mega_fft/MegaFFT-3.7.grc @@ -6,7 +6,7 @@ <key>options</key> <param> <key>author</key> - <value>Balint Seeber, Ettus Research</value> + <value>Ettus Research</value> </param> <param> <key>alias</key> diff --git a/tools/mega_fft/mega_fft.py b/tools/mega_fft/mega_fft.py index 8dab89f4f..571653d2f 100755 --- a/tools/mega_fft/mega_fft.py +++ b/tools/mega_fft/mega_fft.py @@ -1,8 +1,9 @@ #!/usr/bin/env python2 ################################################## # GNU Radio Python Flow Graph +# Copyright 2014 National Instruments +# # Title: Mega FFT -# Author: Balint Seeber, Ettus Research # Description: Standard edition, single-channel # Generated: Fri Jul 24 11:56:33 2015 ################################################## @@ -171,7 +172,7 @@ class mega_fft(grc_wxgui.top_block_gui): cpu_format="fc32", channels=range(1), ), - + ) if spec != "": self.src.set_subdev_spec(spec, 0) self.src.set_samp_rate(requested_sample_rate) @@ -217,7 +218,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -258,7 +259,7 @@ class mega_fft(grc_wxgui.top_block_gui): self.nb.GetPage(0).Add(self.fft_sink.win) def fft_sink_callback(x, y): self.set_clicked_freq(x) - + self.fft_sink.set_callback(fft_sink_callback) self.waterfall_sink = waterfallsink2.waterfall_sink_c( self.nb.GetPage(2).GetWin(), @@ -279,7 +280,7 @@ class mega_fft(grc_wxgui.top_block_gui): self.nb.GetPage(2).Add(self.waterfall_sink.win) def waterfall_sink_callback(x, y): self.set_clicked_freq(x) - + self.waterfall_sink.set_callback(waterfall_sink_callback) self._test_chooser = forms.button( parent=self.nb_test.GetPage(0).GetWin(), @@ -365,7 +366,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -410,7 +411,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -455,7 +456,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -562,7 +563,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -725,7 +726,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -769,7 +770,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -814,7 +815,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -859,7 +860,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -903,7 +904,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -948,7 +949,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -993,7 +994,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1038,7 +1039,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1083,7 +1084,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1159,7 +1160,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1334,7 +1335,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1417,7 +1418,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1485,7 +1486,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1598,7 +1599,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1671,7 +1672,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1714,7 +1715,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1759,7 +1760,7 @@ class mega_fft(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1784,23 +1785,23 @@ class mega_fft(grc_wxgui.top_block_gui): ################################################## # Connections ################################################## - self.connect((self.blks2_selector_0, 0), (self.wxgui_scopesink2_0, 0)) - self.connect((self.blks2_selector_0_0, 0), (self.blks2_selector_0, 0)) - self.connect((self.blks2_selector_0_0, 1), (self.blocks_complex_to_mag_0, 0)) - self.connect((self.blocks_argmax_xx_0, 1), (self.blocks_null_sink_0, 0)) - self.connect((self.blocks_argmax_xx_0, 0), (self.fft_max_idx_probe, 0)) - self.connect((self.blocks_complex_to_mag_0, 0), (self.blocks_float_to_complex_0, 1)) - self.connect((self.blocks_complex_to_mag_0, 0), (self.blocks_float_to_complex_0, 0)) - self.connect((self.blocks_float_to_complex_0, 0), (self.blks2_selector_0, 1)) - self.connect((self.blocks_max_xx_0, 0), (self.fft_max_lvl_probe, 0)) - self.connect((self.logpwrfft_x_0, 0), (self.blocks_argmax_xx_0, 0)) - self.connect((self.logpwrfft_x_0, 0), (self.blocks_max_xx_0, 0)) - self.connect((self.src, 0), (self.blocks_tag_debug_0, 0)) - self.connect((self.src, 0), (self.blks2_selector_0_0, 0)) - self.connect((self.src, 0), (self.fft_sink, 0)) - self.connect((self.src, 0), (self.waterfall_sink, 0)) - self.connect((self.src, 0), (self.probe_avg_mag, 0)) - self.connect((self.src, 0), (self.logpwrfft_x_0, 0)) + self.connect((self.blks2_selector_0, 0), (self.wxgui_scopesink2_0, 0)) + self.connect((self.blks2_selector_0_0, 0), (self.blks2_selector_0, 0)) + self.connect((self.blks2_selector_0_0, 1), (self.blocks_complex_to_mag_0, 0)) + self.connect((self.blocks_argmax_xx_0, 1), (self.blocks_null_sink_0, 0)) + self.connect((self.blocks_argmax_xx_0, 0), (self.fft_max_idx_probe, 0)) + self.connect((self.blocks_complex_to_mag_0, 0), (self.blocks_float_to_complex_0, 1)) + self.connect((self.blocks_complex_to_mag_0, 0), (self.blocks_float_to_complex_0, 0)) + self.connect((self.blocks_float_to_complex_0, 0), (self.blks2_selector_0, 1)) + self.connect((self.blocks_max_xx_0, 0), (self.fft_max_lvl_probe, 0)) + self.connect((self.logpwrfft_x_0, 0), (self.blocks_argmax_xx_0, 0)) + self.connect((self.logpwrfft_x_0, 0), (self.blocks_max_xx_0, 0)) + self.connect((self.src, 0), (self.blocks_tag_debug_0, 0)) + self.connect((self.src, 0), (self.blks2_selector_0_0, 0)) + self.connect((self.src, 0), (self.fft_sink, 0)) + self.connect((self.src, 0), (self.waterfall_sink, 0)) + self.connect((self.src, 0), (self.probe_avg_mag, 0)) + self.connect((self.src, 0), (self.logpwrfft_x_0, 0)) def get_antenna(self): diff --git a/tools/mega_fft/mega_fft_2ch.py b/tools/mega_fft/mega_fft_2ch.py index c8a74bc26..32543cf6e 100755 --- a/tools/mega_fft/mega_fft_2ch.py +++ b/tools/mega_fft/mega_fft_2ch.py @@ -1,8 +1,9 @@ #!/usr/bin/env python2 ################################################## # GNU Radio Python Flow Graph +# Copyright 2014 National Instruments +# # Title: Mega FFT -# Author: Balint Seeber, Ettus Research # Description: Standard edition, dual-channel # Generated: Sun Jul 26 20:09:53 2015 ################################################## @@ -174,7 +175,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): cpu_format="fc32", channels=range(2), ), - + ) if spec != "": self.src.set_subdev_spec(spec, 0) self.src.set_samp_rate(requested_sample_rate) @@ -222,7 +223,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -263,7 +264,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): self.nb.GetPage(0).Add(self.fft_sink.win) def fft_sink_callback(x, y): self.set_clicked_freq(x) - + self.fft_sink.set_callback(fft_sink_callback) self.waterfall_sink = waterfallsink2.waterfall_sink_c( self.nb.GetPage(2).GetWin(), @@ -284,7 +285,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): self.nb.GetPage(2).Add(self.waterfall_sink.win) def waterfall_sink_callback(x, y): self.set_clicked_freq(x) - + self.waterfall_sink.set_callback(waterfall_sink_callback) self._test_chooser = forms.button( parent=self.nb_test.GetPage(0).GetWin(), @@ -380,7 +381,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -425,7 +426,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -470,7 +471,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -578,7 +579,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -646,7 +647,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): self.nb.GetPage(2).Add(self.waterfall_sink_0.win) def waterfall_sink_0_callback(x, y): self.set_clicked_freq(x) - + self.waterfall_sink_0.set_callback(waterfall_sink_0_callback) self._variable_static_usrp_info_static_text = forms.static_text( parent=self.nb_info.GetPage(0).GetWin(), @@ -776,7 +777,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -820,7 +821,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -865,7 +866,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -910,7 +911,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -954,7 +955,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -999,7 +1000,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1044,7 +1045,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1089,7 +1090,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1134,7 +1135,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1210,7 +1211,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1385,7 +1386,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1476,7 +1477,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1544,7 +1545,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1584,7 +1585,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): self.nb.GetPage(0).Add(self.fft_sink_two_1.win) def fft_sink_two_1_callback(x, y): self.set_clicked_freq(x) - + self.fft_sink_two_1.set_callback(fft_sink_two_1_callback) self.fft_max_lvl_probe = blocks.probe_signal_f() if probe_interval > 0: @@ -1702,7 +1703,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1794,7 +1795,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1837,7 +1838,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1882,7 +1883,7 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): de = wx.PyEvent() de.SetEventType(wxEVT_AnyCode) wx.PostEvent(self.GetWin(), de) - except TypeError: + except TypeError: pass except AttributeError: # FIXME print "Cannot post message" @@ -1907,38 +1908,38 @@ class mega_fft_2ch(grc_wxgui.top_block_gui): ################################################## # Connections ################################################## - self.connect((self.blks2_selector_0, 0), (self.wxgui_scopesink2_0, 0)) - self.connect((self.blks2_selector_0_0, 0), (self.blks2_selector_0, 0)) - self.connect((self.blks2_selector_0_0, 1), (self.blocks_complex_to_mag_0, 0)) - self.connect((self.blks2_selector_0_0_0, 0), (self.blks2_selector_0_1, 0)) - self.connect((self.blks2_selector_0_0_0, 1), (self.blocks_complex_to_mag_0_0, 0)) - self.connect((self.blks2_selector_0_1, 0), (self.wxgui_scopesink2_0_0, 0)) - self.connect((self.blocks_argmax_xx_0, 1), (self.blocks_null_sink_0, 0)) - self.connect((self.blocks_argmax_xx_0, 0), (self.fft_max_idx_probe, 0)) - self.connect((self.blocks_argmax_xx_0_0, 1), (self.blocks_null_sink_0_0, 0)) - self.connect((self.blocks_argmax_xx_0_0, 0), (self.fft_max_idx_probe_0, 0)) - self.connect((self.blocks_complex_to_mag_0, 0), (self.blocks_float_to_complex_0, 1)) - self.connect((self.blocks_complex_to_mag_0, 0), (self.blocks_float_to_complex_0, 0)) - self.connect((self.blocks_complex_to_mag_0_0, 0), (self.blocks_float_to_complex_0_0, 1)) - self.connect((self.blocks_complex_to_mag_0_0, 0), (self.blocks_float_to_complex_0_0, 0)) - self.connect((self.blocks_float_to_complex_0, 0), (self.blks2_selector_0, 1)) - self.connect((self.blocks_float_to_complex_0_0, 0), (self.blks2_selector_0_1, 1)) - self.connect((self.blocks_max_xx_0, 0), (self.fft_max_lvl_probe, 0)) - self.connect((self.blocks_max_xx_0_0, 0), (self.fft_max_lvl_probe_2, 0)) - self.connect((self.logpwrfft_x_0, 0), (self.blocks_argmax_xx_0, 0)) - self.connect((self.logpwrfft_x_0, 0), (self.blocks_max_xx_0, 0)) - self.connect((self.logpwrfft_x_0_0, 0), (self.blocks_argmax_xx_0_0, 0)) - self.connect((self.logpwrfft_x_0_0, 0), (self.blocks_max_xx_0_0, 0)) - self.connect((self.src, 0), (self.blocks_tag_debug_0, 0)) - self.connect((self.src, 0), (self.blks2_selector_0_0, 0)) - self.connect((self.src, 0), (self.fft_sink, 0)) - self.connect((self.src, 0), (self.waterfall_sink, 0)) - self.connect((self.src, 0), (self.probe_avg_mag, 0)) - self.connect((self.src, 0), (self.logpwrfft_x_0, 0)) - self.connect((self.src, 1), (self.blks2_selector_0_0_0, 0)) - self.connect((self.src, 1), (self.fft_sink_two_1, 0)) - self.connect((self.src, 1), (self.logpwrfft_x_0_0, 0)) - self.connect((self.src, 1), (self.waterfall_sink_0, 0)) + self.connect((self.blks2_selector_0, 0), (self.wxgui_scopesink2_0, 0)) + self.connect((self.blks2_selector_0_0, 0), (self.blks2_selector_0, 0)) + self.connect((self.blks2_selector_0_0, 1), (self.blocks_complex_to_mag_0, 0)) + self.connect((self.blks2_selector_0_0_0, 0), (self.blks2_selector_0_1, 0)) + self.connect((self.blks2_selector_0_0_0, 1), (self.blocks_complex_to_mag_0_0, 0)) + self.connect((self.blks2_selector_0_1, 0), (self.wxgui_scopesink2_0_0, 0)) + self.connect((self.blocks_argmax_xx_0, 1), (self.blocks_null_sink_0, 0)) + self.connect((self.blocks_argmax_xx_0, 0), (self.fft_max_idx_probe, 0)) + self.connect((self.blocks_argmax_xx_0_0, 1), (self.blocks_null_sink_0_0, 0)) + self.connect((self.blocks_argmax_xx_0_0, 0), (self.fft_max_idx_probe_0, 0)) + self.connect((self.blocks_complex_to_mag_0, 0), (self.blocks_float_to_complex_0, 1)) + self.connect((self.blocks_complex_to_mag_0, 0), (self.blocks_float_to_complex_0, 0)) + self.connect((self.blocks_complex_to_mag_0_0, 0), (self.blocks_float_to_complex_0_0, 1)) + self.connect((self.blocks_complex_to_mag_0_0, 0), (self.blocks_float_to_complex_0_0, 0)) + self.connect((self.blocks_float_to_complex_0, 0), (self.blks2_selector_0, 1)) + self.connect((self.blocks_float_to_complex_0_0, 0), (self.blks2_selector_0_1, 1)) + self.connect((self.blocks_max_xx_0, 0), (self.fft_max_lvl_probe, 0)) + self.connect((self.blocks_max_xx_0_0, 0), (self.fft_max_lvl_probe_2, 0)) + self.connect((self.logpwrfft_x_0, 0), (self.blocks_argmax_xx_0, 0)) + self.connect((self.logpwrfft_x_0, 0), (self.blocks_max_xx_0, 0)) + self.connect((self.logpwrfft_x_0_0, 0), (self.blocks_argmax_xx_0_0, 0)) + self.connect((self.logpwrfft_x_0_0, 0), (self.blocks_max_xx_0_0, 0)) + self.connect((self.src, 0), (self.blocks_tag_debug_0, 0)) + self.connect((self.src, 0), (self.blks2_selector_0_0, 0)) + self.connect((self.src, 0), (self.fft_sink, 0)) + self.connect((self.src, 0), (self.waterfall_sink, 0)) + self.connect((self.src, 0), (self.probe_avg_mag, 0)) + self.connect((self.src, 0), (self.logpwrfft_x_0, 0)) + self.connect((self.src, 1), (self.blks2_selector_0_0_0, 0)) + self.connect((self.src, 1), (self.fft_sink_two_1, 0)) + self.connect((self.src, 1), (self.logpwrfft_x_0_0, 0)) + self.connect((self.src, 1), (self.waterfall_sink_0, 0)) def get_antenna(self): |