pax_global_header00006660000000000000000000000064142322734540014520gustar00rootroot0000000000000052 comment=fd0452e31264f065bb315e74313384ca4a121ef1 libmirisdr-4-2.0.0/000077500000000000000000000000001423227345400140205ustar00rootroot00000000000000libmirisdr-4-2.0.0/.gitignore000066400000000000000000000000641423227345400160100ustar00rootroot00000000000000build/ src/*.dll src/*.a src/x64 .cproject .project libmirisdr-4-2.0.0/CMakeLists.txt000066400000000000000000000133421423227345400165630ustar00rootroot00000000000000# Copyright 2012 OSMOCOM Project # # This file is part of MiriSDR # # GNU Radio 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, or (at your option) # any later version. # # GNU Radio 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 GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. ######################################################################## # Project setup ######################################################################## cmake_minimum_required(VERSION 2.6) project(mirisdr C) # use, i.e. don't skip the full RPATH for the build tree set(CMAKE_SKIP_BUILD_RPATH FALSE) # when building, don't use the install RPATH already # (but later on when installing) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") # add the automatically determined parts of the RPATH # which point to directories outside the build tree to the install RPATH set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) #select the release build type by default to get optimization flags if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") message(STATUS "Build type not specified: defaulting to release.") endif(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) # Set the version information here set(VERSION_INFO_MAJOR_VERSION 4) # increment major on api compatibility changes set(VERSION_INFO_MINOR_VERSION 0) # increment minor on feature-level changes set(VERSION_INFO_PATCH_VERSION git) # increment patch for bug fixes and docs include(Version) # setup version info ######################################################################## # Compiler specific setup ######################################################################## if(CMAKE_COMPILER_IS_GNUCC AND NOT WIN32) ADD_DEFINITIONS(-Wall) ADD_DEFINITIONS(-Wextra) ADD_DEFINITIONS(-Wno-unused) ADD_DEFINITIONS(-Wsign-compare) #http://gcc.gnu.org/wiki/Visibility add_definitions(-fvisibility=hidden) endif() ######################################################################## # Find build dependencies ######################################################################## find_package(PkgConfig) find_package(LibUSB) set(THREADS_USE_PTHREADS_WIN32 true) find_package(Threads) if(NOT LIBUSB_FOUND) message(FATAL_ERROR "LibUSB 1.0 required to compile MiriSDR") endif() ######################################################################## # Setup the include and linker paths ######################################################################## include_directories( ${CMAKE_SOURCE_DIR}/include ${LIBUSB_INCLUDE_DIR} ) #link_directories( # ... #) # Set component parameters #set(INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "" FORCE) ######################################################################## # Create uninstall target ######################################################################## configure_file( ${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake @ONLY) add_custom_target(uninstall ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake ) ######################################################################## # Handle detach kernel driver option ######################################################################## option(DETACH_KERNEL_DRIVER "Detach kernel driver if loaded" OFF) if (DETACH_KERNEL_DRIVER) message (STATUS "Building with kernel driver detaching enabled") add_definitions(-DDETACH_KERNEL_DRIVER=1) else (DETACH_KERNEL_DRIVER) message (STATUS "Building with kernel driver detaching disabled, use -DDETACH_KERNEL_DRIVER=ON to enable") endif (DETACH_KERNEL_DRIVER) ######################################################################## # Add subdirectories ######################################################################## add_subdirectory(include) add_subdirectory(src) ######################################################################## # Create Pkg Config File ######################################################################## FOREACH(inc ${LIBUSB_INCLUDE_DIR}) LIST(APPEND MIRISDR_PC_CFLAGS "-I${inc}") ENDFOREACH(inc) FOREACH(lib ${LIBUSB_LIBRARY_DIRS}) LIST(APPEND MIRISDR_PC_LIBS "-L${lib}") ENDFOREACH(lib) # use space-separation format for the pc file STRING(REPLACE ";" " " MIRISDR_PC_CFLAGS "${MIRISDR_PC_CFLAGS}") STRING(REPLACE ";" " " MIRISDR_PC_LIBS "${MIRISDR_PC_LIBS}") # unset these vars to avoid hard-coded paths to cross environment IF(CMAKE_CROSSCOMPILING) UNSET(MIRISDR_PC_CFLAGS) UNSET(MIRISDR_PC_LIBS) ENDIF(CMAKE_CROSSCOMPILING) set(prefix ${CMAKE_INSTALL_PREFIX}) set(exec_prefix \${prefix}) set(libdir \${exec_prefix}/lib${LIB_SUFFIX}) set(includedir \${prefix}/include) CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/libmirisdr.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libmirisdr.pc @ONLY) INSTALL( FILES ${CMAKE_CURRENT_BINARY_DIR}/libmirisdr.pc DESTINATION lib${LIB_SUFFIX}/pkgconfig ) ######################################################################## # Print Summary ######################################################################## MESSAGE(STATUS "Building for version: ${VERSION} / ${LIBVER}") MESSAGE(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}") libmirisdr-4-2.0.0/COPYING000066400000000000000000000431031423227345400150540ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. libmirisdr-4-2.0.0/Makefile.am000066400000000000000000000017351423227345400160620ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 ACLOCAL_AMFLAGS = -I m4 INCLUDES = $(all_includes) -I$(top_srcdir)/include SUBDIRS = include src pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libosmosdr.pc BUILT_SOURCES = $(top_srcdir)/.version $(top_srcdir)/.version: echo $(VERSION) > $@-t && mv $@-t $@ dist-hook: echo $(VERSION) > $(distdir)/.tarball-version EXTRA_DIST = git-version-gen if HAVE_DOXYGEN pkgdocdir=$(docdir)/$(PACKAGE)-$(VERSION) doc_htmldir=$(pkgdocdir)/html doc_html_DATA = $(top_builddir)/doc/html.tar $(doc_html_DATA): $(top_builddir)/doc/html/index.html cd $(top_builddir)/doc && tar cf html.tar html $(top_builddir)/doc/html/index.html: $(SOURCES) Doxyfile @rm -rf doc mkdir -p doc $(DOXYGEN) Doxyfile install-data-hook: cd $(DESTDIR)$(doc_htmldir) && tar xf html.tar --strip-components 1 && rm -f html.tar uninstall-hook: cd $(DESTDIR) && rm -rf $(doc_htmldir) DX_CLEAN = doc/{html,latex}/* doc/html.tar endif MOSTLYCLEANFILES = $(DX_CLEAN) libmirisdr-4-2.0.0/README.md000066400000000000000000000027611423227345400153050ustar00rootroot00000000000000LibMiriSDR-4 ============ This is (yet) another flavour of libmirisdr initiated with original libmirisdr-2 from Miroslav Slugen and additions of Leif Asbrink SM5BSZ in libmirisdr-3-bsz. Bear with me for the missing special characters on both authors names. The initial release contains these improvements and bug fixes from the originals:

Improvements

- Better support of SDRPlay through a "flavour" option in the open function. This indicator can be used throughout the code if necessary. At present it drives the frequency plan that drives the choice between the different receiving paths of the MSi001 depending on frequency. - Remove useless auto gain feature that is just fixed gain in fact. The setter/getter still exists for compatibility but effectively does nothing. - Set the RPATH on the executables so you don't have to set LD_LIBRARY_PATH with the binaries installed by cmake. - Use Unix framework when compiling under Windows witn MinGW. This may fix possible bugs. - Use more meaningful variable names for what is actually gain reductions and not gains. - Some comments in the code were translated from Czech to English (Google translated) to ease understanding by the masses.

Bug fixes

- Stop using a deprecated version of libusb.h (1.0.13) and rely on the one installed in the system or specified in the cmake command line. - Restore gain settings after a frequency, bandwidth or IF change as this affects the gain settings. - Corrected baseband gain setting. libmirisdr-4-2.0.0/cmake/000077500000000000000000000000001423227345400151005ustar00rootroot00000000000000libmirisdr-4-2.0.0/cmake/Modules/000077500000000000000000000000001423227345400165105ustar00rootroot00000000000000libmirisdr-4-2.0.0/cmake/Modules/FindLibUSB.cmake000066400000000000000000000014501423227345400213730ustar00rootroot00000000000000if(NOT LIBUSB_FOUND) pkg_check_modules (LIBUSB_PKG libusb-1.0) find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h PATHS ${LIBUSB_PKG_INCLUDE_DIRS} /usr/include/libusb-1.0 /usr/include /usr/local/include ) find_library(LIBUSB_LIBRARIES NAMES usb-1.0 PATHS ${LIBUSB_PKG_LIBRARY_DIRS} /usr/lib /usr/local/lib ) if(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) set(LIBUSB_FOUND TRUE CACHE INTERNAL "libusb-1.0 found") message(STATUS "Found libusb-1.0: ${LIBUSB_INCLUDE_DIR}, ${LIBUSB_LIBRARIES}") else(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) set(LIBUSB_FOUND FALSE CACHE INTERNAL "libusb-1.0 found") message(STATUS "libusb-1.0 not found.") endif(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) endif(NOT LIBUSB_FOUND) libmirisdr-4-2.0.0/cmake/Modules/FindThreads.cmake000066400000000000000000000207171423227345400217140ustar00rootroot00000000000000# Updated FindThreads.cmake that supports pthread-win32 # Downloaded from http://www.vtk.org/Bug/bug_view_advanced_page.php?bug_id=6399 # - This module determines the thread library of the system. # # The following variables are set # CMAKE_THREAD_LIBS_INIT - the thread library # CMAKE_USE_SPROC_INIT - are we using sproc? # CMAKE_USE_WIN32_THREADS_INIT - using WIN32 threads? # CMAKE_USE_PTHREADS_INIT - are we using pthreads # CMAKE_HP_PTHREADS_INIT - are we using hp pthreads # # If use of pthreads-win32 is desired, the following variables # can be set. # # THREADS_USE_PTHREADS_WIN32 - # Setting this to true searches for the pthreads-win32 # port (since CMake 2.8.0) # # THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME # C = no exceptions (default) # (NOTE: This is the default scheme on most POSIX thread # implementations and what you should probably be using) # CE = C++ Exception Handling # SE = Structure Exception Handling (MSVC only) # (NOTE: Changing this option from the default may affect # the portability of your application. See pthreads-win32 # documentation for more details.) # #====================================================== # Example usage where threading library # is provided by the system: # # find_package(Threads REQUIRED) # add_executable(foo foo.cc) # target_link_libraries(foo ${CMAKE_THREAD_LIBS_INIT}) # # Example usage if pthreads-win32 is desired on Windows # or a system provided thread library: # # set(THREADS_USE_PTHREADS_WIN32 true) # find_package(Threads REQUIRED) # include_directories(${THREADS_PTHREADS_INCLUDE_DIR}) # # add_executable(foo foo.cc) # target_link_libraries(foo ${CMAKE_THREAD_LIBS_INIT}) # INCLUDE (CheckIncludeFiles) INCLUDE (CheckLibraryExists) SET(Threads_FOUND FALSE) IF(WIN32 AND NOT CYGWIN AND THREADS_USE_PTHREADS_WIN32) SET(_Threads_ptwin32 true) ENDIF() # Do we have sproc? IF(CMAKE_SYSTEM MATCHES IRIX) CHECK_INCLUDE_FILES("sys/types.h;sys/prctl.h" CMAKE_HAVE_SPROC_H) ENDIF() IF(CMAKE_HAVE_SPROC_H) # We have sproc SET(CMAKE_USE_SPROC_INIT 1) ELSEIF(_Threads_ptwin32) IF(NOT DEFINED THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME) # Assign the default scheme SET(THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME "C") ELSE() # Validate the scheme specified by the user IF(NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "C" AND NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "CE" AND NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "SE") MESSAGE(FATAL_ERROR "See documentation for FindPthreads.cmake, only C, CE, and SE modes are allowed") ENDIF() IF(NOT MSVC AND THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "SE") MESSAGE(FATAL_ERROR "Structured Exception Handling is only allowed for MSVC") ENDIF(NOT MSVC AND THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "SE") ENDIF() FIND_PATH(THREADS_PTHREADS_INCLUDE_DIR pthread.h) # Determine the library filename IF(MSVC) SET(_Threads_pthreads_libname pthreadV${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2) ELSEIF(MINGW) SET(_Threads_pthreads_libname pthreadG${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2) ELSE() MESSAGE(FATAL_ERROR "This should never happen") ENDIF() # Use the include path to help find the library if possible SET(_Threads_lib_paths "") IF(THREADS_PTHREADS_INCLUDE_DIR) GET_FILENAME_COMPONENT(_Threads_root_dir ${THREADS_PTHREADS_INCLUDE_DIR} PATH) SET(_Threads_lib_paths ${_Threads_root_dir}/lib) ENDIF() FIND_LIBRARY(THREADS_PTHREADS_WIN32_LIBRARY NAMES ${_Threads_pthreads_libname} PATHS ${_Threads_lib_paths} DOC "The Portable Threads Library for Win32" NO_SYSTEM_PATH ) IF(THREADS_PTHREADS_INCLUDE_DIR AND THREADS_PTHREADS_WIN32_LIBRARY) MARK_AS_ADVANCED(THREADS_PTHREADS_INCLUDE_DIR) SET(CMAKE_THREAD_LIBS_INIT ${THREADS_PTHREADS_WIN32_LIBRARY}) SET(CMAKE_HAVE_THREADS_LIBRARY 1) SET(Threads_FOUND TRUE) ENDIF() MARK_AS_ADVANCED(THREADS_PTHREADS_WIN32_LIBRARY) ELSE() # Do we have pthreads? CHECK_INCLUDE_FILES("pthread.h" CMAKE_HAVE_PTHREAD_H) IF(CMAKE_HAVE_PTHREAD_H) # # We have pthread.h # Let's check for the library now. # SET(CMAKE_HAVE_THREADS_LIBRARY) IF(NOT THREADS_HAVE_PTHREAD_ARG) # Do we have -lpthreads CHECK_LIBRARY_EXISTS(pthreads pthread_create "" CMAKE_HAVE_PTHREADS_CREATE) IF(CMAKE_HAVE_PTHREADS_CREATE) SET(CMAKE_THREAD_LIBS_INIT "-lpthreads") SET(CMAKE_HAVE_THREADS_LIBRARY 1) SET(Threads_FOUND TRUE) ENDIF() # Ok, how about -lpthread CHECK_LIBRARY_EXISTS(pthread pthread_create "" CMAKE_HAVE_PTHREAD_CREATE) IF(CMAKE_HAVE_PTHREAD_CREATE) SET(CMAKE_THREAD_LIBS_INIT "-lpthread") SET(Threads_FOUND TRUE) SET(CMAKE_HAVE_THREADS_LIBRARY 1) ENDIF() IF(CMAKE_SYSTEM MATCHES "SunOS.*") # On sun also check for -lthread CHECK_LIBRARY_EXISTS(thread thr_create "" CMAKE_HAVE_THR_CREATE) IF(CMAKE_HAVE_THR_CREATE) SET(CMAKE_THREAD_LIBS_INIT "-lthread") SET(CMAKE_HAVE_THREADS_LIBRARY 1) SET(Threads_FOUND TRUE) ENDIF() ENDIF(CMAKE_SYSTEM MATCHES "SunOS.*") ENDIF(NOT THREADS_HAVE_PTHREAD_ARG) IF(NOT CMAKE_HAVE_THREADS_LIBRARY) # If we did not found -lpthread, -lpthread, or -lthread, look for -pthread IF("THREADS_HAVE_PTHREAD_ARG" MATCHES "^THREADS_HAVE_PTHREAD_ARG") MESSAGE(STATUS "Check if compiler accepts -pthread") TRY_RUN(THREADS_PTHREAD_ARG THREADS_HAVE_PTHREAD_ARG ${CMAKE_BINARY_DIR} ${CMAKE_ROOT}/Modules/CheckForPthreads.c CMAKE_FLAGS -DLINK_LIBRARIES:STRING=-pthread COMPILE_OUTPUT_VARIABLE OUTPUT) IF(THREADS_HAVE_PTHREAD_ARG) IF(THREADS_PTHREAD_ARG MATCHES "^2$") SET(Threads_FOUND TRUE) MESSAGE(STATUS "Check if compiler accepts -pthread - yes") ELSE() MESSAGE(STATUS "Check if compiler accepts -pthread - no") FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "Determining if compiler accepts -pthread returned ${THREADS_PTHREAD_ARG} instead of 2. The compiler had the following output:\n${OUTPUT}\n\n") ENDIF() ELSE() MESSAGE(STATUS "Check if compiler accepts -pthread - no") FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "Determining if compiler accepts -pthread failed with the following output:\n${OUTPUT}\n\n") ENDIF() ENDIF("THREADS_HAVE_PTHREAD_ARG" MATCHES "^THREADS_HAVE_PTHREAD_ARG") IF(THREADS_HAVE_PTHREAD_ARG) SET(Threads_FOUND TRUE) SET(CMAKE_THREAD_LIBS_INIT "-pthread") ENDIF() ENDIF(NOT CMAKE_HAVE_THREADS_LIBRARY) ENDIF(CMAKE_HAVE_PTHREAD_H) ENDIF() IF(CMAKE_THREAD_LIBS_INIT) SET(CMAKE_USE_PTHREADS_INIT 1) SET(Threads_FOUND TRUE) ENDIF() IF(CMAKE_SYSTEM MATCHES "Windows" AND NOT THREADS_USE_PTHREADS_WIN32) SET(CMAKE_USE_WIN32_THREADS_INIT 1) SET(Threads_FOUND TRUE) ENDIF() IF(CMAKE_USE_PTHREADS_INIT) IF(CMAKE_SYSTEM MATCHES "HP-UX-*") # Use libcma if it exists and can be used. It provides more # symbols than the plain pthread library. CMA threads # have actually been deprecated: # http://docs.hp.com/en/B3920-90091/ch12s03.html#d0e11395 # http://docs.hp.com/en/947/d8.html # but we need to maintain compatibility here. # The CMAKE_HP_PTHREADS setting actually indicates whether CMA threads # are available. CHECK_LIBRARY_EXISTS(cma pthread_attr_create "" CMAKE_HAVE_HP_CMA) IF(CMAKE_HAVE_HP_CMA) SET(CMAKE_THREAD_LIBS_INIT "-lcma") SET(CMAKE_HP_PTHREADS_INIT 1) SET(Threads_FOUND TRUE) ENDIF(CMAKE_HAVE_HP_CMA) SET(CMAKE_USE_PTHREADS_INIT 1) ENDIF() IF(CMAKE_SYSTEM MATCHES "OSF1-V*") SET(CMAKE_USE_PTHREADS_INIT 0) SET(CMAKE_THREAD_LIBS_INIT ) ENDIF() IF(CMAKE_SYSTEM MATCHES "CYGWIN_NT*") SET(CMAKE_USE_PTHREADS_INIT 1) SET(Threads_FOUND TRUE) SET(CMAKE_THREAD_LIBS_INIT ) SET(CMAKE_USE_WIN32_THREADS_INIT 0) ENDIF() ENDIF(CMAKE_USE_PTHREADS_INIT) INCLUDE(FindPackageHandleStandardArgs) IF(_Threads_ptwin32) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Threads DEFAULT_MSG THREADS_PTHREADS_WIN32_LIBRARY THREADS_PTHREADS_INCLUDE_DIR) ELSE() FIND_PACKAGE_HANDLE_STANDARD_ARGS(Threads DEFAULT_MSG Threads_FOUND) ENDIF() libmirisdr-4-2.0.0/cmake/Modules/Version.cmake000066400000000000000000000043071423227345400211430ustar00rootroot00000000000000# Copyright 2013 OSMOCOM Project # # This file is part of rtl-sdr # # rtl-sdr 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, or (at your option) # any later version. # # rtl-sdr 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 rtl-sdr; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. if(DEFINED __INCLUDED_VERSION_CMAKE) return() endif() set(__INCLUDED_VERSION_CMAKE TRUE) # VERSION_INFO_* variables must be provided by user set(MAJOR_VERSION ${VERSION_INFO_MAJOR_VERSION}) set(MINOR_VERSION ${VERSION_INFO_MINOR_VERSION}) set(PATCH_VERSION ${VERSION_INFO_PATCH_VERSION}) ######################################################################## # Extract the version string from git describe. ######################################################################## find_package(Git QUIET) if(GIT_FOUND) message(STATUS "Extracting version information from git describe...") execute_process( COMMAND ${GIT_EXECUTABLE} describe --always --abbrev=4 --long OUTPUT_VARIABLE GIT_DESCRIBE OUTPUT_STRIP_TRAILING_WHITESPACE WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) else() set(GIT_DESCRIBE "v${MAJOR_VERSION}.${MINOR_VERSION}.x-xxx-xunknown") endif() ######################################################################## # Use the logic below to set the version constants ######################################################################## if("${PATCH_VERSION}" STREQUAL "git") # VERSION: 3.6git-xxx-gxxxxxxxx # LIBVER: 3.6git set(VERSION "${GIT_DESCRIBE}") set(LIBVER "${MAJOR_VERSION}.${MINOR_VERSION}${PATCH_VERSION}") else() # This is a numbered release. # VERSION: 3.6.1 # LIBVER: 3.6.1 set(VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}") set(LIBVER "${VERSION}") endif() libmirisdr-4-2.0.0/cmake/cmake_uninstall.cmake.in000066400000000000000000000025321423227345400216620ustar00rootroot00000000000000# http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) STRING(REGEX REPLACE "\n" ";" files "${files}") FOREACH(file ${files}) MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") IF(EXISTS "$ENV{DESTDIR}${file}") EXEC_PROGRAM( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) IF(NOT "${rm_retval}" STREQUAL 0) MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") ENDIF(NOT "${rm_retval}" STREQUAL 0) ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}") EXEC_PROGRAM( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) IF(NOT "${rm_retval}" STREQUAL 0) MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") ENDIF(NOT "${rm_retval}" STREQUAL 0) ELSE(EXISTS "$ENV{DESTDIR}${file}") MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") ENDIF(EXISTS "$ENV{DESTDIR}${file}") ENDFOREACH(file) libmirisdr-4-2.0.0/include/000077500000000000000000000000001423227345400154435ustar00rootroot00000000000000libmirisdr-4-2.0.0/include/CMakeLists.txt000066400000000000000000000017651423227345400202140ustar00rootroot00000000000000# Copyright 2012 OSMOCOM Project # # This file is part of MiriSDR # # GNU Radio 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, or (at your option) # any later version. # # GNU Radio 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 GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. ######################################################################## # Install public header files ######################################################################## install(FILES mirisdr.h mirisdr_export.h DESTINATION include ) libmirisdr-4-2.0.0/include/Makefile.am000066400000000000000000000001111423227345400174700ustar00rootroot00000000000000mirisdr_HEADERS = mirisdr.h mirisdr_export.h mirisdrdir = $(includedir) libmirisdr-4-2.0.0/include/mirisdr.h000066400000000000000000000133361423227345400172730ustar00rootroot00000000000000/* * Copyright (C) 2012 by Steve Markgraf * Copyright (C) 2012 by Dimitri Stolnikov * * 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 2 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 . */ #ifndef __MIRISDR_H #define __MIRISDR_H #ifdef __cplusplus extern "C" { #endif // Set debug level // 0=no debug // 1=gain and frequency info. // 2=extended debug #define MIRISDR_DEBUG 0 #include #include typedef enum { MIRISDR_HW_DEFAULT, MIRISDR_HW_SDRPLAY, } mirisdr_hw_flavour_t; typedef enum { MIRISDR_BAND_AM1, MIRISDR_BAND_AM2, MIRISDR_BAND_VHF, MIRISDR_BAND_3, MIRISDR_BAND_45, MIRISDR_BAND_L, } mirisdr_band_t; typedef struct mirisdr_dev mirisdr_dev_t; /* devices */ MIRISDR_API uint32_t mirisdr_get_device_count (void); MIRISDR_API const char *mirisdr_get_device_name (uint32_t index); MIRISDR_API int mirisdr_get_device_usb_strings (uint32_t index, char *manufact, char *product, char *serial); /* main */ MIRISDR_API int mirisdr_open (mirisdr_dev_t **p, uint32_t index); MIRISDR_API int mirisdr_close (mirisdr_dev_t *p); MIRISDR_API int mirisdr_reset (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_reset_buffer (mirisdr_dev_t *p); MIRISDR_API int mirisdr_get_usb_strings (mirisdr_dev_t *dev, char *manufact, char *product, char *serial); MIRISDR_API int mirisdr_set_hw_flavour (mirisdr_dev_t *p, mirisdr_hw_flavour_t hw_flavour); /* sync */ MIRISDR_API int mirisdr_read_sync (mirisdr_dev_t *p, void *buf, int len, int *n_read); /* async */ typedef void(*mirisdr_read_async_cb_t) (unsigned char *buf, uint32_t len, void *ctx); MIRISDR_API int mirisdr_read_async (mirisdr_dev_t *p, mirisdr_read_async_cb_t cb, void *ctx, uint32_t num, uint32_t len); MIRISDR_API int mirisdr_cancel_async (mirisdr_dev_t *p); MIRISDR_API int mirisdr_cancel_async_now (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_start_async (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_stop_async (mirisdr_dev_t *p); /* extra */ /* adc */ MIRISDR_API int mirisdr_adc_init (mirisdr_dev_t *p); /* extra */ /* rate control */ MIRISDR_API int mirisdr_set_sample_rate (mirisdr_dev_t *p, uint32_t rate); MIRISDR_API uint32_t mirisdr_get_sample_rate (mirisdr_dev_t *p); /* sample format control */ MIRISDR_API int mirisdr_set_sample_format (mirisdr_dev_t *p, char *v); /* extra */ MIRISDR_API const char *mirisdr_get_sample_format (mirisdr_dev_t *p); /* extra */ /* streaming control */ MIRISDR_API int mirisdr_streaming_start (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_streaming_stop (mirisdr_dev_t *p); /* extra */ /* frequency */ MIRISDR_API int mirisdr_set_center_freq (mirisdr_dev_t *p, uint32_t freq); MIRISDR_API uint32_t mirisdr_get_center_freq (mirisdr_dev_t *p); MIRISDR_API int mirisdr_set_if_freq (mirisdr_dev_t *p, uint32_t freq); /* extra */ MIRISDR_API uint32_t mirisdr_get_if_freq (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_set_xtal_freq (mirisdr_dev_t *p, uint32_t freq);/* extra */ MIRISDR_API uint32_t mirisdr_get_xtal_freq (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_set_bandwidth (mirisdr_dev_t *p, uint32_t bw); /* extra */ MIRISDR_API uint32_t mirisdr_get_bandwidth (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_set_offset_tuning (mirisdr_dev_t *p, int on); /* extra */ MIRISDR_API mirisdr_band_t mirisdr_get_band (mirisdr_dev_t *p); /* extra */ /* not implemented yet */ MIRISDR_API int mirisdr_set_freq_correction (mirisdr_dev_t *p, int ppm); MIRISDR_API int mirisdr_set_direct_sampling (mirisdr_dev_t *p, int on); /* transfer */ MIRISDR_API int mirisdr_set_transfer (mirisdr_dev_t *p, char *v); /* extra */ MIRISDR_API const char *mirisdr_get_transfer (mirisdr_dev_t *p); /* extra */ /* gain */ MIRISDR_API int mirisdr_set_gain (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_get_tuner_gains (mirisdr_dev_t *dev, int *gains); MIRISDR_API int mirisdr_set_tuner_gain (mirisdr_dev_t *p, int gain); MIRISDR_API int mirisdr_get_tuner_gain (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_set_tuner_gain_mode (mirisdr_dev_t *p, int mode); MIRISDR_API int mirisdr_get_tuner_gain_mode (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_set_mixer_gain (mirisdr_dev_t *p, int gain); /* extra */ MIRISDR_API int mirisdr_set_mixbuffer_gain (mirisdr_dev_t *p, int gain);/* extra */ MIRISDR_API int mirisdr_set_lna_gain (mirisdr_dev_t *p, int gain); /* extra */ MIRISDR_API int mirisdr_set_baseband_gain (mirisdr_dev_t *p, int gain); /* extra */ MIRISDR_API int mirisdr_get_mixer_gain (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_get_mixbuffer_gain (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_get_lna_gain (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_get_baseband_gain (mirisdr_dev_t *p); /* extra */ MIRISDR_API int mirisdr_set_bias (mirisdr_dev_t *p, int bias); /* extra */ MIRISDR_API int mirisdr_get_bias (mirisdr_dev_t *p); /* extra */ #ifdef __cplusplus } #endif #endif /* __MIRISDR_H */ libmirisdr-4-2.0.0/include/mirisdr_export.h000066400000000000000000000026211423227345400206670ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ #ifndef __MIRISDR_EXPORT_H #define __MIRISDR_EXPORT_H #if defined __GNUC__ # if __GNUC__ >= 4 # define __SDR_EXPORT __attribute__((visibility("default"))) # define __SDR_IMPORT __attribute__((visibility("default"))) # else # define __SDR_EXPORT # define __SDR_IMPORT # endif #else # if defined _MSC_VER # define __SDR_EXPORT __declspec(dllexport) # define __SDR_IMPORT __declspec(dllimport) # else # define __SDR_EXPORT # define __SDR_IMPORT # endif #endif #ifndef mirisdr_STATIC # ifdef mirisdr_EXPORTS # define MIRISDR_API __SDR_EXPORT # else # define MIRISDR_API __SDR_IMPORT # endif #else # define MIRISDR_API #endif #endif /* __MIRISDR_EXPORT_H */ libmirisdr-4-2.0.0/libmirisdr.pc.in000066400000000000000000000004161423227345400171120ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: MiriSDR Library Description: C Utility Library Version: @VERSION@ Cflags: -I${includedir}/ @MIRISDR_PC_CFLAGS@ Libs: -L${libdir} -lmirisdr -lusb-1.0 Libs.private: @MIRISDR_PC_LIBS@ libmirisdr-4-2.0.0/mirisdr.rules000066400000000000000000000021341423227345400165450ustar00rootroot00000000000000# # Copyright 2012 Osmocom MiriSDR project # # 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 . # # Mirics MSi2500 default (e.g. VTX3D card) SUBSYSTEMS=="usb", ATTRS{idVendor}=="1df7", ATTRS{idProduct}=="2500", MODE:="0666" # IO-DATA GV-TV100 stick SUBSYSTEMS=="usb", ATTRS{idVendor}=="04bb", ATTRS{idProduct}=="0537", MODE:="0666" # SDRplay RSP1A SUBSYSTEMS=="usb", ATTRS{idVendor}=="1df7", ATTRS{idProduct}=="3000", MODE:="0666" # SDRplay RSP2 SUBSYSTEMS=="usb", ATTRS{idVendor}=="1df7", ATTRS{idProduct}=="3010", MODE:="0666" libmirisdr-4-2.0.0/src/000077500000000000000000000000001423227345400146075ustar00rootroot00000000000000libmirisdr-4-2.0.0/src/CMakeLists.txt000066400000000000000000000057141423227345400173560ustar00rootroot00000000000000# Copyright 2012 OSMOCOM Project # # This file is part of MiriSDR # # GNU Radio 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, or (at your option) # any later version. # # GNU Radio 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 GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. ######################################################################## # Setup library ######################################################################## add_library(mirisdr_shared SHARED libmirisdr.c ) target_link_libraries(mirisdr_shared ${LIBUSB_LIBRARIES} ) set_target_properties(mirisdr_shared PROPERTIES DEFINE_SYMBOL "mirisdr_EXPORTS") set_target_properties(mirisdr_shared PROPERTIES OUTPUT_NAME mirisdr) set_target_properties(mirisdr_shared PROPERTIES SOVERSION ${MAJOR_VERSION}) set_target_properties(mirisdr_shared PROPERTIES VERSION ${LIBVER}) add_library(mirisdr_static STATIC libmirisdr.c ) if(WIN32) add_library(libgetopt_static STATIC getopt/getopt.c ) endif() target_link_libraries(mirisdr_static ${LIBUSB_LIBRARIES} ) set_property(TARGET mirisdr_static APPEND PROPERTY COMPILE_DEFINITIONS "mirisdr_STATIC" ) if(NOT WIN32) # Force same library filename for static and shared variants of the library set_target_properties(mirisdr_static PROPERTIES OUTPUT_NAME mirisdr) endif() ######################################################################## # Build utility ######################################################################## add_executable(miri_sdr miri_sdr.c) add_executable(miri_fm miri_fm.c) set(INSTALL_TARGETS mirisdr_shared mirisdr_static miri_sdr miri_fm) target_link_libraries(miri_sdr mirisdr_shared ${LIBUSB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) target_link_libraries(miri_fm mirisdr_shared ${LIBUSB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) if(UNIX) target_link_libraries(miri_fm m) endif() if(WIN32) target_link_libraries(miri_sdr libgetopt_static) target_link_libraries(miri_fm libgetopt_static) set_property(TARGET miri_sdr APPEND PROPERTY COMPILE_DEFINITIONS "mirisdr_STATIC" ) set_property(TARGET miri_fm APPEND PROPERTY COMPILE_DEFINITIONS "mirisdr_STATIC" ) endif() ######################################################################## # Install built library files & utilities ######################################################################## install(TARGETS ${INSTALL_TARGETS} LIBRARY DESTINATION lib${LIB_SUFFIX} # .so/.dylib file ARCHIVE DESTINATION lib${LIB_SUFFIX} # .lib file RUNTIME DESTINATION bin # .dll file ) libmirisdr-4-2.0.0/src/Makefile.am000066400000000000000000000011421423227345400166410ustar00rootroot00000000000000# This is _NOT_ the library release version, it's an API version. # Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification LIBVERSION=0:0:0 INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS = ${CFLAGS} -fPIC ${SYMBOL_VISIBILITY} lib_LTLIBRARIES = libmirisdr.la libmirisdr_la_SOURCES = libmirisdr.c libmirisdr_la_LDFLAGS = -version-info $(LIBVERSION) bin_PROGRAMS = miri_sdr miri_fm miri_sdr_SOURCES = miri_sdr.c miri_sdr_LDADD = libmirisdr.la miri_fm_SOURCES = miri_fm.c miri_fm_LDADD = libmirisdr.la $(LIBM) libmirisdr-4-2.0.0/src/Makefile.mingw000066400000000000000000000025601423227345400173720ustar00rootroot00000000000000WCC = /usr/bin/i686-w64-mingw32-gcc -march=i686 WCC64 = x86_64-w64-mingw32-gcc CFW = -c -g -O2 -m32 -Wreturn-type -Wformat -Wunused -Wcomment \ -Wchar-subscripts -Wshadow -Wuninitialized -Wparentheses \ -Wstrict-prototypes -Werror -ffast-math -Wundef -fomit-frame-pointer \ -I../include -o CFW64 = -c -g -O2 -m64 -Wreturn-type -Wformat -Wunused -Wcomment \ -Wchar-subscripts -Wshadow -Wuninitialized -Wparentheses \ -Wstrict-prototypes -Werror -ffast-math -Wundef -fomit-frame-pointer \ -I../include -o all: Makefile.mingw libmirisdr.a mirisdr.dll x64/mirisdr.dll libmirisdr.a: libmirisdr.o Makefile.mingw ar rs libmirisdr.a libmirisdr.o /usr/bin/i686-w64-mingw32-ranlib libmirisdr.a mirisdr.dll: libmirisdr.o Makefile.mingw $(WCC) libmirisdr.o libusb-1.0.dll libgcc_s_sjlj-1.dll -shared -o mirisdr.dll x64/mirisdr.dll: libmirisdr.oy Makefile.mingw $(WCC64) libmirisdr.oy x64/libusb-1.0.dll -shared -o x64/mirisdr.dll libmirisdr.o: Makefile.mingw libmirisdr.c async.c reg.c adc.c convert/base.c \ devices.c gain.c hard.c streaming.c soft.c sync.c ../include/mirisdr.h \ ../include/mirisdr_export.h $(WCC) libmirisdr.c $(CFW) libmirisdr.o libmirisdr.oy: Makefile.mingw libmirisdr.c async.c reg.c adc.c convert/base.c \ devices.c gain.c hard.c streaming.c soft.c sync.c ../include/mirisdr.h \ ../include/mirisdr_export.h $(WCC64) libmirisdr.c $(CFW64) libmirisdr.oy libmirisdr-4-2.0.0/src/Makefile.mingw-win000066400000000000000000000025231423227345400201640ustar00rootroot00000000000000WCC =C:\mingw\bin\mingw32-gcc WCC64 = x86_64-w64-mingw32-gcc CFW = -c -g -O2 -m32 -Wreturn-type -Wformat -Wunused -Wcomment \ -Wchar-subscripts -Wshadow -Wuninitialized -Wparentheses \ -Wstrict-prototypes -Werror -ffast-math -Wundef -fomit-frame-pointer \ -I../include -o CFW64 = -c -g -O2 -m64 -Wreturn-type -Wformat -Wunused -Wcomment \ -Wchar-subscripts -Wshadow -Wuninitialized -Wparentheses \ -Wstrict-prototypes -Werror -ffast-math -Wundef -fomit-frame-pointer \ -I../include -o all: Makefile.mingw libmirisdr.a mirisdr.dll x64/mirisdr.dll libmirisdr.a: libmirisdr.o Makefile.mingw ar rs libmirisdr.a libmirisdr.o C:\mingw\bin\ranlib libmirisdr.a mirisdr.dll: libmirisdr.o Makefile.mingw $(WCC) libmirisdr.o libusb-1.0.dll libgcc_s_sjlj-1.dll -shared -o mirisdr.dll x64/mirisdr.dll: libmirisdr.oy Makefile.mingw $(WCC64) libmirisdr.oy x64/libusb-1.0.dll -shared -o x64/mirisdr.dll libmirisdr.o: Makefile.mingw libmirisdr.c async.c reg.c adc.c convert/base.c \ devices.c gain.c hard.c streaming.c soft.c sync.c ../include/mirisdr.h \ ../include/mirisdr_export.h $(WCC) libmirisdr.c $(CFW) libmirisdr.o libmirisdr.oy: Makefile.mingw libmirisdr.c async.c reg.c adc.c convert/base.c \ devices.c gain.c hard.c streaming.c soft.c sync.c ../include/mirisdr.h \ ../include/mirisdr_export.h $(WCC64) libmirisdr.c $(CFW64) libmirisdr.oy libmirisdr-4-2.0.0/src/adc.c000066400000000000000000000024171423227345400155060ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ int mirisdr_adc_init (mirisdr_dev_t *p) { if (!p) goto failed; /* inicializace - statická */ mirisdr_write_reg(p, 0x08, 0x006080); /* kernel driver */ mirisdr_write_reg(p, 0x05, 0x00000c); mirisdr_write_reg(p, 0x00, 0x000200); mirisdr_write_reg(p, 0x02, 0x004801); mirisdr_write_reg(p, 0x08, 0x00f380); /* kernel driver */ return 0; failed: return -1; } int mirisdr_adc_stop (mirisdr_dev_t *p) { if (!p) goto failed; /* uspíme USB IF a ADC */ mirisdr_write_reg(p, 0x03, 0x010000); return 0; failed: return -1; } libmirisdr-4-2.0.0/src/async.c000066400000000000000000000464631423227345400161050ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ #include "async.h" /* uložení dat */ static int mirisdr_feed_async (mirisdr_dev_t *p, unsigned char *samples, uint32_t bytes) { uint32_t i; if (!p) goto failed; if (!p->cb) goto failed; /* automatická velikost */ if (!p->xfer_out_len) { /* přímé zaslání */ p->cb(samples, bytes, p->cb_ctx); /* fixní velikost bufferu bez předchozích dat */ } else if (p->xfer_out_pos == 0) { /* buffer přesně odpovídá - málo časté, přímé zaslání */ if (bytes == p->xfer_out_len) { p->cb(samples, bytes, p->cb_ctx); /* buffer je kratší */ } else if (bytes < p->xfer_out_len) { memcpy(p->xfer_out, samples, bytes); p->xfer_out_pos = bytes; /* buffer je delší */ } else { /* muže být i x násobkem délky */ for (i = 0;; i+= p->xfer_out_len) { if (i + p->xfer_out_len > bytes) { if (bytes > i) { memcpy(p->xfer_out, samples + i, bytes - i); p->xfer_out_pos = bytes - i; } break; } p->cb(samples + i, p->xfer_out_len, p->cb_ctx); } } /* data jsou přesně, využije se interní buffer */ } else if (p->xfer_out_pos + bytes == p->xfer_out_len) { memcpy(p->xfer_out + p->xfer_out_pos, samples, bytes); p->cb(p->xfer_out, p->xfer_out_len, p->cb_ctx); p->xfer_out_pos = 0; /* není dostatek dat */ } else if (p->xfer_out_pos + bytes < p->xfer_out_len) { memcpy(p->xfer_out + p->xfer_out_pos, samples, bytes); p->xfer_out_pos+= bytes; /* dat je více než potřebujeme, nejsložitější případ */ } else { memcpy(p->xfer_out + p->xfer_out_pos, samples, p->xfer_out_len - p->xfer_out_pos); p->cb(p->xfer_out, p->xfer_out_len, p->cb_ctx); for (i = p->xfer_out_len - p->xfer_out_pos;; i+= p->xfer_out_len) { if (i + p->xfer_out_len > bytes) { if (bytes > i) { memcpy(p->xfer_out, samples + i, bytes - i); p->xfer_out_pos = bytes - i; } else { p->xfer_out_pos = 0; } break; } p->cb(samples + i, p->xfer_out_len, p->cb_ctx); } } return 0; failed: return -1; } /* volání pro zasílání dat */ static void LIBUSB_CALL _libusb_callback (struct libusb_transfer *xfer) { size_t i; int len, bytes = 0; static unsigned char *iso_packet_buf; mirisdr_dev_t *p = (mirisdr_dev_t*) xfer->user_data; uint8_t *samples = NULL; if (!p) goto failed; /* zpracujeme pouze kompletní přenos */ if (xfer->status == LIBUSB_TRANSFER_COMPLETED) { /* * Určení správné velikosti bufferu, tato část musí být provedena * v jednom kroku, jinak může dojít ke změně formátu uprostřed procesu, * druhá možnost je používat lock. */ switch (xfer->type) { case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: switch (p->format) { case MIRISDR_FORMAT_252_S16: samples = malloc(504 * DEFAULT_ISO_BUFFERS * DEFAULT_ISO_PACKETS * 2); for (i = 0; i < DEFAULT_ISO_PACKETS; i++) { struct libusb_iso_packet_descriptor *packet = &xfer->iso_packet_desc[i]; /* buffer_simple je pouze pro stejně velké pakety */ if ((packet->actual_length > 0) && (iso_packet_buf = libusb_get_iso_packet_buffer_simple(xfer, i))) { /* menší velikost než 3072 nevadí, je běžný násobek 1024, cokoliv jiného je chyba */ len = mirisdr_samples_convert_252_s16(p, iso_packet_buf, samples + bytes, packet->actual_length); bytes+= len; } } break; case MIRISDR_FORMAT_336_S16: samples = malloc(672 * DEFAULT_ISO_BUFFERS * DEFAULT_ISO_PACKETS * 2); for (i = 0; i < DEFAULT_ISO_PACKETS; i++) { struct libusb_iso_packet_descriptor *packet = &xfer->iso_packet_desc[i]; if ((packet->actual_length > 0) && (iso_packet_buf = libusb_get_iso_packet_buffer_simple(xfer, i))) { len = mirisdr_samples_convert_336_s16(p, iso_packet_buf, samples + bytes, packet->actual_length); bytes+= len; } } break; case MIRISDR_FORMAT_384_S16: samples = malloc(768 * DEFAULT_ISO_BUFFERS * DEFAULT_ISO_PACKETS * 2); for (i = 0; i < DEFAULT_ISO_PACKETS; i++) { struct libusb_iso_packet_descriptor *packet = &xfer->iso_packet_desc[i]; if ((packet->actual_length > 0) && (iso_packet_buf = libusb_get_iso_packet_buffer_simple(xfer, i))) { len = mirisdr_samples_convert_384_s16(p, iso_packet_buf, samples + bytes, packet->actual_length); bytes+= len; } } break; case MIRISDR_FORMAT_504_S16: samples = malloc(1008 * DEFAULT_ISO_BUFFERS * DEFAULT_ISO_PACKETS * 2); for (i = 0; i < DEFAULT_ISO_PACKETS; i++) { struct libusb_iso_packet_descriptor *packet = &xfer->iso_packet_desc[i]; if ((packet->actual_length > 0) && (iso_packet_buf = libusb_get_iso_packet_buffer_simple(xfer, i))) { len = mirisdr_samples_convert_504_s16(p, iso_packet_buf, samples + bytes, packet->actual_length); bytes+= len; } } break; case MIRISDR_FORMAT_504_S8: samples = malloc(1008 * DEFAULT_ISO_BUFFERS * DEFAULT_ISO_PACKETS); for (i = 0; i < DEFAULT_ISO_PACKETS; i++) { struct libusb_iso_packet_descriptor *packet = &xfer->iso_packet_desc[i]; if ((packet->actual_length > 0) && (iso_packet_buf = libusb_get_iso_packet_buffer_simple(xfer, i))) { len = mirisdr_samples_convert_504_s8(p, iso_packet_buf, samples + bytes, packet->actual_length); bytes+= len; } } break; } break; case LIBUSB_TRANSFER_TYPE_BULK: switch (p->format) { case MIRISDR_FORMAT_252_S16: samples = malloc((DEFAULT_BULK_BUFFER / 1024) * 1008); bytes = mirisdr_samples_convert_252_s16(p, xfer->buffer, samples, xfer->actual_length); break; case MIRISDR_FORMAT_336_S16: samples = malloc((DEFAULT_BULK_BUFFER / 1024) * 1344); bytes = mirisdr_samples_convert_336_s16(p, xfer->buffer, samples, xfer->actual_length); break; case MIRISDR_FORMAT_384_S16: samples = malloc((DEFAULT_BULK_BUFFER / 1024) * 1536); bytes = mirisdr_samples_convert_384_s16(p, xfer->buffer, samples, xfer->actual_length); break; case MIRISDR_FORMAT_504_S16: samples = malloc((DEFAULT_BULK_BUFFER / 1024) * 2016); bytes = mirisdr_samples_convert_504_s16(p, xfer->buffer, samples, xfer->actual_length); break; case MIRISDR_FORMAT_504_S8: samples = malloc((DEFAULT_BULK_BUFFER / 1024) * 1008); bytes = mirisdr_samples_convert_504_s8(p, xfer->buffer, samples, xfer->actual_length); break; } break; default: fprintf( stderr, "not isoc or bulk transfer type on usb device: %u\n", p->index); goto failed; } if (bytes > 0) mirisdr_feed_async(p, samples, bytes); if (samples) free(samples); /* pokračujeme dalším přenosem */ if (libusb_submit_transfer(xfer) < 0) { fprintf( stderr, "error re-submitting URB on device %u\n", p->index); goto failed; } } else if (xfer->status != LIBUSB_TRANSFER_CANCELLED) { fprintf( stderr, "error async transfer status %d on device %u\n", xfer->status, p->index); goto failed; } return; failed: mirisdr_cancel_async(p); /* stav failed má absolutní přednost */ p->async_status = MIRISDR_ASYNC_FAILED; } /* ukončení async části */ int mirisdr_cancel_async (mirisdr_dev_t *p) { if (!p) goto failed; switch (p->async_status) { case MIRISDR_ASYNC_INACTIVE: case MIRISDR_ASYNC_CANCELING: goto canceled; case MIRISDR_ASYNC_RUNNING: case MIRISDR_ASYNC_PAUSED: p->async_status = MIRISDR_ASYNC_CANCELING; break; case MIRISDR_ASYNC_FAILED: goto failed; } return 0; failed: return -1; canceled: return -2; } /* ukončení async části včetně čekání */ int mirisdr_cancel_async_now (mirisdr_dev_t *p) { if (!p) goto failed; switch (p->async_status) { case MIRISDR_ASYNC_INACTIVE: goto done; case MIRISDR_ASYNC_CANCELING: break; case MIRISDR_ASYNC_RUNNING: case MIRISDR_ASYNC_PAUSED: p->async_status = MIRISDR_ASYNC_CANCELING; break; case MIRISDR_ASYNC_FAILED: goto failed; } /* cyklujeme dokud není vše ukončeno */ while ((p->async_status != MIRISDR_ASYNC_INACTIVE) && (p->async_status != MIRISDR_ASYNC_FAILED)) #if defined (_WIN32) && !defined(__MINGW32__) Sleep(20); #else usleep(20000); #endif done: return 0; failed: return -1; } /* alokace asynchronních bufferů */ static int mirisdr_async_alloc (mirisdr_dev_t *p) { size_t i; if (!p->xfer) { p->xfer = malloc(p->xfer_buf_num * sizeof(*p->xfer)); for (i = 0; i < p->xfer_buf_num; i++) { switch (p->transfer) { case MIRISDR_TRANSFER_BULK: p->xfer[i] = libusb_alloc_transfer(0); break; case MIRISDR_TRANSFER_ISOC: p->xfer[i] = libusb_alloc_transfer(DEFAULT_ISO_PACKETS); break; } } } if (!p->xfer_buf) { p->xfer_buf = malloc(p->xfer_buf_num * sizeof(*p->xfer_buf)); for (i = 0; i < p->xfer_buf_num; i++) { switch (p->transfer) { case MIRISDR_TRANSFER_BULK: p->xfer_buf[i] = malloc(DEFAULT_BULK_BUFFER); break; case MIRISDR_TRANSFER_ISOC: p->xfer_buf[i] = malloc(DEFAULT_ISO_BUFFER * DEFAULT_ISO_BUFFERS * DEFAULT_ISO_PACKETS); break; } } } if ((!p->xfer_out) && (p->xfer_out_len)) { p->xfer_out = malloc(p->xfer_out_len * sizeof(*p->xfer_out)); } return 0; } /* uvolnění asynchronních bufferů */ static int mirisdr_async_free (mirisdr_dev_t *p) { size_t i; if (p->xfer) { for (i = 0; i < p->xfer_buf_num; i++) { if (p->xfer[i]) libusb_free_transfer(p->xfer[i]); } free(p->xfer); p->xfer = NULL; } if (p->xfer_buf) { for (i = 0; i < p->xfer_buf_num; i++) { if (p->xfer_buf[i]) free(p->xfer_buf[i]); } free(p->xfer_buf); p->xfer_buf = NULL; } if (p->xfer_out) { free(p->xfer_out); p->xfer_out = NULL; } return 0; } /* spuštění async části */ int mirisdr_read_async (mirisdr_dev_t *p, mirisdr_read_async_cb_t cb, void *ctx, uint32_t num, uint32_t len) { size_t i; int r, semafor; struct timeval tv = {1, 0}; if (!p) goto failed; if (!p->dh) goto failed; /* nedovolíme spustit jiný stav než neaktivní */ if (p->async_status != MIRISDR_ASYNC_INACTIVE) goto failed; p->cb = cb; p->cb_ctx = ctx; p->xfer_buf_num = (num == 0) ? DEFAULT_BUF_NUMBER : num; /* jde o fixní velikost výstupního bufferu */ p->xfer_out_len = (len == 0) ? 0 : len; p->xfer_out_pos = 0; #if MIRISDR_DEBUG >= 1 fprintf( stderr, "async read on device %u, buffers: %lu, output size: ", p->index, (long)p->xfer_buf_num); if (p->xfer_out_len) { fprintf( stderr, "%lu", (long)p->xfer_out_len); } else { fprintf( stderr, "auto"); } #endif /* použití správného rozhraní které zasílá data - není kritické */ switch (p->transfer) { case MIRISDR_TRANSFER_BULK: #if MIRISDR_DEBUG >= 1 fprintf( stderr, ", transfer: bulk\n"); #endif if ((r = libusb_set_interface_alt_setting(p->dh, 0, 3)) < 0) { fprintf( stderr, "failed to use alternate setting for Bulk mode on miri usb device %u with code %d\n", p->index, r); } break; case MIRISDR_TRANSFER_ISOC: #if MIRISDR_DEBUG >= 1 fprintf( stderr, ", transfer: isochronous\n"); #endif if ((r = libusb_set_interface_alt_setting(p->dh, 0, 1)) < 0) { fprintf( stderr, "failed to use alternate setting for Isochronous mode on miri usb device %u with code %d\n", p->index, r); } break; default: fprintf( stderr, "\nunsupported transfer type on miri usb device %u\n", p->index); goto failed; } mirisdr_async_alloc(p); /* spustíme přenosy */ for (i = 0; i < p->xfer_buf_num; i++) { switch (p->transfer) { case MIRISDR_TRANSFER_BULK: libusb_fill_bulk_transfer(p->xfer[i], p->dh, 0x81, p->xfer_buf[i], DEFAULT_BULK_BUFFER, _libusb_callback, (void*) p, DEFAULT_BULK_TIMEOUT); break; case MIRISDR_TRANSFER_ISOC: libusb_fill_iso_transfer(p->xfer[i], p->dh, 0x81, p->xfer_buf[i], DEFAULT_ISO_BUFFER * DEFAULT_ISO_BUFFERS * DEFAULT_ISO_PACKETS, DEFAULT_ISO_PACKETS, _libusb_callback, (void*) p, DEFAULT_ISO_TIMEOUT); libusb_set_iso_packet_lengths(p->xfer[i], DEFAULT_ISO_BUFFER * DEFAULT_ISO_BUFFERS); break; default: fprintf( stderr, "unsupported transfer type\n"); goto failed_free; } r = libusb_submit_transfer(p->xfer[i]); if (r < 0) { fprintf(stderr, "Failed to submit transfer %lu reason: %d\n", i, r); goto failed_free; } } /* spustíme streamování dat */ mirisdr_streaming_start(p); p->async_status = MIRISDR_ASYNC_RUNNING; while (p->async_status != MIRISDR_ASYNC_INACTIVE) { /* počkáme na další událost */ if ((r = libusb_handle_events_timeout(p->ctx, &tv)) < 0) { fprintf( stderr, "libusb_handle_events returned: %d\n", r); if (r == LIBUSB_ERROR_INTERRUPTED) continue; /* stray */ goto failed_free; } /* dochází k ukončení */ if (p->async_status == MIRISDR_ASYNC_CANCELING) { if (!p->xfer) { p->async_status = MIRISDR_ASYNC_INACTIVE; break; } /* ukončíme všechny přenosy */ semafor = 1; for (i = 0; i < p->xfer_buf_num; i++) { if (!p->xfer[i]) continue; /* pro isoc režim je completed i v případě chyb */ if (p->xfer[i]->status != LIBUSB_TRANSFER_CANCELLED) { libusb_cancel_transfer(p->xfer[i]); semafor = 0; } } /* nedošlo k žádnému vynuceném ukončení přenosu, skončíme */ if (semafor) { p->async_status = MIRISDR_ASYNC_INACTIVE; /* počkáme na dokončení všech procesů */ libusb_handle_events_timeout(p->ctx, &tv); break; } } else if (p->async_status == MIRISDR_ASYNC_FAILED) { goto failed_free; } } /* dealokujeme buffer */ mirisdr_async_free(p); /* ukončíme streamování dat */ #if defined (_WIN32) && !defined(__MINGW32__) Sleep(20); #else usleep(20000); #endif mirisdr_streaming_stop(p); /* je vhodné ukončit i adc, jenže pak by při dalším otevření bylo nutné provést inicializaci */ return 0; failed_free: mirisdr_async_free(p); failed: return -1; } /* spuštění streamování */ int mirisdr_start_async (mirisdr_dev_t *p) { size_t i; /* nedovolíme jiný stav než pozastavený */ if (p->async_status != MIRISDR_ASYNC_PAUSED) goto failed; /* reset interního bufferu */ p->xfer_out_pos = 0; for (i = 0; i < p->xfer_buf_num; i++) { if (!p->xfer[i]) continue; if (libusb_submit_transfer(p->xfer[i])< 0) { goto failed; } } if (p->async_status != MIRISDR_ASYNC_PAUSED) goto failed; mirisdr_streaming_start(p); p->async_status = MIRISDR_ASYNC_RUNNING; return 0; failed: return -1; } /* zastavení streamování */ int mirisdr_stop_async (mirisdr_dev_t *p) { size_t i; int r, semafor; struct timeval tv = {1, 0}; /* nedovolíme jiný stav než spuštěný */ if (p->async_status != MIRISDR_ASYNC_RUNNING) goto failed; while (p->async_status == MIRISDR_ASYNC_RUNNING) { semafor = 1; for (i = 0; i < p->xfer_buf_num; i++) { if (!p->xfer[i]) continue; /* pro isoc režim je completed i v případě chyb */ if (p->xfer[i]->status != LIBUSB_TRANSFER_CANCELLED) { libusb_cancel_transfer(p->xfer[i]); semafor = 0; } } if (semafor) break; /* počkáme na další událost */ if ((r = libusb_handle_events_timeout(p->ctx, &tv)) < 0) { fprintf( stderr, "libusb_handle_events returned: %d\n", r); if (r == LIBUSB_ERROR_INTERRUPTED) continue; /* stray */ goto failed; } } if (p->async_status != MIRISDR_ASYNC_RUNNING) goto failed; #if defined (_WIN32) && !defined(__MINGW32__) Sleep(20); #else usleep(20000); #endif mirisdr_streaming_stop(p); p->async_status = MIRISDR_ASYNC_PAUSED; return 0; failed: return -1; } libmirisdr-4-2.0.0/src/async.h000066400000000000000000000017141423227345400161000ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ #define DEFAULT_ISO_BUFFER 1024 #define DEFAULT_ISO_BUFFERS 3 #define DEFAULT_ISO_PACKETS 8 #define DEFAULT_ISO_TIMEOUT 1000 #define DEFAULT_BULK_BUFFER 16384 #define DEFAULT_BULK_TIMEOUT 1000 #define DEFAULT_BUF_NUMBER 32 libmirisdr-4-2.0.0/src/constants.h000066400000000000000000000015501423227345400167750ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ #define CTRL_TIMEOUT 2000 #define DEFAULT_RATE 2000000 #define DEFAULT_FREQ 90000000 #define DEFAULT_GAIN 43 libmirisdr-4-2.0.0/src/convenience.c000066400000000000000000000170441423227345400172550ustar00rootroot00000000000000/* * Copyright (C) 2012 by Kyle Keen * * 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 2 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 . */ /* a collection of user friendly tools * todo: use strtol for more flexible int parsing * */ #include #include #include #if !defined(_WIN32) || defined(__MINGW32__) #include #else #include #include #include #define _USE_MATH_DEFINES #endif #include #include "mirisdr.h" double atofs(char *s) /* standard suffixes */ { char last; int len; double suff = 1.0; len = strlen(s); last = s[len-1]; s[len-1] = '\0'; switch (last) { case 'g': case 'G': suff *= 1e3; case 'm': case 'M': suff *= 1e3; case 'k': case 'K': suff *= 1e3; suff *= atof(s); s[len-1] = last; return suff; } s[len-1] = last; return atof(s); } double atoft(char *s) /* time suffixes, returns seconds */ { char last; int len; double suff = 1.0; len = strlen(s); last = s[len-1]; s[len-1] = '\0'; switch (last) { case 'h': case 'H': suff *= 60; case 'm': case 'M': suff *= 60; case 's': case 'S': suff *= atof(s); s[len-1] = last; return suff; } s[len-1] = last; return atof(s); } double atofp(char *s) /* percent suffixes */ { char last; int len; double suff = 1.0; len = strlen(s); last = s[len-1]; s[len-1] = '\0'; switch (last) { case '%': suff *= 0.01; suff *= atof(s); s[len-1] = last; return suff; } s[len-1] = last; return atof(s); } int nearest_gain(mirisdr_dev_t *dev, int target_gain) { int i, r, err1, err2, count, nearest; int* gains; r = mirisdr_set_tuner_gain_mode(dev, 1); if (r < 0) { fprintf(stderr, "WARNING: Failed to enable manual gain.\n"); return r; } count = mirisdr_get_tuner_gains(dev, NULL); if (count <= 0) { return 0; } gains = malloc(sizeof(int) * count); count = mirisdr_get_tuner_gains(dev, gains); nearest = gains[0]; for (i=0; i=0; i--) { if (serial[i] != start_char) { continue;} fprintf(stderr, "PPM calibration found in eeprom.\n"); status = 0; *ppm_error = atoi(serial + i + 1); break; } serial[len-1] = stop_char; return status; } int verbose_reset_buffer(mirisdr_dev_t *dev) { int r; r = mirisdr_reset_buffer(dev); if (r < 0) { fprintf(stderr, "WARNING: Failed to reset buffers.\n");} return r; } int verbose_device_search(char *s) { int i, device_count, device, offset; char *s2; char vendor[256], product[256], serial[256]; device_count = mirisdr_get_device_count(); if (!device_count) { fprintf(stderr, "No supported devices found.\n"); return -1; } fprintf(stderr, "Found %d device(s):\n", device_count); for (i = 0; i < device_count; i++) { mirisdr_get_device_usb_strings(i, vendor, product, serial); fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial); } fprintf(stderr, "\n"); /* does string look like raw id number */ device = (int)strtol(s, &s2, 0); if (s2[0] == '\0' && device >= 0 && device < device_count) { fprintf(stderr, "Using device %d: %s\n", device, mirisdr_get_device_name((uint32_t)device)); return device; } /* does string exact match a serial */ for (i = 0; i < device_count; i++) { mirisdr_get_device_usb_strings(i, vendor, product, serial); if (strcmp(s, serial) != 0) { continue;} device = i; fprintf(stderr, "Using device %d: %s\n", device, mirisdr_get_device_name((uint32_t)device)); return device; } /* does string prefix match a serial */ for (i = 0; i < device_count; i++) { mirisdr_get_device_usb_strings(i, vendor, product, serial); if (strncmp(s, serial, strlen(s)) != 0) { continue;} device = i; fprintf(stderr, "Using device %d: %s\n", device, mirisdr_get_device_name((uint32_t)device)); return device; } /* does string suffix match a serial */ for (i = 0; i < device_count; i++) { mirisdr_get_device_usb_strings(i, vendor, product, serial); offset = strlen(serial) - strlen(s); if (offset < 0) { continue;} if (strncmp(s, serial+offset, strlen(s)) != 0) { continue;} device = i; fprintf(stderr, "Using device %d: %s\n", device, mirisdr_get_device_name((uint32_t)device)); return device; } fprintf(stderr, "No matching devices found.\n"); return -1; } // vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab libmirisdr-4-2.0.0/src/convert/000077500000000000000000000000001423227345400162675ustar00rootroot00000000000000libmirisdr-4-2.0.0/src/convert/252_s16.c000066400000000000000000000022631423227345400174370ustar00rootroot00000000000000 /* * 14 bitový formát * 1024 bajtů odpovídá 504 hodnotám * struktura: * 16b hlavička * 1008b bloků obsahujících 504 14b hodnot tvářících se jako 16b */ static int mirisdr_samples_convert_252_s16 (mirisdr_dev_t *p, unsigned char* buf, uint8_t *dst8, int cnt) { int i, i_max, j, ret = 0; uint32_t addr = 0; uint8_t *src = buf; int16_t *dst = (int16_t*) dst8; /* dostáváme 1-3 1024 bytů dlouhé bloky */ for (i_max = cnt >> 10, i = 0; i < i_max; i++, src+= 1008) { /* pozice hlavičky */ addr = src[3] << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0; /* potenciálně ztracená data */ if ((i == 0) && (addr != p->addr)) { fprintf(stderr, "%u samples lost, %d, %08x:%08x\n", addr - p->addr, cnt, p->addr, addr); } /* přeskočíme hlavičku 16 bitů, 252 I+Q párů */ for (src+= 16, j = 0; j < 1008; j+= 4, ret+= 2) { /* maximální rozsah */ dst[ret + 0] = (src[j + 0] << 2) | (src[j + 1] << 10); dst[ret + 1] = (src[j + 2] << 2) | (src[j + 3] << 10); } } p->addr = addr + 252; /* total used bytes */ return ret * 2; } libmirisdr-4-2.0.0/src/convert/336_s16.c000066400000000000000000000023231423227345400174370ustar00rootroot00000000000000 /* * 12 bitový formát * 1024 bajtů odpovídá 672 hodnotám * struktura: * 16b hlavička * 1008b bloků obsahujících 672 12b hodnot */ static int mirisdr_samples_convert_336_s16 (mirisdr_dev_t *p, unsigned char* buf, uint8_t *dst8, int cnt) { int i, i_max, j, ret = 0; uint32_t addr = 0; uint8_t *src = buf; int16_t *dst = (int16_t*) dst8; /* dostáváme 1-3 1024 bytů dlouhé bloky */ for (i_max = cnt >> 10, i = 0; i < i_max; i++, src+= 1008) { /* pozice hlavičky */ addr = src[3] << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0; /* potenciálně ztracená data */ if ((i == 0) && (addr != p->addr)) { fprintf(stderr, "%u samples lost, %d, %08x:%08x\n", addr - p->addr, cnt, p->addr, addr); } /* přeskočíme hlavičku 16 bitů, 336 I+Q párů */ for (src+= 16, j = 0; j < 1008; j+= 3, ret+= 2) { /* plný rozsah zaručí správné znaménko */ dst[ret + 0] = ((src[j + 0] & 0xff) << 4) | ((src[j + 1] & 0x0f) << 12); dst[ret + 1] = ((src[j + 1] & 0xf0) << 0) | ((src[j + 2] & 0xff) << 8); } } p->addr = addr + 336; /* total used bytes */ return ret * 2; } libmirisdr-4-2.0.0/src/convert/384_s16.c000066400000000000000000000057731423227345400174560ustar00rootroot00000000000000 /* * 10+2 bitový formát * 1024 bajtů odpovídá 768 hodnotám * struktura: * 16b hlavička * 984b 6 bloků o velikosti 164b * 160b = 128x 10b hodnot * 4b = posun vlevo 2b * 24b kontrolní součet */ static int mirisdr_samples_convert_384_s16 (mirisdr_dev_t *p, unsigned char* buf, uint8_t *dst8, int cnt) { int i, i_max, j, k, ret = 0; uint32_t addr = 0, shift; uint8_t *src = buf; int16_t *dst = (int16_t*) dst8; /* dostáváme 1-3 1024 bytů dlouhé bloky, poslední část je 24 bitů, tu nezpracováváme */ for (i_max = cnt >> 10, i = 0; i < i_max; i++, src+= 24) { /* pozice hlavičky */ addr = src[3] << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0; /* potenciálně ztracená data */ if ((i == 0) && (addr != p->addr)) { fprintf(stderr, "%u samples lost, %d, %08x:%08x\n", addr - p->addr, cnt, p->addr, addr); } /* přeskočíme hlavičku 16 bitů, 6 bloků, poslední 4 bajtový posuvný blok zpracujeme */ for (src+= 16, j = 0; j < 6; j++, src+= 4) { /* 2 bity pro každou hodnotu - určení posunu */ shift = src[160 + 3] << 24 | src[160 + 2] << 16 | src[160 + 1] << 8 | src[160 + 0] << 0; /* 16x 10 bajtů */ for (k = 0; k < 16; k++, src+= 10, ret+= 8) { /* 10 bajtů na 8 vzorků, plný rozsah zaručí správné znaménko */ dst[ret + 0] = ((src[0] & 0xff) << 6) | ((src[1] & 0x03) << 14); dst[ret + 1] = ((src[1] & 0xfc) << 4) | ((src[2] & 0x0f) << 12); dst[ret + 2] = ((src[2] & 0xf0) << 2) | ((src[3] & 0x3f) << 10); dst[ret + 3] = ((src[3] & 0xc0) << 0) | ((src[4] & 0xff) << 8); dst[ret + 4] = ((src[5] & 0xff) << 6) | ((src[6] & 0x03) << 14); dst[ret + 5] = ((src[6] & 0xfc) << 4) | ((src[7] & 0x0f) << 12); dst[ret + 6] = ((src[7] & 0xf0) << 2) | ((src[8] & 0x3f) << 10); dst[ret + 7] = ((src[8] & 0xc0) << 0) | ((src[9] & 0xff) << 8); /* posun vpravo respektuje signed bit */ switch ((shift >> (2 * k)) & 0x3) { case 0: dst[ret + 0]>>= 2; dst[ret + 1]>>= 2; dst[ret + 2]>>= 2; dst[ret + 3]>>= 2; dst[ret + 4]>>= 2; dst[ret + 5]>>= 2; dst[ret + 6]>>= 2; dst[ret + 7]>>= 2; break; case 1: dst[ret + 0]>>= 1; dst[ret + 1]>>= 1; dst[ret + 2]>>= 1; dst[ret + 3]>>= 1; dst[ret + 4]>>= 1; dst[ret + 5]>>= 1; dst[ret + 6]>>= 1; dst[ret + 7]>>= 1; break; /* 2 = 3 */ } } } } p->addr = addr + 384; /* total used bytes */ return ret * 2; } libmirisdr-4-2.0.0/src/convert/504_s16.c000066400000000000000000000022411423227345400174330ustar00rootroot00000000000000 /* * 8 bitový formát * 1024 bajtů odpovídá 1008 hodnotám * struktura: * 16b hlavička * 1008b bloků obsahujících 1008 8b hodnot */ static int mirisdr_samples_convert_504_s16 (mirisdr_dev_t *p, unsigned char* buf, uint8_t *dst8, int cnt) { int i, i_max, j, ret = 0; uint32_t addr = 0; uint8_t *src = buf; int16_t *dst = (int16_t*) dst8; /* dostáváme 1-3 1024 bytů dlouhé bloky */ for (i_max = cnt >> 10, i = 0; i < i_max; i++, src+= 1008) { /* pozice hlavičky */ addr = src[3] << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0; /* potenciálně ztracená data */ if ((i == 0) && (addr != p->addr)) { fprintf(stderr, "%u samples lost, %d, %08x:%08x\n", addr - p->addr, cnt, p->addr, addr); } /* přeskočíme hlavičku 16 bitů, 504 I+Q párů */ for (src+= 16, j = 0; j < 1008; j+= 2, ret+= 2) { /* bitovým posunem zajistíme plný rozsah a zároveň správné znaménko */ dst[ret + 0] = src[j + 0] << 8; dst[ret + 1] = src[j + 1] << 8; } } p->addr = addr + 504; /* total used bytes */ return ret * 2; } libmirisdr-4-2.0.0/src/convert/504_s8.c000066400000000000000000000012421423227345400173540ustar00rootroot00000000000000 /* * 8 bitový formát * 1024 bajtů odpovídá 1008 hodnotám * struktura: * 16b hlavička * 1008b bloků obsahujících 1008 8b hodnot */ static int mirisdr_samples_convert_504_s8 (mirisdr_dev_t *p, unsigned char* src, uint8_t *dst, int cnt) { int i, ret = 0; uint32_t addr = src[3] << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0; /* ztracená data */ if (p->addr != addr) { fprintf(stderr, "%u samples lost, %d, %08x:%08x\n", addr - p->addr, cnt, p->addr, addr); p->addr = addr; } for (i = 16; i < cnt; i+= 1024, ret+= 1008) { memcpy(dst + ret, src + i, 1008); p->addr+= 504; } return ret; } libmirisdr-4-2.0.0/src/convert/base.c000066400000000000000000000001521423227345400173430ustar00rootroot00000000000000 #include "252_s16.c" #include "336_s16.c" #include "384_s16.c" #include "504_s16.c" #include "504_s8.c" libmirisdr-4-2.0.0/src/devices.c000066400000000000000000000073501423227345400164020ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ static mirisdr_device_t mirisdr_devices[] = { { 0x1df7, 0x2500, "Mirics MSi2500 default (e.g. VTX3D card)", "Mirics", "MSi2500"}, { 0x1df7, 0x3000, "SDRplay RSP1A", "SDRPlay", "RSP1A"}, { 0x1df7, 0x3010, "SDRplay RSP1A", "SDRPlay", "RSP2"}, { 0x2040, 0xd300, "Hauppauge WinTV 133559 LF", "Hauppauge", "WinTV 133559 LF"}, { 0x07ca, 0x8591, "AverMedia A859 Pure DVBT", "AverTV", "A859 Pure DVBT"}, { 0x04bb, 0x0537, "IO-DATA GV-TV100 stick", "IO-DATA", "GV-TV100"}, { 0x0511, 0x0037, "Logitec LDT-1S310U/J", "Logitec", "LDT-1S310U/J"} }; static mirisdr_device_t *mirisdr_device_get (uint16_t vid, uint16_t pid) { size_t i; for (i = 0; i < sizeof(mirisdr_devices) / sizeof(mirisdr_device_t); i++) { if ((mirisdr_devices[i].vid == vid) && (mirisdr_devices[i].pid == pid)) return &mirisdr_devices[i]; } return NULL; } /* počet dostupných zařízení */ uint32_t mirisdr_get_device_count (void) { ssize_t i, i_max; uint32_t ret = 0; libusb_context *ctx; libusb_device **list; struct libusb_device_descriptor dd; libusb_init(&ctx); i_max = libusb_get_device_list(ctx, &list); for (i = 0; i < i_max; i++) { libusb_get_device_descriptor(list[i], &dd); if (mirisdr_device_get(dd.idVendor, dd.idProduct)) ret++; } libusb_free_device_list(list, 1); libusb_exit(ctx); return ret; } /* název zařízení */ const char *mirisdr_get_device_name (uint32_t index) { ssize_t i, i_max; size_t j = 0; libusb_context *ctx; libusb_device **list; struct libusb_device_descriptor dd; mirisdr_device_t *device = NULL; libusb_init(&ctx); i_max = libusb_get_device_list(ctx, &list); for (i = 0; i < i_max; i++) { libusb_get_device_descriptor(list[i], &dd); if ((device = mirisdr_device_get(dd.idVendor, dd.idProduct)) && (j++ == index)) { libusb_free_device_list(list, 1); libusb_exit(ctx); return device->name; } } libusb_free_device_list(list, 1); libusb_exit(ctx); return ""; } /* vlastní implementace */ int mirisdr_get_device_usb_strings (uint32_t index, char *manufact, char *product, char *serial) { ssize_t i, i_max; size_t j = 0; libusb_context *ctx; libusb_device **list; struct libusb_device_descriptor dd; mirisdr_device_t *device = NULL; libusb_init(&ctx); i_max = libusb_get_device_list(ctx, &list); for (i = 0; i < i_max; i++) { libusb_get_device_descriptor(list[i], &dd); if ((device = mirisdr_device_get(dd.idVendor, dd.idProduct)) && (j++ == index)) { strcpy(manufact, device->manufacturer); strcpy(product, device->product); sprintf(serial, "%08u", index + 1); libusb_free_device_list(list, 1); libusb_exit(ctx); return 0; } } memset(manufact, 0, 256); memset(product, 0, 256); memset(serial, 0, 256); libusb_free_device_list(list, 1); libusb_exit(ctx); return -1; } libmirisdr-4-2.0.0/src/gain.c000066400000000000000000000156451423227345400157040ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ #include "gain.h" int mirisdr_set_gain(mirisdr_dev_t *p) { uint32_t reg1 = 1, reg6 = 6; #if MIRISDR_DEBUG >= 1 fprintf (stderr, "gain reduction baseband: %d, lna: %d, mixer: %d\n", p->gain_reduction_baseband, p->gain_reduction_lna, p->gain_reduction_mixer); #endif // Reset to 0xf380 to enable gain control added Dec 5 2014 SM5BSZ // mirisdr_write_reg(p, 0x08, 0xf380); /* Receiver Gain Control */ /* 0-3 => registr */ /* 4-9 => baseband, 0 - 59, 60-63 je stejné jako 59 */ /* 10-11 => mixer gain reduction pouze pro AM režim */ /* 12 => mixer gain reduction -19dB */ /* 13 => lna gain reduction -24dB */ /* 14-16 => DC kalibrace */ /* 17 => zrychlená DC kalibrace */ reg1 |= p->gain_reduction_baseband << 4; // Mixbuffer is on AM1 and AM2 inputs only if (p->band == MIRISDR_BAND_AM1) { reg1 |= (p->gain_reduction_mixbuffer & 0x03) << 10; } else if (p->band == MIRISDR_BAND_AM2) { fprintf(stderr, "mirisdr_set_gain: gain_reduction_mixbuffer: %d\n", p->gain_reduction_mixbuffer); reg1 |= (p->gain_reduction_mixbuffer == 0 ? 0x0 : 0x03) << 10; } else { reg1 |= 0x0 << 10; } reg1 |= p->gain_reduction_mixer << 12; // LNA is not on AM1 nor AM2 inputs if ((p->band == MIRISDR_BAND_AM1) || (p->band == MIRISDR_BAND_AM2)) { reg1 |= 0x0 << 13; } else { reg1 |= p->gain_reduction_lna << 13; } reg1 |= MIRISDR_DC_OFFSET_CALIBRATION_PERIODIC2 << 14; reg1 |= MIRISDR_DC_OFFSET_CALIBRATION_SPEEDUP_OFF << 17; mirisdr_write_reg(p, 0x09, reg1); /* DC Offset Calibration setup */ reg6 |= 0x1F << 4; reg6 |= 0x800 << 10; mirisdr_write_reg(p, 0x09, reg6); //// set to 0xf300 to select AM input added Dec 5 2014 SM5BSZ // if (p->freq < 50000000) // { // mirisdr_write_reg(p, 0x08, 0xf300); // } // else // { // if (p->freq >= 108000000) // { //// Nothing between 00 and 0xff helps to switch in signals above 108 MHz. //// mirisdr_write_reg(p, 0x08, 0xf3ff); // } // } return 0; } int mirisdr_get_tuner_gains(mirisdr_dev_t *dev, int *gains) { int i; (void) dev; i = 103; if (gains) { for (i = 0; i <= 102; i++) { gains[i] = i; } } return i; } int mirisdr_set_tuner_gain(mirisdr_dev_t *p, int gain) { p->gain = gain; /* * Pro VHF režim je lna zapnutý +24dB, mixer +19dB a baseband * je možné nastavovat plynule od 0 - 59 dB, z toho je maximální * zesílení 102 dB * * For VHF mode LNA is turned on to + 24 db, mixer to + 19 dB and baseband * can be adjusted continuously from 0 to 59 db, of which the maximum gain of 102 db */ if (p->gain > 102) { p->gain = 102; } else if (p->gain < 0) { goto gain_auto; } /* Nejvyšší citlivost vždy bez redukce mixeru a lna */ /* Always the highest sensitivity without reducing the mixer and LNA */ if (p->gain >= 43) { p->gain_reduction_lna = 0; p->gain_reduction_mixbuffer = 0; // LNA equivalent for AM inputs p->gain_reduction_mixer = 0; p->gain_reduction_baseband = 59 - (p->gain - 43); } else if (p->gain >= 19) { p->gain_reduction_lna = 1; p->gain_reduction_mixbuffer = 3; // LNA equivalent for AM inputs (AM1: 18dB / AM2: 24 dB) p->gain_reduction_mixer = 0; p->gain_reduction_baseband = 59 - (p->gain - 19); } else { p->gain_reduction_lna = 1; p->gain_reduction_mixbuffer = 3; // LNA equivalent for AM inputs (AM1: 18dB / AM2: 24 dB) p->gain_reduction_mixer = 1; p->gain_reduction_baseband = 59 - p->gain; } return mirisdr_set_gain(p); gain_auto: return mirisdr_set_tuner_gain_mode(p, 0); } int mirisdr_get_tuner_gain(mirisdr_dev_t *p) { int gain = 0; if (p->gain < 0) goto gain_auto; gain += 59 - p->gain_reduction_baseband; if (p->band == MIRISDR_BAND_AM1) { gain += 18 - 6*p->gain_reduction_mixbuffer; } else if (p->band == MIRISDR_BAND_AM2) { gain += (p->gain_reduction_mixbuffer == 0 ? 24 : 0); } else { if (!p->gain_reduction_lna) { gain += 24; } } if (!p->gain_reduction_mixer) { gain += 19; } return gain; gain_auto: return -1; } int mirisdr_set_tuner_gain_mode(mirisdr_dev_t *p, int mode) { // if (!mode) { // p->gain = -1; //#if MIRISDR_DEBUG >= 1 // fprintf( stderr, "gain mode: auto\n"); //#endif // mirisdr_write_reg(p, 0x09, 0x014281); // mirisdr_write_reg(p, 0x09, 0x3FFFF6); // } else if (p->gain < 0) { //#if MIRISDR_DEBUG >= 1 // fprintf( stderr, "gain mode: manual\n"); //#endif // p->gain = DEFAULT_GAIN; // } return 0; } int mirisdr_get_tuner_gain_mode(mirisdr_dev_t *p) { return (p->gain < 0) ? 0 : 1; } /* * Gain reduction is an index that depends on the AM mode (only applies to AM inputs) * AM1 AM2 * 0x00 0 dB 0 dB * 0x01 6 dB 24 dB * 0x10 12 dB 24 dB * 0x11 18 dB 24 dB */ int mirisdr_set_mixer_gain(mirisdr_dev_t *p, int gain) { p->gain_reduction_mixer = gain; return mirisdr_set_gain(p); } int mirisdr_set_mixbuffer_gain(mirisdr_dev_t *p, int gain) { p->gain_reduction_mixbuffer = gain & 0x03; return mirisdr_set_gain(p); } int mirisdr_set_lna_gain(mirisdr_dev_t *p, int gain) { p->gain_reduction_lna = gain; return mirisdr_set_gain(p); } int mirisdr_set_baseband_gain(mirisdr_dev_t *p, int gain) { p->gain_reduction_baseband = 59 - gain; return mirisdr_set_gain(p); } int mirisdr_get_mixer_gain(mirisdr_dev_t *p) { return p->gain_reduction_mixer ? 0 : 19; } int mirisdr_get_mixbuffer_gain(mirisdr_dev_t *p) { if (p->band == MIRISDR_BAND_AM1) { return 18 - 6*p->gain_reduction_mixbuffer; } else if (p->band == MIRISDR_BAND_AM2) { return p->gain_reduction_mixbuffer == 0 ? 24 : 0; } else { return 0; } } int mirisdr_get_lna_gain(mirisdr_dev_t *p) { return p->gain_reduction_lna ? 0 : 24; } int mirisdr_get_baseband_gain(mirisdr_dev_t *p) { return 59 - p->gain_reduction_baseband; } libmirisdr-4-2.0.0/src/gain.h000066400000000000000000000031341423227345400156770ustar00rootroot00000000000000 /*** Register 1: Receiver Gain Control ***/ /* reg1: 4:9 (BBGAIN0 - BBGAIN5) */ #define MIRISDR_BASEBAND_GAIN_REDUCTION_MIN 0 #define MIRISDR_BASEBAND_GAIN_REDUCTION_MAX 0x3B /* reg1: 10:11 (MIXBU0, MIXBU1) - AM port 1 */ #define MIRISDR_AM_PORT1_BLOCKUP_CONVERT_GAIN_REDUCTION_0DB 0 #define MIRISDR_AM_PORT1_BLOCKUP_CONVERT_GAIN_REDUCTION_6DB 1 #define MIRISDR_AM_PORT1_BLOCKUP_CONVERT_GAIN_REDUCTION_12DB 2 #define MIRISDR_AM_PORT1_BLOCKUP_CONVERT_GAIN_REDUCTION_18DB 3 /* reg1: 10:11 (MIXBU0, MIXBU1) - AM port 2 */ #define MIRISDR_AM_PORT2_BLOCKUP_CONVERT_GAIN_REDUCTION_0DB 0 #define MIRISDR_AM_PORT2_BLOCKUP_CONVERT_GAIN_REDUCTION_24DB 3 /* reg1: 12 (MIXL) */ #define MIRISDR_LNA_GAIN_REDUCTION_OFF 0 #define MIRISDR_LNA_GAIN_REDUCTION_ON 1 /* reg1: 13 (LNAGR) */ #define MIRISDR_MIXER_GAIN_REDUCTION_OFF 0 #define MIRISDR_MIXER_GAIN_REDUCTION_ON 1 /* reg1: 14:16 (DCCAL0 - DCCAL2) */ #define MIRISDR_DC_OFFSET_CALIBRATION_STATIC 0 #define MIRISDR_DC_OFFSET_CALIBRATION_PERIODIC1 1 #define MIRISDR_DC_OFFSET_CALIBRATION_PERIODIC2 2 #define MIRISDR_DC_OFFSET_CALIBRATION_PERIODIC3 3 #define MIRISDR_DC_OFFSET_CALIBRATION_ONE_SHOT 4 #define MIRISDR_DC_OFFSET_CALIBRATION_CONTINUOUS 5 /* reg1: 17 (DCCAL_SPEEDUP) */ #define MIRISDR_DC_OFFSET_CALIBRATION_SPEEDUP_OFF 0 #define MIRISDR_DC_OFFSET_CALIBRATION_SPEEDUP_ON 1 /*** Register 6: DC Offset Calibration setup ***/ /* reg6: 4:7 (DCTRK_TIM0 - DCTRK_TIM3) */ /* reg6: 8:21 (DCRATE_TIM0 - DCRATE_TIM11) */ libmirisdr-4-2.0.0/src/getopt/000077500000000000000000000000001423227345400161115ustar00rootroot00000000000000libmirisdr-4-2.0.0/src/getopt/getopt.c000066400000000000000000000730741423227345400175720ustar00rootroot00000000000000/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ # ifndef const # define const # endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include # include #endif /* GNU C library. */ #ifdef VMS # include # if HAVE_STRING_H - 0 # include # endif #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. */ # if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC # include # ifndef _ # define _(msgid) gettext (msgid) # endif # else # define _(msgid) (msgid) # endif #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Formerly, initialization of getopt depended on optind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ # include # define my_index strchr #else # if 1 //HAVE_STRING_H # include # else # include # endif /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv #ifdef _MSC_VER // DDK will complain if you don't use the stdlib defined getenv #include #else extern char *getenv (); #endif #endif static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ # if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Stored original parameters. XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ extern int __libc_argc; extern char **__libc_argv; /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ # ifdef USE_NONOPTION_FLAGS /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; # endif # ifdef USE_NONOPTION_FLAGS # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } # else # define SWAP_FLAGS(ch1, ch2) # endif #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #if defined _LIBC && defined USE_NONOPTION_FLAGS if (posixly_correct == NULL && argc == __libc_argc && argv == __libc_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { int print_errors = opterr; if (optstring[0] == ':') print_errors = 0; if (argc < 1) return -1; optarg = NULL; if (optind == 0 || !__getopt_initialized) { if (optind == 0) optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) { if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); } nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (print_errors) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (print_errors) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) fprintf (stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == -1) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ libmirisdr-4-2.0.0/src/getopt/getopt.h000066400000000000000000000144571423227345400175770ustar00rootroot00000000000000/* Declarations for getopt. Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifndef _GETOPT_H #ifndef __need_getopt # define _GETOPT_H 1 #endif /* If __GNU_LIBRARY__ is not already defined, either we are being used standalone, or this is the first header included in the source file. If we are being used with glibc, we need to include , but that does not exist if we are standalone. So: if __GNU_LIBRARY__ is not defined, include , which will pull in for us if it's from glibc. (Why ctype.h? It's guaranteed to exist and it doesn't flood the namespace with stuff the way some other headers do.) */ #if !defined __GNU_LIBRARY__ # include #endif #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; #ifndef __need_getopt /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { # if (defined __STDC__ && __STDC__) || defined __cplusplus const char *name; # else char *name; # endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ # define no_argument 0 # define required_argument 1 # define optional_argument 2 #endif /* need getopt */ /* Get definitions and prototypes for functions to process the arguments in ARGV (ARGC of them, minus the program name) for options given in OPTS. Return the option character from OPTS just read. Return -1 when there are no more options. For unrecognized options, or options missing arguments, `optopt' is set to the option letter, and '?' is returned. The OPTS string is a list of characters which are recognized option letters, optionally followed by colons, specifying that that letter takes an argument, to be placed in `optarg'. If a letter in OPTS is followed by two colons, its argument is optional. This behavior is specific to the GNU `getopt'. The argument `--' causes premature termination of argument scanning, explicitly telling `getopt' that there are no more options. If OPTS begins with `--', then non-option arguments are treated as arguments to the option '\0'. This behavior is specific to the GNU `getopt'. */ #if (defined __STDC__ && __STDC__) || defined __cplusplus # ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int __argc, char *const *__argv, const char *__shortopts); # else /* not __GNU_LIBRARY__ */ extern int getopt (); # endif /* __GNU_LIBRARY__ */ # ifndef __need_getopt extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); extern int getopt_long_only (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only); # endif #else /* not __STDC__ */ extern int getopt (); # ifndef __need_getopt extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); # endif #endif /* __STDC__ */ #ifdef __cplusplus } #endif /* Make sure we later can get all the definitions and declarations. */ #undef __need_getopt #endif /* getopt.h */ libmirisdr-4-2.0.0/src/hard.c000066400000000000000000000152401423227345400156730ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ #include "hard.h" /* nastavení parametrů které vyžadují restart */ /* parameters that require restart */ int mirisdr_set_hard(mirisdr_dev_t *p) { int streaming = 0; uint32_t reg3 = 0, reg4 = 0; uint64_t i, vco, n, fract; /* při změně registrů musíme zastavit streamování */ /* at a registry change we must stop streaming */ if (p->async_status == MIRISDR_ASYNC_RUNNING) { streaming = 1; if ((mirisdr_stop_async(p) < 0) || (mirisdr_adc_stop(p) < 0)) { goto failed; } } /* omezení rozsahu */ /* limit the scope of */ if (p->rate > MIRISDR_SAMPLE_RATE_MAX) { fprintf(stderr, "can't set rate %u, setting maximum rate: %d\n", p->rate, MIRISDR_SAMPLE_RATE_MAX); p->rate = MIRISDR_SAMPLE_RATE_MAX; } else if (p->rate < MIRISDR_SAMPLE_RATE_MIN) { fprintf(stderr, "can't set rate %u, setting minimum rate: %d\n", p->rate, MIRISDR_SAMPLE_RATE_MIN); p->rate = MIRISDR_SAMPLE_RATE_MIN; } /* automatická volba formátu */ /* automatic choice format */ if (p->format_auto == MIRISDR_FORMAT_AUTO_ON) { if (p->rate <= 6048000) { p->format = MIRISDR_FORMAT_252_S16; } else if (p->rate <= 8064000) { p->format = MIRISDR_FORMAT_336_S16; } else if (p->rate <= 9216000) { p->format = MIRISDR_FORMAT_384_S16; } else { p->format = MIRISDR_FORMAT_504_S16; } } /* typ forámtu a šířka pásma */ /* format type and bandwidth */ switch (p->format) { case MIRISDR_FORMAT_252_S16: /* maximum rate 6.048 Msps | 24.576 MB/s | 196.608 Mbit/s */ #if MIRISDR_DEBUG >= 1 fprintf( stderr, "format: 252\n"); #endif mirisdr_write_reg(p, 0x07, 0x000094); p->addr = 252 + 2; break; case MIRISDR_FORMAT_336_S16: /* maximum rate 8.064 Msps | 24.576 MB/s | 196.608 Mbit/s */ #if MIRISDR_DEBUG >= 1 fprintf( stderr, "format: 336\n"); #endif mirisdr_write_reg(p, 0x07, 0x000085); p->addr = 336 + 2; break; case MIRISDR_FORMAT_384_S16: /* maximum rate 9.216 Msps | 24.576 MB/s | 196.608 Mbit/s */ #if MIRISDR_DEBUG >= 1 fprintf( stderr, "format: 384\n"); #endif mirisdr_write_reg(p, 0x07, 0x0000a5); p->addr = 384 + 2; break; case MIRISDR_FORMAT_504_S16: case MIRISDR_FORMAT_504_S8: /* maximum rate 12.096 Msps | 24.576 MB/s | 196.608 Mbit/s */ #if MIRISDR_DEBUG >= 1 fprintf( stderr, "format: 504\n"); #endif mirisdr_write_reg(p, 0x07, 0x000c94); p->addr = 504 + 2; break; } /* * Výpočet dělení vzorkovací frekvence * Min: >= 1.3 Msps * Max: <= 15 Msps, od 12,096 Msps prokládaně * Poznámka: Nastavení vyšší frekvence než 15 Msps uvede tuner do speciálního * režimu kdy není možné přepnout rate zpět, stejně tak nastavení nižší * frekvence než je 571429 sps, protože pak bude N menší jak 2, což není * přípustný stav. */ /* * Calculating division sampling frequency * Min: >= 1.3 Msps * Max: <= 15 Msps, from 12,096 Msps interpolated * Note: Setting a higher frequency than 15 Msps indicate tuner into a special mode * where you can not switch back rate, as well as setting a lower frequency than 571,429 SPS * because it will be less than N 2, which is not an acceptable condition. */ for (i = 4; i < 16; i += 2) { vco = (uint64_t) p->rate * i * 12; if (vco >= 202000000UL) { break; } } /* z předchozího výpočtu je N minimálně 4 */ /* from the previous calculation N is at least 4 */ n = vco / 48000000UL; fract = 0x200000UL * (vco % 48000000UL) / 48000000UL; #if MIRISDR_DEBUG >= 1 fprintf( stderr, "rate: %u, vco: %lu (%lu), n: %lu, fraction: %lu\n", p->rate, (long unsigned int)vco, (long unsigned int)(i / 2) - 1, (long unsigned int)n, (long unsigned int)fract); #endif /* nastavení vzorkovací frekvence */ /* Setting the sampling rate */ reg3 |= (0x03 & 3) << 0; /* ?? */ reg3 |= (0x07 & (i / 2 - 1)) << 2; /* rozlišení / distinction */ reg3 |= (0x03 & 0) << 5; /* ?? */ reg3 |= (0x01 & (fract >> 20)) << 7; /* +0.5 */ reg3 |= (0x0f & n) << 8; /* hlavní rozsah / main range */ switch (p->format) { /* AGC */ case MIRISDR_FORMAT_252_S16: reg3 |= (0x0f & 0x01) << 12; break; case MIRISDR_FORMAT_336_S16: reg3 |= (0x0f & 0x05) << 12; break; case MIRISDR_FORMAT_384_S16: reg3 |= (0x0f & 0x09) << 12; break; case MIRISDR_FORMAT_504_S16: case MIRISDR_FORMAT_504_S8: reg3 |= (0x0f & 0x0d) << 12; break; } reg3 |= (0x01 & 1) << 16; /* ?? */ /* registr pro detailní nastavení vzorkovací frekvence */ /* Registry settings for detailed sampling frequency */ reg4 |= (0xfffff & fract) << 0; mirisdr_write_reg(p, 0x04, reg4); mirisdr_write_reg(p, 0x03, reg3); /* opětovné spuštění streamu */ /* restart stream */ if ((streaming) && (mirisdr_start_async(p) < 0)) { goto failed; } return 0; failed: return -1; } int mirisdr_set_sample_rate(mirisdr_dev_t *p, uint32_t rate) { p->rate = rate; return mirisdr_set_hard(p); } uint32_t mirisdr_get_sample_rate(mirisdr_dev_t *p) { return p->rate; } int mirisdr_set_sample_format(mirisdr_dev_t *p, char *v) { if (!strcmp(v, "AUTO")) { p->format_auto = MIRISDR_FORMAT_AUTO_ON; } else { p->format_auto = MIRISDR_FORMAT_AUTO_OFF; if (!strcmp(v, "252_S16")) { p->format = MIRISDR_FORMAT_252_S16; } else if (!strcmp(v, "336_S16")) { p->format = MIRISDR_FORMAT_336_S16; } else if (!strcmp(v, "384_S16")) { p->format = MIRISDR_FORMAT_384_S16; } else if (!strcmp(v, "504_S16")) { p->format = MIRISDR_FORMAT_504_S16; } else if (!strcmp(v, "504_S8")) { p->format = MIRISDR_FORMAT_504_S8; } else { fprintf(stderr, "unsupported format: %s\n", v); goto failed; } } return mirisdr_set_hard(p); failed: return -1; } const char *mirisdr_get_sample_format(mirisdr_dev_t *p) { if (p->format_auto == MIRISDR_FORMAT_AUTO_ON) { return "AUTO"; } switch (p->format) { case MIRISDR_FORMAT_252_S16: return "252_S16"; case MIRISDR_FORMAT_336_S16: return "336_S16"; case MIRISDR_FORMAT_384_S16: return "384_S16"; case MIRISDR_FORMAT_504_S16: return "504_S16"; case MIRISDR_FORMAT_504_S8: return "504_S8"; } return ""; } libmirisdr-4-2.0.0/src/hard.h000066400000000000000000000014571423227345400157050ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ #define MIRISDR_SAMPLE_RATE_MIN 1300000 #define MIRISDR_SAMPLE_RATE_MAX 15000000 libmirisdr-4-2.0.0/src/libmirisdr.c000066400000000000000000000154051423227345400171200ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ /* potřebné funkce */ #include #include #include #include #include #include #if !defined (_WIN32) || defined(__MINGW32__) #include #define min(a, b) (((a) < (b)) ? (a) : (b)) #endif #include "libusb.h" #ifndef LIBUSB_CALL #define LIBUSB_CALL #endif /* hlavní hlavičkový soubor */ #include "mirisdr.h" /* interní definice */ #include "constants.h" #include "structs.h" /* interní funkce - inline */ #include "reg.c" #include "adc.c" #include "convert/base.c" #include "async.c" #include "devices.c" #include "gain.c" #include "hard.c" #include "streaming.c" #include "soft.c" #include "sync.c" int mirisdr_open (mirisdr_dev_t **p, uint32_t index) { mirisdr_dev_t *dev = NULL; libusb_device **list, *device = NULL; struct libusb_device_descriptor dd; ssize_t i, i_max; size_t count = 0; int r; *p = NULL; if (!(dev = malloc(sizeof(*dev)))) return -ENOMEM; memset(dev, 0, sizeof(*dev)); /* ostatní parametry */ dev->index = index; libusb_init(&dev->ctx); i_max = libusb_get_device_list(dev->ctx, &list); for (i = 0; i < i_max; i++) { libusb_get_device_descriptor(list[i], &dd); if ((mirisdr_device_get(dd.idVendor, dd.idProduct)) && (count++ == index)) { device = list[i]; break; } } /* nenašli jsme zařízení */ if (!device) { libusb_free_device_list(list, 1); fprintf( stderr, "no miri device %u found\n", dev->index); goto failed; } /* otevření zařízení */ if ((r = libusb_open(device, &dev->dh)) < 0) { libusb_free_device_list(list, 1); fprintf( stderr, "failed to open miri usb device %u with code %d\n", dev->index, r); goto failed; } libusb_free_device_list(list, 1); /* reset je potřeba, jinak občas zařízení odmítá komunikovat */ mirisdr_reset(dev); /* ještě je třeba vždy ukončit i streamování, které může být při otevření aktivní */ mirisdr_streaming_stop(dev); mirisdr_adc_stop(dev); if (libusb_kernel_driver_active(dev->dh, 0) == 1) { dev->driver_active = 1; #ifdef DETACH_KERNEL_DRIVER if (!libusb_detach_kernel_driver(dev->dh, 0)) { fprintf(stderr, "Detached kernel driver\n"); } else { fprintf(stderr, "Detaching kernel driver failed!"); dev->driver_active = 0; goto failed; } #else fprintf(stderr, "\nKernel driver is active, or device is " "claimed by second instance of libmirisdr." "\nIn the first case, please either detach" " or blacklist the kernel module\n" "(msi001 and msi2500), or enable automatic" " detaching at compile time.\n\n"); #endif } else { dev->driver_active = 0; } if ((r = libusb_claim_interface(dev->dh, 0)) < 0) { fprintf( stderr, "failed to claim miri usb device %u with code %d\n", dev->index, r); goto failed; } /* inicializace tuneru */ dev->freq = DEFAULT_FREQ; dev->rate = DEFAULT_RATE; dev->gain = DEFAULT_GAIN; dev->band = MIRISDR_BAND_VHF; // matches always the default frequency of 90 MHz dev->gain_reduction_lna = 0; dev->gain_reduction_mixer = 0; dev->gain_reduction_baseband = 43; dev->if_freq = MIRISDR_IF_ZERO; dev->format_auto = MIRISDR_FORMAT_AUTO_ON; dev->bandwidth = MIRISDR_BW_8MHZ; dev->xtal = MIRISDR_XTAL_24M; dev->bias = 0; dev->hw_flavour = MIRISDR_HW_DEFAULT; /* ISOC is more stable but works only on Unix systems */ #if !defined (_WIN32) || defined(__MINGW32__) dev->transfer = MIRISDR_TRANSFER_ISOC; #else dev->transfer = MIRISDR_TRANSFER_BULK; #endif mirisdr_adc_init(dev); mirisdr_set_hard(dev); mirisdr_set_soft(dev); mirisdr_set_gain(dev); *p = dev; return 0; failed: if (dev) { if (dev->dh) { libusb_release_interface(dev->dh, 0); libusb_close(dev->dh); } if (dev->ctx) libusb_exit(dev->ctx); free(dev); } return -1; } int mirisdr_close (mirisdr_dev_t *p) { if (!p) goto failed; /* ukončení async čtení okamžitě */ mirisdr_cancel_async_now(p); // similar to rtl-sdr #if defined(_WIN32) && !defined(__MINGW32__) Sleep(1); #else usleep(1000); #endif /* deinicializace tuneru */ if (p->dh) { libusb_release_interface(p->dh, 0); #ifdef DETACH_KERNEL_DRIVER if (p->driver_active) { if (!libusb_attach_kernel_driver(p->dh, 0)) fprintf(stderr, "Reattached kernel driver\n"); else fprintf(stderr, "Reattaching kernel driver failed!\n"); } #endif if (p->async_status != MIRISDR_ASYNC_FAILED) { libusb_close(p->dh); } } if (p->ctx) libusb_exit(p->ctx); free(p); return 0; failed: return -1; } int mirisdr_reset (mirisdr_dev_t *p) { int r; if (!p) goto failed; if (!p->dh) goto failed; /* měli bychom uvolnit zařízení předem? */ if ((r = libusb_reset_device(p->dh)) < 0) { fprintf( stderr, "failed to reset miri usb device %u with code %d\n", p->index, r); goto failed; } return 0; failed: return -1; } int mirisdr_reset_buffer (mirisdr_dev_t *p) { if (!p) goto failed; if (!p->dh) goto failed; /* zatím není jasné k čemu by bylo, proto pouze provedeme reset async části */ mirisdr_stop_async(p); mirisdr_start_async(p); return 0; failed: return -1; } int mirisdr_get_usb_strings (mirisdr_dev_t *dev, char *manufact, char *product, char *serial) { (void) dev; fprintf( stderr, "mirisdr_get_usb_strings not implemented yet\n"); memset(manufact, 0, 256); memset(product, 0, 256); memset(serial, 0, 256); return 0; } int mirisdr_set_hw_flavour (mirisdr_dev_t *p, mirisdr_hw_flavour_t hw_flavour) { if (!p) goto failed; p->hw_flavour = hw_flavour; return 0; failed: return -1; }libmirisdr-4-2.0.0/src/libusb.h.1.0.13000066400000000000000000002110141423227345400167560ustar00rootroot00000000000000/* * Public libusb header file * Copyright © 2001 Johannes Erdfelt * Copyright © 2007-2008 Daniel Drake * Copyright © 2012 Pete Batard * Copyright © 2012 Nathan Hjelm * For more information, please visit: http://libusb.info * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LIBUSB_H #define LIBUSB_H #ifdef _MSC_VER /* on MS environments, the inline keyword is available in C++ only */ #if !defined(__cplusplus) #define inline __inline #endif /* ssize_t is also not available (copy/paste from MinGW) */ #ifndef _SSIZE_T_DEFINED #define _SSIZE_T_DEFINED #undef ssize_t #ifdef _WIN64 typedef __int64 ssize_t; #else typedef int ssize_t; #endif /* _WIN64 */ #endif /* _SSIZE_T_DEFINED */ #endif /* _MSC_VER */ /* stdint.h is not available on older MSVC */ #if defined(_MSC_VER) && (_MSC_VER < 1600) && (!defined(_STDINT)) && (!defined(_STDINT_H)) typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; #else #include #endif #if !defined(_WIN32_WCE) #include #endif #if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) #include #endif #include #include /* 'interface' might be defined as a macro on Windows, so we need to * undefine it so as not to break the current libusb API, because * libusb_config_descriptor has an 'interface' member * As this can be problematic if you include windows.h after libusb.h * in your sources, we force windows.h to be included first. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) #include #if defined(interface) #undef interface #endif #if !defined(__CYGWIN__) #include #endif #endif #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #define LIBUSB_DEPRECATED_FOR(f) \ __attribute__((deprecated("Use " #f " instead"))) #else #define LIBUSB_DEPRECATED_FOR(f) #endif /* __GNUC__ */ /** \def LIBUSB_CALL * \ingroup misc * libusb's Windows calling convention. * * Under Windows, the selection of available compilers and configurations * means that, unlike other platforms, there is not one true calling * convention (calling convention: the manner in which parameters are * passed to funcions in the generated assembly code). * * Matching the Windows API itself, libusb uses the WINAPI convention (which * translates to the stdcall convention) and guarantees that the * library is compiled in this way. The public header file also includes * appropriate annotations so that your own software will use the right * convention, even if another convention is being used by default within * your codebase. * * The one consideration that you must apply in your software is to mark * all functions which you use as libusb callbacks with this LIBUSB_CALL * annotation, so that they too get compiled for the correct calling * convention. * * On non-Windows operating systems, this macro is defined as nothing. This * means that you can apply it to your code without worrying about * cross-platform compatibility. */ /* LIBUSB_CALL must be defined on both definition and declaration of libusb * functions. You'd think that declaration would be enough, but cygwin will * complain about conflicting types unless both are marked this way. * The placement of this macro is important too; it must appear after the * return type, before the function name. See internal documentation for * API_EXPORTED. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) #define LIBUSB_CALL WINAPI #else #define LIBUSB_CALL #endif /** \def LIBUSB_API_VERSION * \ingroup misc * libusb's API version. * * Since version 1.0.13, to help with feature detection, libusb defines * a LIBUSB_API_VERSION macro that gets increased every time there is a * significant change to the API, such as the introduction of a new call, * the definition of a new macro/enum member, or any other element that * libusb applications may want to detect at compilation time. * * The macro is typically used in an application as follows: * \code * #if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01001234) * // Use one of the newer features from the libusb API * #endif * \endcode * * Another feature of LIBUSB_API_VERSION is that it can be used to detect * whether you are compiling against the libusb or the libusb library. * * Internally, LIBUSB_API_VERSION is defined as follows: * (libusb major << 24) | (libusb minor << 16) | (16 bit incremental) */ #define LIBUSB_API_VERSION 0x01000103 /* The following is kept for compatibility, but will be deprecated in the future */ #define LIBUSBX_API_VERSION LIBUSB_API_VERSION #ifdef __cplusplus extern "C" { #endif /** * \ingroup misc * Convert a 16-bit value from host-endian to little-endian format. On * little endian systems, this function does nothing. On big endian systems, * the bytes are swapped. * \param x the host-endian value to convert * \returns the value in little-endian byte order */ static inline uint16_t libusb_cpu_to_le16(const uint16_t x) { union { uint8_t b8[2]; uint16_t b16; } _tmp; _tmp.b8[1] = (uint8_t) (x >> 8); _tmp.b8[0] = (uint8_t) (x & 0xff); return _tmp.b16; } /** \def libusb_le16_to_cpu * \ingroup misc * Convert a 16-bit value from little-endian to host-endian format. On * little endian systems, this function does nothing. On big endian systems, * the bytes are swapped. * \param x the little-endian value to convert * \returns the value in host-endian byte order */ #define libusb_le16_to_cpu libusb_cpu_to_le16 /* standard USB stuff */ /** \ingroup desc * Device and/or Interface Class codes */ enum libusb_class_code { /** In the context of a \ref libusb_device_descriptor "device descriptor", * this bDeviceClass value indicates that each interface specifies its * own class information and all interfaces operate independently. */ LIBUSB_CLASS_PER_INTERFACE = 0, /** Audio class */ LIBUSB_CLASS_AUDIO = 1, /** Communications class */ LIBUSB_CLASS_COMM = 2, /** Human Interface Device class */ LIBUSB_CLASS_HID = 3, /** Physical */ LIBUSB_CLASS_PHYSICAL = 5, /** Printer class */ LIBUSB_CLASS_PRINTER = 7, /** Image class */ LIBUSB_CLASS_PTP = 6, /* legacy name from libusb-0.1 usb.h */ LIBUSB_CLASS_IMAGE = 6, /** Mass storage class */ LIBUSB_CLASS_MASS_STORAGE = 8, /** Hub class */ LIBUSB_CLASS_HUB = 9, /** Data class */ LIBUSB_CLASS_DATA = 10, /** Smart Card */ LIBUSB_CLASS_SMART_CARD = 0x0b, /** Content Security */ LIBUSB_CLASS_CONTENT_SECURITY = 0x0d, /** Video */ LIBUSB_CLASS_VIDEO = 0x0e, /** Personal Healthcare */ LIBUSB_CLASS_PERSONAL_HEALTHCARE = 0x0f, /** Diagnostic Device */ LIBUSB_CLASS_DIAGNOSTIC_DEVICE = 0xdc, /** Wireless class */ LIBUSB_CLASS_WIRELESS = 0xe0, /** Application class */ LIBUSB_CLASS_APPLICATION = 0xfe, /** Class is vendor-specific */ LIBUSB_CLASS_VENDOR_SPEC = 0xff }; /** \ingroup desc * Descriptor types as defined by the USB specification. */ enum libusb_descriptor_type { /** Device descriptor. See libusb_device_descriptor. */ LIBUSB_DT_DEVICE = 0x01, /** Configuration descriptor. See libusb_config_descriptor. */ LIBUSB_DT_CONFIG = 0x02, /** String descriptor */ LIBUSB_DT_STRING = 0x03, /** Interface descriptor. See libusb_interface_descriptor. */ LIBUSB_DT_INTERFACE = 0x04, /** Endpoint descriptor. See libusb_endpoint_descriptor. */ LIBUSB_DT_ENDPOINT = 0x05, /** BOS descriptor */ LIBUSB_DT_BOS = 0x0f, /** Device Capability descriptor */ LIBUSB_DT_DEVICE_CAPABILITY = 0x10, /** HID descriptor */ LIBUSB_DT_HID = 0x21, /** HID report descriptor */ LIBUSB_DT_REPORT = 0x22, /** Physical descriptor */ LIBUSB_DT_PHYSICAL = 0x23, /** Hub descriptor */ LIBUSB_DT_HUB = 0x29, /** SuperSpeed Hub descriptor */ LIBUSB_DT_SUPERSPEED_HUB = 0x2a, /** SuperSpeed Endpoint Companion descriptor */ LIBUSB_DT_SS_ENDPOINT_COMPANION = 0x30 }; /* Descriptor sizes per descriptor type */ #define LIBUSB_DT_DEVICE_SIZE 18 #define LIBUSB_DT_CONFIG_SIZE 9 #define LIBUSB_DT_INTERFACE_SIZE 9 #define LIBUSB_DT_ENDPOINT_SIZE 7 #define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ #define LIBUSB_DT_HUB_NONVAR_SIZE 7 #define LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE 6 #define LIBUSB_DT_BOS_SIZE 5 #define LIBUSB_DT_DEVICE_CAPABILITY_SIZE 3 /* BOS descriptor sizes */ #define LIBUSB_BT_USB_2_0_EXTENSION_SIZE 7 #define LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE 10 #define LIBUSB_BT_CONTAINER_ID_SIZE 20 /* We unwrap the BOS => define its max size */ #define LIBUSB_DT_BOS_MAX_SIZE ((LIBUSB_DT_BOS_SIZE) +\ (LIBUSB_BT_USB_2_0_EXTENSION_SIZE) +\ (LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) +\ (LIBUSB_BT_CONTAINER_ID_SIZE)) #define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */ #define LIBUSB_ENDPOINT_DIR_MASK 0x80 /** \ingroup desc * Endpoint direction. Values for bit 7 of the * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme. */ enum libusb_endpoint_direction { /** In: device-to-host */ LIBUSB_ENDPOINT_IN = 0x80, /** Out: host-to-device */ LIBUSB_ENDPOINT_OUT = 0x00 }; #define LIBUSB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */ /** \ingroup desc * Endpoint transfer type. Values for bits 0:1 of the * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field. */ enum libusb_transfer_type { /** Control endpoint */ LIBUSB_TRANSFER_TYPE_CONTROL = 0, /** Isochronous endpoint */ LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1, /** Bulk endpoint */ LIBUSB_TRANSFER_TYPE_BULK = 2, /** Interrupt endpoint */ LIBUSB_TRANSFER_TYPE_INTERRUPT = 3, /** Stream endpoint */ LIBUSB_TRANSFER_TYPE_BULK_STREAM = 4, }; /** \ingroup misc * Standard requests, as defined in table 9-5 of the USB 3.0 specifications */ enum libusb_standard_request { /** Request status of the specific recipient */ LIBUSB_REQUEST_GET_STATUS = 0x00, /** Clear or disable a specific feature */ LIBUSB_REQUEST_CLEAR_FEATURE = 0x01, /* 0x02 is reserved */ /** Set or enable a specific feature */ LIBUSB_REQUEST_SET_FEATURE = 0x03, /* 0x04 is reserved */ /** Set device address for all future accesses */ LIBUSB_REQUEST_SET_ADDRESS = 0x05, /** Get the specified descriptor */ LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06, /** Used to update existing descriptors or add new descriptors */ LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07, /** Get the current device configuration value */ LIBUSB_REQUEST_GET_CONFIGURATION = 0x08, /** Set device configuration */ LIBUSB_REQUEST_SET_CONFIGURATION = 0x09, /** Return the selected alternate setting for the specified interface */ LIBUSB_REQUEST_GET_INTERFACE = 0x0A, /** Select an alternate interface for the specified interface */ LIBUSB_REQUEST_SET_INTERFACE = 0x0B, /** Set then report an endpoint's synchronization frame */ LIBUSB_REQUEST_SYNCH_FRAME = 0x0C, /** Sets both the U1 and U2 Exit Latency */ LIBUSB_REQUEST_SET_SEL = 0x30, /** Delay from the time a host transmits a packet to the time it is * received by the device. */ LIBUSB_SET_ISOCH_DELAY = 0x31, }; /** \ingroup misc * Request type bits of the * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control * transfers. */ enum libusb_request_type { /** Standard */ LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5), /** Class */ LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5), /** Vendor */ LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5), /** Reserved */ LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5) }; /** \ingroup misc * Recipient bits of the * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control * transfers. Values 4 through 31 are reserved. */ enum libusb_request_recipient { /** Device */ LIBUSB_RECIPIENT_DEVICE = 0x00, /** Interface */ LIBUSB_RECIPIENT_INTERFACE = 0x01, /** Endpoint */ LIBUSB_RECIPIENT_ENDPOINT = 0x02, /** Other */ LIBUSB_RECIPIENT_OTHER = 0x03, }; #define LIBUSB_ISO_SYNC_TYPE_MASK 0x0C /** \ingroup desc * Synchronization type for isochronous endpoints. Values for bits 2:3 of the * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in * libusb_endpoint_descriptor. */ enum libusb_iso_sync_type { /** No synchronization */ LIBUSB_ISO_SYNC_TYPE_NONE = 0, /** Asynchronous */ LIBUSB_ISO_SYNC_TYPE_ASYNC = 1, /** Adaptive */ LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2, /** Synchronous */ LIBUSB_ISO_SYNC_TYPE_SYNC = 3 }; #define LIBUSB_ISO_USAGE_TYPE_MASK 0x30 /** \ingroup desc * Usage type for isochronous endpoints. Values for bits 4:5 of the * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in * libusb_endpoint_descriptor. */ enum libusb_iso_usage_type { /** Data endpoint */ LIBUSB_ISO_USAGE_TYPE_DATA = 0, /** Feedback endpoint */ LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1, /** Implicit feedback Data endpoint */ LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2, }; /** \ingroup desc * A structure representing the standard USB device descriptor. This * descriptor is documented in section 9.6.1 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. */ struct libusb_device_descriptor { /** Size of this descriptor (in bytes) */ uint8_t bLength; /** Descriptor type. Will have value * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this * context. */ uint8_t bDescriptorType; /** USB specification release number in binary-coded decimal. A value of * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */ uint16_t bcdUSB; /** USB-IF class code for the device. See \ref libusb_class_code. */ uint8_t bDeviceClass; /** USB-IF subclass code for the device, qualified by the bDeviceClass * value */ uint8_t bDeviceSubClass; /** USB-IF protocol code for the device, qualified by the bDeviceClass and * bDeviceSubClass values */ uint8_t bDeviceProtocol; /** Maximum packet size for endpoint 0 */ uint8_t bMaxPacketSize0; /** USB-IF vendor ID */ uint16_t idVendor; /** USB-IF product ID */ uint16_t idProduct; /** Device release number in binary-coded decimal */ uint16_t bcdDevice; /** Index of string descriptor describing manufacturer */ uint8_t iManufacturer; /** Index of string descriptor describing product */ uint8_t iProduct; /** Index of string descriptor containing device serial number */ uint8_t iSerialNumber; /** Number of possible configurations */ uint8_t bNumConfigurations; }; /** \ingroup desc * A structure representing the standard USB endpoint descriptor. This * descriptor is documented in section 9.6.6 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. */ struct libusb_endpoint_descriptor { /** Size of this descriptor (in bytes) */ uint8_t bLength; /** Descriptor type. Will have value * \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in * this context. */ uint8_t bDescriptorType; /** The address of the endpoint described by this descriptor. Bits 0:3 are * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction, * see \ref libusb_endpoint_direction. */ uint8_t bEndpointAddress; /** Attributes which apply to the endpoint when it is configured using * the bConfigurationValue. Bits 0:1 determine the transfer type and * correspond to \ref libusb_transfer_type. Bits 2:3 are only used for * isochronous endpoints and correspond to \ref libusb_iso_sync_type. * Bits 4:5 are also only used for isochronous endpoints and correspond to * \ref libusb_iso_usage_type. Bits 6:7 are reserved. */ uint8_t bmAttributes; /** Maximum packet size this endpoint is capable of sending/receiving. */ uint16_t wMaxPacketSize; /** Interval for polling endpoint for data transfers. */ uint8_t bInterval; /** For audio devices only: the rate at which synchronization feedback * is provided. */ uint8_t bRefresh; /** For audio devices only: the address if the synch endpoint */ uint8_t bSynchAddress; /** Extra descriptors. If libusb encounters unknown endpoint descriptors, * it will store them here, should you wish to parse them. */ const unsigned char *extra; /** Length of the extra descriptors, in bytes. */ int extra_length; }; /** \ingroup desc * A structure representing the standard USB interface descriptor. This * descriptor is documented in section 9.6.5 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. */ struct libusb_interface_descriptor { /** Size of this descriptor (in bytes) */ uint8_t bLength; /** Descriptor type. Will have value * \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE * in this context. */ uint8_t bDescriptorType; /** Number of this interface */ uint8_t bInterfaceNumber; /** Value used to select this alternate setting for this interface */ uint8_t bAlternateSetting; /** Number of endpoints used by this interface (excluding the control * endpoint). */ uint8_t bNumEndpoints; /** USB-IF class code for this interface. See \ref libusb_class_code. */ uint8_t bInterfaceClass; /** USB-IF subclass code for this interface, qualified by the * bInterfaceClass value */ uint8_t bInterfaceSubClass; /** USB-IF protocol code for this interface, qualified by the * bInterfaceClass and bInterfaceSubClass values */ uint8_t bInterfaceProtocol; /** Index of string descriptor describing this interface */ uint8_t iInterface; /** Array of endpoint descriptors. This length of this array is determined * by the bNumEndpoints field. */ const struct libusb_endpoint_descriptor *endpoint; /** Extra descriptors. If libusb encounters unknown interface descriptors, * it will store them here, should you wish to parse them. */ const unsigned char *extra; /** Length of the extra descriptors, in bytes. */ int extra_length; }; /** \ingroup desc * A collection of alternate settings for a particular USB interface. */ struct libusb_interface { /** Array of interface descriptors. The length of this array is determined * by the num_altsetting field. */ const struct libusb_interface_descriptor *altsetting; /** The number of alternate settings that belong to this interface */ int num_altsetting; }; /** \ingroup desc * A structure representing the standard USB configuration descriptor. This * descriptor is documented in section 9.6.3 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. */ struct libusb_config_descriptor { /** Size of this descriptor (in bytes) */ uint8_t bLength; /** Descriptor type. Will have value * \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG * in this context. */ uint8_t bDescriptorType; /** Total length of data returned for this configuration */ uint16_t wTotalLength; /** Number of interfaces supported by this configuration */ uint8_t bNumInterfaces; /** Identifier value for this configuration */ uint8_t bConfigurationValue; /** Index of string descriptor describing this configuration */ uint8_t iConfiguration; /** Configuration characteristics */ uint8_t bmAttributes; /** Maximum power consumption of the USB device from this bus in this * configuration when the device is fully opreation. Expressed in units * of 2 mA. */ uint8_t MaxPower; /** Array of interfaces supported by this configuration. The length of * this array is determined by the bNumInterfaces field. */ const struct libusb_interface *interface; /** Extra descriptors. If libusb encounters unknown configuration * descriptors, it will store them here, should you wish to parse them. */ const unsigned char *extra; /** Length of the extra descriptors, in bytes. */ int extra_length; }; /** \ingroup desc * A structure representing the superspeed endpoint companion * descriptor. This descriptor is documented in section 9.6.7 of * the USB 3.0 specification. All multiple-byte fields are represented in * host-endian format. */ struct libusb_ss_endpoint_companion_descriptor { /** Size of this descriptor (in bytes) */ uint8_t bLength; /** Descriptor type. Will have value * \ref libusb_descriptor_type::LIBUSB_DT_SS_ENDPOINT_COMPANION in * this context. */ uint8_t bDescriptorType; /** The maximum number of packets the endpoint can send or * recieve as part of a burst. */ uint8_t bMaxBurst; /** In bulk EP: bits 4:0 represents the maximum number of * streams the EP supports. In isochronous EP: bits 1:0 * represents the Mult - a zero based value that determines * the maximum number of packets within a service interval */ uint8_t bmAttributes; /** The total number of bytes this EP will transfer every * service interval. valid only for periodic EPs. */ uint16_t wBytesPerInterval; }; /** \ingroup desc * A generic representation of a BOS Device Capability descriptor. It is * advised to check bDevCapabilityType and call the matching * libusb_get_*_descriptor function to get a structure fully matching the type. */ struct libusb_bos_dev_capability_descriptor { /** Size of this descriptor (in bytes) */ uint8_t bLength; /** Descriptor type. Will have value * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY * LIBUSB_DT_DEVICE_CAPABILITY in this context. */ uint8_t bDescriptorType; /** Device Capability type */ uint8_t bDevCapabilityType; /** Device Capability data (bLength - 3 bytes) */ uint8_t dev_capability_data #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) [] /* valid C99 code */ #else [0] /* non-standard, but usually working code */ #endif ; }; /** \ingroup desc * A structure representing the Binary Device Object Store (BOS) descriptor. * This descriptor is documented in section 9.6.2 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. */ struct libusb_bos_descriptor { /** Size of this descriptor (in bytes) */ uint8_t bLength; /** Descriptor type. Will have value * \ref libusb_descriptor_type::LIBUSB_DT_BOS LIBUSB_DT_BOS * in this context. */ uint8_t bDescriptorType; /** Length of this descriptor and all of its sub descriptors */ uint16_t wTotalLength; /** The number of separate device capability descriptors in * the BOS */ uint8_t bNumDeviceCaps; /** bNumDeviceCap Device Capability Descriptors */ struct libusb_bos_dev_capability_descriptor *dev_capability #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) [] /* valid C99 code */ #else [0] /* non-standard, but usually working code */ #endif ; }; /** \ingroup desc * A structure representing the USB 2.0 Extension descriptor * This descriptor is documented in section 9.6.2.1 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. */ struct libusb_usb_2_0_extension_descriptor { /** Size of this descriptor (in bytes) */ uint8_t bLength; /** Descriptor type. Will have value * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY * LIBUSB_DT_DEVICE_CAPABILITY in this context. */ uint8_t bDescriptorType; /** Capability type. Will have value * \ref libusb_capability_type::LIBUSB_BT_USB_2_0_EXTENSION * LIBUSB_BT_USB_2_0_EXTENSION in this context. */ uint8_t bDevCapabilityType; /** Bitmap encoding of supported device level features. * A value of one in a bit location indicates a feature is * supported; a value of zero indicates it is not supported. * See \ref libusb_usb_2_0_extension_attributes. */ uint32_t bmAttributes; }; /** \ingroup desc * A structure representing the SuperSpeed USB Device Capability descriptor * This descriptor is documented in section 9.6.2.2 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. */ struct libusb_ss_usb_device_capability_descriptor { /** Size of this descriptor (in bytes) */ uint8_t bLength; /** Descriptor type. Will have value * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY * LIBUSB_DT_DEVICE_CAPABILITY in this context. */ uint8_t bDescriptorType; /** Capability type. Will have value * \ref libusb_capability_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY * LIBUSB_BT_SS_USB_DEVICE_CAPABILITY in this context. */ uint8_t bDevCapabilityType; /** Bitmap encoding of supported device level features. * A value of one in a bit location indicates a feature is * supported; a value of zero indicates it is not supported. * See \ref libusb_ss_usb_device_capability_attributes. */ uint8_t bmAttributes; /** Bitmap encoding of the speed supported by this device when * operating in SuperSpeed mode. See \ref libusb_supported_speed. */ uint16_t wSpeedSupported; /** The lowest speed at which all the functionality supported * by the device is available to the user. For example if the * device supports all its functionality when connected at * full speed and above then it sets this value to 1. */ uint8_t bFunctionalitySupport; /** U1 Device Exit Latency. */ uint8_t bU1DevExitLat; /** U2 Device Exit Latency. */ uint16_t bU2DevExitLat; }; /** \ingroup desc * A structure representing the Container ID descriptor. * This descriptor is documented in section 9.6.2.3 of the USB 3.0 specification. * All multiple-byte fields, except UUIDs, are represented in host-endian format. */ struct libusb_container_id_descriptor { /** Size of this descriptor (in bytes) */ uint8_t bLength; /** Descriptor type. Will have value * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY * LIBUSB_DT_DEVICE_CAPABILITY in this context. */ uint8_t bDescriptorType; /** Capability type. Will have value * \ref libusb_capability_type::LIBUSB_BT_CONTAINER_ID * LIBUSB_BT_CONTAINER_ID in this context. */ uint8_t bDevCapabilityType; /** Reserved field */ uint8_t bReserved; /** 128 bit UUID */ uint8_t ContainerID[16]; }; /** \ingroup asyncio * Setup packet for control transfers. */ struct libusb_control_setup { /** Request type. Bits 0:4 determine recipient, see * \ref libusb_request_recipient. Bits 5:6 determine type, see * \ref libusb_request_type. Bit 7 determines data transfer direction, see * \ref libusb_endpoint_direction. */ uint8_t bmRequestType; /** Request. If the type bits of bmRequestType are equal to * \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD * "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to * \ref libusb_standard_request. For other cases, use of this field is * application-specific. */ uint8_t bRequest; /** Value. Varies according to request */ uint16_t wValue; /** Index. Varies according to request, typically used to pass an index * or offset */ uint16_t wIndex; /** Number of bytes to transfer */ uint16_t wLength; }; #define LIBUSB_CONTROL_SETUP_SIZE (sizeof(struct libusb_control_setup)) /* libusb */ struct libusb_context; struct libusb_device; struct libusb_device_handle; struct libusb_hotplug_callback; /** \ingroup lib * Structure providing the version of the libusb runtime */ struct libusb_version { /** Library major version. */ const uint16_t major; /** Library minor version. */ const uint16_t minor; /** Library micro version. */ const uint16_t micro; /** Library nano version. */ const uint16_t nano; /** Library release candidate suffix string, e.g. "-rc4". */ const char *rc; /** For ABI compatibility only. */ const char* describe; }; /** \ingroup lib * Structure representing a libusb session. The concept of individual libusb * sessions allows for your program to use two libraries (or dynamically * load two modules) which both independently use libusb. This will prevent * interference between the individual libusb users - for example * libusb_set_debug() will not affect the other user of the library, and * libusb_exit() will not destroy resources that the other user is still * using. * * Sessions are created by libusb_init() and destroyed through libusb_exit(). * If your application is guaranteed to only ever include a single libusb * user (i.e. you), you do not have to worry about contexts: pass NULL in * every function call where a context is required. The default context * will be used. * * For more information, see \ref contexts. */ typedef struct libusb_context libusb_context; /** \ingroup dev * Structure representing a USB device detected on the system. This is an * opaque type for which you are only ever provided with a pointer, usually * originating from libusb_get_device_list(). * * Certain operations can be performed on a device, but in order to do any * I/O you will have to first obtain a device handle using libusb_open(). * * Devices are reference counted with libusb_ref_device() and * libusb_unref_device(), and are freed when the reference count reaches 0. * New devices presented by libusb_get_device_list() have a reference count of * 1, and libusb_free_device_list() can optionally decrease the reference count * on all devices in the list. libusb_open() adds another reference which is * later destroyed by libusb_close(). */ typedef struct libusb_device libusb_device; /** \ingroup dev * Structure representing a handle on a USB device. This is an opaque type for * which you are only ever provided with a pointer, usually originating from * libusb_open(). * * A device handle is used to perform I/O and other operations. When finished * with a device handle, you should call libusb_close(). */ typedef struct libusb_device_handle libusb_device_handle; /** \ingroup dev * Speed codes. Indicates the speed at which the device is operating. */ enum libusb_speed { /** The OS doesn't report or know the device speed. */ LIBUSB_SPEED_UNKNOWN = 0, /** The device is operating at low speed (1.5MBit/s). */ LIBUSB_SPEED_LOW = 1, /** The device is operating at full speed (12MBit/s). */ LIBUSB_SPEED_FULL = 2, /** The device is operating at high speed (480MBit/s). */ LIBUSB_SPEED_HIGH = 3, /** The device is operating at super speed (5000MBit/s). */ LIBUSB_SPEED_SUPER = 4, }; /** \ingroup dev * Supported speeds (wSpeedSupported) bitfield. Indicates what * speeds the device supports. */ enum libusb_supported_speed { /** Low speed operation supported (1.5MBit/s). */ LIBUSB_LOW_SPEED_OPERATION = 1, /** Full speed operation supported (12MBit/s). */ LIBUSB_FULL_SPEED_OPERATION = 2, /** High speed operation supported (480MBit/s). */ LIBUSB_HIGH_SPEED_OPERATION = 4, /** Superspeed operation supported (5000MBit/s). */ LIBUSB_SUPER_SPEED_OPERATION = 8, }; /** \ingroup dev * Masks for the bits of the * \ref libusb_usb_2_0_extension_descriptor::bmAttributes "bmAttributes" field * of the USB 2.0 Extension descriptor. */ enum libusb_usb_2_0_extension_attributes { /** Supports Link Power Management (LPM) */ LIBUSB_BM_LPM_SUPPORT = 2, }; /** \ingroup dev * Masks for the bits of the * \ref libusb_ss_usb_device_capability_descriptor::bmAttributes "bmAttributes" field * field of the SuperSpeed USB Device Capability descriptor. */ enum libusb_ss_usb_device_capability_attributes { /** Supports Latency Tolerance Messages (LTM) */ LIBUSB_BM_LTM_SUPPORT = 2, }; /** \ingroup dev * USB capability types */ enum libusb_bos_type { /** Wireless USB device capability */ LIBUSB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 1, /** USB 2.0 extensions */ LIBUSB_BT_USB_2_0_EXTENSION = 2, /** SuperSpeed USB device capability */ LIBUSB_BT_SS_USB_DEVICE_CAPABILITY = 3, /** Container ID type */ LIBUSB_BT_CONTAINER_ID = 4, }; /** \ingroup misc * Error codes. Most libusb functions return 0 on success or one of these * codes on failure. * You can call libusb_error_name() to retrieve a string representation of an * error code or libusb_strerror() to get an end-user suitable description of * an error code. */ enum libusb_error { /** Success (no error) */ LIBUSB_SUCCESS = 0, /** Input/output error */ LIBUSB_ERROR_IO = -1, /** Invalid parameter */ LIBUSB_ERROR_INVALID_PARAM = -2, /** Access denied (insufficient permissions) */ LIBUSB_ERROR_ACCESS = -3, /** No such device (it may have been disconnected) */ LIBUSB_ERROR_NO_DEVICE = -4, /** Entity not found */ LIBUSB_ERROR_NOT_FOUND = -5, /** Resource busy */ LIBUSB_ERROR_BUSY = -6, /** Operation timed out */ LIBUSB_ERROR_TIMEOUT = -7, /** Overflow */ LIBUSB_ERROR_OVERFLOW = -8, /** Pipe error */ LIBUSB_ERROR_PIPE = -9, /** System call interrupted (perhaps due to signal) */ LIBUSB_ERROR_INTERRUPTED = -10, /** Insufficient memory */ LIBUSB_ERROR_NO_MEM = -11, /** Operation not supported or unimplemented on this platform */ LIBUSB_ERROR_NOT_SUPPORTED = -12, /* NB: Remember to update LIBUSB_ERROR_COUNT below as well as the message strings in strerror.c when adding new error codes here. */ /** Other error */ LIBUSB_ERROR_OTHER = -99, }; /* Total number of error codes in enum libusb_error */ #define LIBUSB_ERROR_COUNT 14 /** \ingroup asyncio * Transfer status codes */ enum libusb_transfer_status { /** Transfer completed without error. Note that this does not indicate * that the entire amount of requested data was transferred. */ LIBUSB_TRANSFER_COMPLETED, /** Transfer failed */ LIBUSB_TRANSFER_ERROR, /** Transfer timed out */ LIBUSB_TRANSFER_TIMED_OUT, /** Transfer was cancelled */ LIBUSB_TRANSFER_CANCELLED, /** For bulk/interrupt endpoints: halt condition detected (endpoint * stalled). For control endpoints: control request not supported. */ LIBUSB_TRANSFER_STALL, /** Device was disconnected */ LIBUSB_TRANSFER_NO_DEVICE, /** Device sent more data than requested */ LIBUSB_TRANSFER_OVERFLOW, /* NB! Remember to update libusb_error_name() when adding new status codes here. */ }; /** \ingroup asyncio * libusb_transfer.flags values */ enum libusb_transfer_flags { /** Report short frames as errors */ LIBUSB_TRANSFER_SHORT_NOT_OK = 1<<0, /** Automatically free() transfer buffer during libusb_free_transfer() */ LIBUSB_TRANSFER_FREE_BUFFER = 1<<1, /** Automatically call libusb_free_transfer() after callback returns. * If this flag is set, it is illegal to call libusb_free_transfer() * from your transfer callback, as this will result in a double-free * when this flag is acted upon. */ LIBUSB_TRANSFER_FREE_TRANSFER = 1<<2, /** Terminate transfers that are a multiple of the endpoint's * wMaxPacketSize with an extra zero length packet. This is useful * when a device protocol mandates that each logical request is * terminated by an incomplete packet (i.e. the logical requests are * not separated by other means). * * This flag only affects host-to-device transfers to bulk and interrupt * endpoints. In other situations, it is ignored. * * This flag only affects transfers with a length that is a multiple of * the endpoint's wMaxPacketSize. On transfers of other lengths, this * flag has no effect. Therefore, if you are working with a device that * needs a ZLP whenever the end of the logical request falls on a packet * boundary, then it is sensible to set this flag on every * transfer (you do not have to worry about only setting it on transfers * that end on the boundary). * * This flag is currently only supported on Linux. * On other systems, libusb_submit_transfer() will return * LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this flag is set. * * Available since libusb-1.0.9. */ LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1 << 3, }; /** \ingroup asyncio * Isochronous packet descriptor. */ struct libusb_iso_packet_descriptor { /** Length of data to request in this packet */ unsigned int length; /** Amount of data that was actually transferred */ unsigned int actual_length; /** Status code for this packet */ enum libusb_transfer_status status; }; struct libusb_transfer; /** \ingroup asyncio * Asynchronous transfer callback function type. When submitting asynchronous * transfers, you pass a pointer to a callback function of this type via the * \ref libusb_transfer::callback "callback" member of the libusb_transfer * structure. libusb will call this function later, when the transfer has * completed or failed. See \ref asyncio for more information. * \param transfer The libusb_transfer struct the callback function is being * notified about. */ typedef void (LIBUSB_CALL *libusb_transfer_cb_fn)(struct libusb_transfer *transfer); /** \ingroup asyncio * The generic USB transfer structure. The user populates this structure and * then submits it in order to request a transfer. After the transfer has * completed, the library populates the transfer with the results and passes * it back to the user. */ struct libusb_transfer { /** Handle of the device that this transfer will be submitted to */ libusb_device_handle *dev_handle; /** A bitwise OR combination of \ref libusb_transfer_flags. */ uint8_t flags; /** Address of the endpoint where this transfer will be sent. */ unsigned char endpoint; /** Type of the endpoint from \ref libusb_transfer_type */ unsigned char type; /** Timeout for this transfer in millseconds. A value of 0 indicates no * timeout. */ unsigned int timeout; /** The status of the transfer. Read-only, and only for use within * transfer callback function. * * If this is an isochronous transfer, this field may read COMPLETED even * if there were errors in the frames. Use the * \ref libusb_iso_packet_descriptor::status "status" field in each packet * to determine if errors occurred. */ enum libusb_transfer_status status; /** Length of the data buffer */ int length; /** Actual length of data that was transferred. Read-only, and only for * use within transfer callback function. Not valid for isochronous * endpoint transfers. */ int actual_length; /** Callback function. This will be invoked when the transfer completes, * fails, or is cancelled. */ libusb_transfer_cb_fn callback; /** User context data to pass to the callback function. */ void *user_data; /** Data buffer */ unsigned char *buffer; /** Number of isochronous packets. Only used for I/O with isochronous * endpoints. */ int num_iso_packets; /** Isochronous packet descriptors, for isochronous transfers only. */ struct libusb_iso_packet_descriptor iso_packet_desc #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) [] /* valid C99 code */ #else [0] /* non-standard, but usually working code */ #endif ; }; /** \ingroup misc * Capabilities supported by an instance of libusb on the current running * platform. Test if the loaded library supports a given capability by calling * \ref libusb_has_capability(). */ enum libusb_capability { /** The libusb_has_capability() API is available. */ LIBUSB_CAP_HAS_CAPABILITY = 0x0000, /** Hotplug support is available on this platform. */ LIBUSB_CAP_HAS_HOTPLUG = 0x0001, /** The library can access HID devices without requiring user intervention. * Note that before being able to actually access an HID device, you may * still have to call additional libusb functions such as * \ref libusb_detach_kernel_driver(). */ LIBUSB_CAP_HAS_HID_ACCESS = 0x0100, /** The library supports detaching of the default USB driver, using * \ref libusb_detach_kernel_driver(), if one is set by the OS kernel */ LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER = 0x0101 }; /** \ingroup lib * Log message levels. * - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default) * - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr * - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr * - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stdout, warning * and error messages are printed to stderr * - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stdout, * warnings and errors to stderr */ enum libusb_log_level { LIBUSB_LOG_LEVEL_NONE = 0, LIBUSB_LOG_LEVEL_ERROR, LIBUSB_LOG_LEVEL_WARNING, LIBUSB_LOG_LEVEL_INFO, LIBUSB_LOG_LEVEL_DEBUG, }; int LIBUSB_CALL libusb_init(libusb_context **ctx); void LIBUSB_CALL libusb_exit(libusb_context *ctx); void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level); const struct libusb_version * LIBUSB_CALL libusb_get_version(void); int LIBUSB_CALL libusb_has_capability(uint32_t capability); const char * LIBUSB_CALL libusb_error_name(int errcode); int LIBUSB_CALL libusb_setlocale(const char *locale); const char * LIBUSB_CALL libusb_strerror(enum libusb_error errcode); ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx, libusb_device ***list); void LIBUSB_CALL libusb_free_device_list(libusb_device **list, int unref_devices); libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev); void LIBUSB_CALL libusb_unref_device(libusb_device *dev); int LIBUSB_CALL libusb_get_configuration(libusb_device_handle *dev, int *config); int LIBUSB_CALL libusb_get_device_descriptor(libusb_device *dev, struct libusb_device_descriptor *desc); int LIBUSB_CALL libusb_get_active_config_descriptor(libusb_device *dev, struct libusb_config_descriptor **config); int LIBUSB_CALL libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index, struct libusb_config_descriptor **config); int LIBUSB_CALL libusb_get_config_descriptor_by_value(libusb_device *dev, uint8_t bConfigurationValue, struct libusb_config_descriptor **config); void LIBUSB_CALL libusb_free_config_descriptor( struct libusb_config_descriptor *config); int LIBUSB_CALL libusb_get_ss_endpoint_companion_descriptor( struct libusb_context *ctx, const struct libusb_endpoint_descriptor *endpoint, struct libusb_ss_endpoint_companion_descriptor **ep_comp); void LIBUSB_CALL libusb_free_ss_endpoint_companion_descriptor( struct libusb_ss_endpoint_companion_descriptor *ep_comp); int LIBUSB_CALL libusb_get_bos_descriptor(libusb_device_handle *handle, struct libusb_bos_descriptor **bos); void LIBUSB_CALL libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos); int LIBUSB_CALL libusb_get_usb_2_0_extension_descriptor( struct libusb_context *ctx, struct libusb_bos_dev_capability_descriptor *dev_cap, struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension); void LIBUSB_CALL libusb_free_usb_2_0_extension_descriptor( struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension); int LIBUSB_CALL libusb_get_ss_usb_device_capability_descriptor( struct libusb_context *ctx, struct libusb_bos_dev_capability_descriptor *dev_cap, struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap); void LIBUSB_CALL libusb_free_ss_usb_device_capability_descriptor( struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap); int LIBUSB_CALL libusb_get_container_id_descriptor(struct libusb_context *ctx, struct libusb_bos_dev_capability_descriptor *dev_cap, struct libusb_container_id_descriptor **container_id); void LIBUSB_CALL libusb_free_container_id_descriptor( struct libusb_container_id_descriptor *container_id); uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev); uint8_t LIBUSB_CALL libusb_get_port_number(libusb_device *dev); int LIBUSB_CALL libusb_get_port_numbers(libusb_device *dev, uint8_t* port_numbers, int port_numbers_len); LIBUSB_DEPRECATED_FOR(libusb_get_port_numbers) int LIBUSB_CALL libusb_get_port_path(libusb_context *ctx, libusb_device *dev, uint8_t* path, uint8_t path_length); libusb_device * LIBUSB_CALL libusb_get_parent(libusb_device *dev); uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device *dev); int LIBUSB_CALL libusb_get_device_speed(libusb_device *dev); int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev, unsigned char endpoint); int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev, unsigned char endpoint); int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle); void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle); libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle); int LIBUSB_CALL libusb_set_configuration(libusb_device_handle *dev, int configuration); int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev, int interface_number); int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev, int interface_number); libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( libusb_context *ctx, uint16_t vendor_id, uint16_t product_id); int LIBUSB_CALL libusb_set_interface_alt_setting(libusb_device_handle *dev, int interface_number, int alternate_setting); int LIBUSB_CALL libusb_clear_halt(libusb_device_handle *dev, unsigned char endpoint); int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev); int LIBUSB_CALL libusb_alloc_streams(libusb_device_handle *dev, uint32_t num_streams, unsigned char *endpoints, int num_endpoints); int LIBUSB_CALL libusb_free_streams(libusb_device_handle *dev, unsigned char *endpoints, int num_endpoints); int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev, int interface_number); int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev, int interface_number); int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev, int interface_number); int LIBUSB_CALL libusb_set_auto_detach_kernel_driver( libusb_device_handle *dev, int enable); /* async I/O */ /** \ingroup asyncio * Get the data section of a control transfer. This convenience function is here * to remind you that the data does not start until 8 bytes into the actual * buffer, as the setup packet comes first. * * Calling this function only makes sense from a transfer callback function, * or situations where you have already allocated a suitably sized buffer at * transfer->buffer. * * \param transfer a transfer * \returns pointer to the first byte of the data section */ static inline unsigned char *libusb_control_transfer_get_data( struct libusb_transfer *transfer) { return transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; } /** \ingroup asyncio * Get the control setup packet of a control transfer. This convenience * function is here to remind you that the control setup occupies the first * 8 bytes of the transfer data buffer. * * Calling this function only makes sense from a transfer callback function, * or situations where you have already allocated a suitably sized buffer at * transfer->buffer. * * \param transfer a transfer * \returns a casted pointer to the start of the transfer data buffer */ static inline struct libusb_control_setup *libusb_control_transfer_get_setup( struct libusb_transfer *transfer) { return (struct libusb_control_setup *)(void *) transfer->buffer; } /** \ingroup asyncio * Helper function to populate the setup packet (first 8 bytes of the data * buffer) for a control transfer. The wIndex, wValue and wLength values should * be given in host-endian byte order. * * \param buffer buffer to output the setup packet into * This pointer must be aligned to at least 2 bytes boundary. * \param bmRequestType see the * \ref libusb_control_setup::bmRequestType "bmRequestType" field of * \ref libusb_control_setup * \param bRequest see the * \ref libusb_control_setup::bRequest "bRequest" field of * \ref libusb_control_setup * \param wValue see the * \ref libusb_control_setup::wValue "wValue" field of * \ref libusb_control_setup * \param wIndex see the * \ref libusb_control_setup::wIndex "wIndex" field of * \ref libusb_control_setup * \param wLength see the * \ref libusb_control_setup::wLength "wLength" field of * \ref libusb_control_setup */ static inline void libusb_fill_control_setup(unsigned char *buffer, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength) { struct libusb_control_setup *setup = (struct libusb_control_setup *)(void *) buffer; setup->bmRequestType = bmRequestType; setup->bRequest = bRequest; setup->wValue = libusb_cpu_to_le16(wValue); setup->wIndex = libusb_cpu_to_le16(wIndex); setup->wLength = libusb_cpu_to_le16(wLength); } struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(int iso_packets); int LIBUSB_CALL libusb_submit_transfer(struct libusb_transfer *transfer); int LIBUSB_CALL libusb_cancel_transfer(struct libusb_transfer *transfer); void LIBUSB_CALL libusb_free_transfer(struct libusb_transfer *transfer); void LIBUSB_CALL libusb_transfer_set_stream_id( struct libusb_transfer *transfer, uint32_t stream_id); uint32_t LIBUSB_CALL libusb_transfer_get_stream_id( struct libusb_transfer *transfer); /** \ingroup asyncio * Helper function to populate the required \ref libusb_transfer fields * for a control transfer. * * If you pass a transfer buffer to this function, the first 8 bytes will * be interpreted as a control setup packet, and the wLength field will be * used to automatically populate the \ref libusb_transfer::length "length" * field of the transfer. Therefore the recommended approach is: * -# Allocate a suitably sized data buffer (including space for control setup) * -# Call libusb_fill_control_setup() * -# If this is a host-to-device transfer with a data stage, put the data * in place after the setup packet * -# Call this function * -# Call libusb_submit_transfer() * * It is also legal to pass a NULL buffer to this function, in which case this * function will not attempt to populate the length field. Remember that you * must then populate the buffer and length fields later. * * \param transfer the transfer to populate * \param dev_handle handle of the device that will handle the transfer * \param buffer data buffer. If provided, this function will interpret the * first 8 bytes as a setup packet and infer the transfer length from that. * This pointer must be aligned to at least 2 bytes boundary. * \param callback callback function to be invoked on transfer completion * \param user_data user data to pass to callback function * \param timeout timeout for the transfer in milliseconds */ static inline void libusb_fill_control_transfer( struct libusb_transfer *transfer, libusb_device_handle *dev_handle, unsigned char *buffer, libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) { struct libusb_control_setup *setup = (struct libusb_control_setup *)(void *) buffer; transfer->dev_handle = dev_handle; transfer->endpoint = 0; transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL; transfer->timeout = timeout; transfer->buffer = buffer; if (setup) transfer->length = (int) (LIBUSB_CONTROL_SETUP_SIZE + libusb_le16_to_cpu(setup->wLength)); transfer->user_data = user_data; transfer->callback = callback; } /** \ingroup asyncio * Helper function to populate the required \ref libusb_transfer fields * for a bulk transfer. * * \param transfer the transfer to populate * \param dev_handle handle of the device that will handle the transfer * \param endpoint address of the endpoint where this transfer will be sent * \param buffer data buffer * \param length length of data buffer * \param callback callback function to be invoked on transfer completion * \param user_data user data to pass to callback function * \param timeout timeout for the transfer in milliseconds */ static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer, libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *buffer, int length, libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) { transfer->dev_handle = dev_handle; transfer->endpoint = endpoint; transfer->type = LIBUSB_TRANSFER_TYPE_BULK; transfer->timeout = timeout; transfer->buffer = buffer; transfer->length = length; transfer->user_data = user_data; transfer->callback = callback; } /** \ingroup asyncio * Helper function to populate the required \ref libusb_transfer fields * for a bulk transfer using bulk streams. * * Since version 1.0.19, \ref LIBUSB_API_VERSION >= 0x01000103 * * \param transfer the transfer to populate * \param dev_handle handle of the device that will handle the transfer * \param endpoint address of the endpoint where this transfer will be sent * \param stream_id bulk stream id for this transfer * \param buffer data buffer * \param length length of data buffer * \param callback callback function to be invoked on transfer completion * \param user_data user data to pass to callback function * \param timeout timeout for the transfer in milliseconds */ static inline void libusb_fill_bulk_stream_transfer( struct libusb_transfer *transfer, libusb_device_handle *dev_handle, unsigned char endpoint, uint32_t stream_id, unsigned char *buffer, int length, libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) { libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length, callback, user_data, timeout); transfer->type = LIBUSB_TRANSFER_TYPE_BULK_STREAM; libusb_transfer_set_stream_id(transfer, stream_id); } /** \ingroup asyncio * Helper function to populate the required \ref libusb_transfer fields * for an interrupt transfer. * * \param transfer the transfer to populate * \param dev_handle handle of the device that will handle the transfer * \param endpoint address of the endpoint where this transfer will be sent * \param buffer data buffer * \param length length of data buffer * \param callback callback function to be invoked on transfer completion * \param user_data user data to pass to callback function * \param timeout timeout for the transfer in milliseconds */ static inline void libusb_fill_interrupt_transfer( struct libusb_transfer *transfer, libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *buffer, int length, libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) { transfer->dev_handle = dev_handle; transfer->endpoint = endpoint; transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT; transfer->timeout = timeout; transfer->buffer = buffer; transfer->length = length; transfer->user_data = user_data; transfer->callback = callback; } /** \ingroup asyncio * Helper function to populate the required \ref libusb_transfer fields * for an isochronous transfer. * * \param transfer the transfer to populate * \param dev_handle handle of the device that will handle the transfer * \param endpoint address of the endpoint where this transfer will be sent * \param buffer data buffer * \param length length of data buffer * \param num_iso_packets the number of isochronous packets * \param callback callback function to be invoked on transfer completion * \param user_data user data to pass to callback function * \param timeout timeout for the transfer in milliseconds */ static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer, libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *buffer, int length, int num_iso_packets, libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) { transfer->dev_handle = dev_handle; transfer->endpoint = endpoint; transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS; transfer->timeout = timeout; transfer->buffer = buffer; transfer->length = length; transfer->num_iso_packets = num_iso_packets; transfer->user_data = user_data; transfer->callback = callback; } /** \ingroup asyncio * Convenience function to set the length of all packets in an isochronous * transfer, based on the num_iso_packets field in the transfer structure. * * \param transfer a transfer * \param length the length to set in each isochronous packet descriptor * \see libusb_get_max_packet_size() */ static inline void libusb_set_iso_packet_lengths( struct libusb_transfer *transfer, unsigned int length) { int i; for (i = 0; i < transfer->num_iso_packets; i++) transfer->iso_packet_desc[i].length = length; } /** \ingroup asyncio * Convenience function to locate the position of an isochronous packet * within the buffer of an isochronous transfer. * * This is a thorough function which loops through all preceding packets, * accumulating their lengths to find the position of the specified packet. * Typically you will assign equal lengths to each packet in the transfer, * and hence the above method is sub-optimal. You may wish to use * libusb_get_iso_packet_buffer_simple() instead. * * \param transfer a transfer * \param packet the packet to return the address of * \returns the base address of the packet buffer inside the transfer buffer, * or NULL if the packet does not exist. * \see libusb_get_iso_packet_buffer_simple() */ static inline unsigned char *libusb_get_iso_packet_buffer( struct libusb_transfer *transfer, unsigned int packet) { int i; size_t offset = 0; int _packet; /* oops..slight bug in the API. packet is an unsigned int, but we use * signed integers almost everywhere else. range-check and convert to * signed to avoid compiler warnings. FIXME for libusb-2. */ if (packet > INT_MAX) return NULL; _packet = (int) packet; if (_packet >= transfer->num_iso_packets) return NULL; for (i = 0; i < _packet; i++) offset += transfer->iso_packet_desc[i].length; return transfer->buffer + offset; } /** \ingroup asyncio * Convenience function to locate the position of an isochronous packet * within the buffer of an isochronous transfer, for transfers where each * packet is of identical size. * * This function relies on the assumption that every packet within the transfer * is of identical size to the first packet. Calculating the location of * the packet buffer is then just a simple calculation: * buffer + (packet_size * packet) * * Do not use this function on transfers other than those that have identical * packet lengths for each packet. * * \param transfer a transfer * \param packet the packet to return the address of * \returns the base address of the packet buffer inside the transfer buffer, * or NULL if the packet does not exist. * \see libusb_get_iso_packet_buffer() */ static inline unsigned char *libusb_get_iso_packet_buffer_simple( struct libusb_transfer *transfer, unsigned int packet) { int _packet; /* oops..slight bug in the API. packet is an unsigned int, but we use * signed integers almost everywhere else. range-check and convert to * signed to avoid compiler warnings. FIXME for libusb-2. */ if (packet > INT_MAX) return NULL; _packet = (int) packet; if (_packet >= transfer->num_iso_packets) return NULL; return transfer->buffer + ((int) transfer->iso_packet_desc[0].length * _packet); } /* sync I/O */ int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout); int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *data, int length, int *actual_length, unsigned int timeout); int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *data, int length, int *actual_length, unsigned int timeout); /** \ingroup desc * Retrieve a descriptor from the default control pipe. * This is a convenience function which formulates the appropriate control * message to retrieve the descriptor. * * \param dev a device handle * \param desc_type the descriptor type, see \ref libusb_descriptor_type * \param desc_index the index of the descriptor to retrieve * \param data output buffer for descriptor * \param length size of data buffer * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure */ static inline int libusb_get_descriptor(libusb_device_handle *dev, uint8_t desc_type, uint8_t desc_index, unsigned char *data, int length) { return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t) ((desc_type << 8) | desc_index), 0, data, (uint16_t) length, 1000); } /** \ingroup desc * Retrieve a descriptor from a device. * This is a convenience function which formulates the appropriate control * message to retrieve the descriptor. The string returned is Unicode, as * detailed in the USB specifications. * * \param dev a device handle * \param desc_index the index of the descriptor to retrieve * \param langid the language ID for the string descriptor * \param data output buffer for descriptor * \param length size of data buffer * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure * \see libusb_get_string_descriptor_ascii() */ static inline int libusb_get_string_descriptor(libusb_device_handle *dev, uint8_t desc_index, uint16_t langid, unsigned char *data, int length) { return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t)((LIBUSB_DT_STRING << 8) | desc_index), langid, data, (uint16_t) length, 1000); } int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev, uint8_t desc_index, unsigned char *data, int length); /* polling and timeouts */ int LIBUSB_CALL libusb_try_lock_events(libusb_context *ctx); void LIBUSB_CALL libusb_lock_events(libusb_context *ctx); void LIBUSB_CALL libusb_unlock_events(libusb_context *ctx); int LIBUSB_CALL libusb_event_handling_ok(libusb_context *ctx); int LIBUSB_CALL libusb_event_handler_active(libusb_context *ctx); void LIBUSB_CALL libusb_lock_event_waiters(libusb_context *ctx); void LIBUSB_CALL libusb_unlock_event_waiters(libusb_context *ctx); int LIBUSB_CALL libusb_wait_for_event(libusb_context *ctx, struct timeval *tv); int LIBUSB_CALL libusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv); int LIBUSB_CALL libusb_handle_events_timeout_completed(libusb_context *ctx, struct timeval *tv, int *completed); int LIBUSB_CALL libusb_handle_events(libusb_context *ctx); int LIBUSB_CALL libusb_handle_events_completed(libusb_context *ctx, int *completed); int LIBUSB_CALL libusb_handle_events_locked(libusb_context *ctx, struct timeval *tv); int LIBUSB_CALL libusb_pollfds_handle_timeouts(libusb_context *ctx); int LIBUSB_CALL libusb_get_next_timeout(libusb_context *ctx, struct timeval *tv); /** \ingroup poll * File descriptor for polling */ struct libusb_pollfd { /** Numeric file descriptor */ int fd; /** Event flags to poll for from . POLLIN indicates that you * should monitor this file descriptor for becoming ready to read from, * and POLLOUT indicates that you should monitor this file descriptor for * nonblocking write readiness. */ short events; }; /** \ingroup poll * Callback function, invoked when a new file descriptor should be added * to the set of file descriptors monitored for events. * \param fd the new file descriptor * \param events events to monitor for, see \ref libusb_pollfd for a * description * \param user_data User data pointer specified in * libusb_set_pollfd_notifiers() call * \see libusb_set_pollfd_notifiers() */ typedef void (LIBUSB_CALL *libusb_pollfd_added_cb)(int fd, short events, void *user_data); /** \ingroup poll * Callback function, invoked when a file descriptor should be removed from * the set of file descriptors being monitored for events. After returning * from this callback, do not use that file descriptor again. * \param fd the file descriptor to stop monitoring * \param user_data User data pointer specified in * libusb_set_pollfd_notifiers() call * \see libusb_set_pollfd_notifiers() */ typedef void (LIBUSB_CALL *libusb_pollfd_removed_cb)(int fd, void *user_data); const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds( libusb_context *ctx); void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx, libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, void *user_data); /** \ingroup hotplug * Callback handle. * * Callbacks handles are generated by libusb_hotplug_register_callback() * and can be used to deregister callbacks. Callback handles are unique * per libusb_context and it is safe to call libusb_hotplug_deregister_callback() * on an already deregisted callback. * * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * * For more information, see \ref hotplug. */ typedef int libusb_hotplug_callback_handle; /** \ingroup hotplug * * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * * Flags for hotplug events */ typedef enum { /** Arm the callback and fire it for all matching currently attached devices. */ LIBUSB_HOTPLUG_ENUMERATE = 1, } libusb_hotplug_flag; /** \ingroup hotplug * * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * * Hotplug events */ typedef enum { /** A device has been plugged in and is ready to use */ LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = 0x01, /** A device has left and is no longer available. * It is the user's responsibility to call libusb_close on any handle associated with a disconnected device. * It is safe to call libusb_get_device_descriptor on a device that has left */ LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT = 0x02, } libusb_hotplug_event; /** \ingroup hotplug * Wildcard matching for hotplug events */ #define LIBUSB_HOTPLUG_MATCH_ANY -1 /** \ingroup hotplug * Hotplug callback function type. When requesting hotplug event notifications, * you pass a pointer to a callback function of this type. * * This callback may be called by an internal event thread and as such it is * recommended the callback do minimal processing before returning. * * libusb will call this function later, when a matching event had happened on * a matching device. See \ref hotplug for more information. * * It is safe to call either libusb_hotplug_register_callback() or * libusb_hotplug_deregister_callback() from within a callback function. * * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * * \param ctx context of this notification * \param device libusb_device this event occurred on * \param event event that occurred * \param user_data user data provided when this callback was registered * \returns bool whether this callback is finished processing events. * returning 1 will cause this callback to be deregistered */ typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx, libusb_device *device, libusb_hotplug_event event, void *user_data); /** \ingroup hotplug * Register a hotplug callback function * * Register a callback with the libusb_context. The callback will fire * when a matching event occurs on a matching device. The callback is * armed until either it is deregistered with libusb_hotplug_deregister_callback() * or the supplied callback returns 1 to indicate it is finished processing events. * * If the \ref LIBUSB_HOTPLUG_ENUMERATE is passed the callback will be * called with a \ref LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED for all devices * already plugged into the machine. Note that libusb modifies its internal * device list from a separate thread, while calling hotplug callbacks from * libusb_handle_events(), so it is possible for a device to already be present * on, or removed from, its internal device list, while the hotplug callbacks * still need to be dispatched. This means that when using \ref * LIBUSB_HOTPLUG_ENUMERATE, your callback may be called twice for the arrival * of the same device, once from libusb_hotplug_register_callback() and once * from libusb_handle_events(); and/or your callback may be called for the * removal of a device for which an arrived call was never made. * * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * * \param[in] ctx context to register this callback with * \param[in] events bitwise or of events that will trigger this callback. See \ref * libusb_hotplug_event * \param[in] flags hotplug callback flags. See \ref libusb_hotplug_flag * \param[in] vendor_id the vendor id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY * \param[in] product_id the product id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY * \param[in] dev_class the device class to match or \ref LIBUSB_HOTPLUG_MATCH_ANY * \param[in] cb_fn the function to be invoked on a matching event/device * \param[in] user_data user data to pass to the callback function * \param[out] handle pointer to store the handle of the allocated callback (can be NULL) * \returns LIBUSB_SUCCESS on success LIBUSB_ERROR code on failure */ int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx, libusb_hotplug_event events, libusb_hotplug_flag flags, int vendor_id, int product_id, int dev_class, libusb_hotplug_callback_fn cb_fn, void *user_data, libusb_hotplug_callback_handle *handle); /** \ingroup hotplug * Deregisters a hotplug callback. * * Deregister a callback from a libusb_context. This function is safe to call from within * a hotplug callback. * * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * * \param[in] ctx context this callback is registered with * \param[in] handle the handle of the callback to deregister */ void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx, libusb_hotplug_callback_handle handle); #ifdef __cplusplus } #endif #endif libmirisdr-4-2.0.0/src/miri_fm.c000066400000000000000000001050671423227345400164060ustar00rootroot00000000000000/* * Copy of rtl-sdr for Mirics devices * Copyright (C) 2012 by Steve Markgraf * Copyright (C) 2012 by Hoernchen * Copyright (C) 2012 by Kyle Keen * Copyright (C) 2013 by Elias Oenal * * 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 2 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 . */ /* * written because people could not do real time * FM demod on Atom hardware with GNU radio * based on rtl_sdr.c and rtl_tcp.c * * lots of locks, but that is okay * (no many-to-many locks) * * todo: * sanity checks * scale squelch to other input parameters * test all the demodulations * pad output on hop * frequency ranges could be stored better * scaled AM demod amplification * auto-hop after time limit * peak detector to tune onto stronger signals * fifo for active hop frequency * clips * noise squelch * merge stereo patch * merge soft agc patch * merge udp patch * testmode to detect overruns * break out convenience functions */ #include #include #include #include #include #if !defined (_WIN32) || defined(__MINGW32__) #include #else #include #include #include #include "getopt/getopt.h" #define usleep(x) Sleep(x/1000) #ifdef _MSC_VER #define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5)) #endif #define _USE_MATH_DEFINES #endif #include #include #include "mirisdr.h" #include "convenience.c" #define DEFAULT_SAMPLE_RATE 24000 #define DEFAULT_ASYNC_BUF_NUMBER 32 #define DEFAULT_BUF_LENGTH (1 * 16384) #define MAXIMUM_OVERSAMPLE 16 #define MAXIMUM_BUF_LENGTH (MAXIMUM_OVERSAMPLE * DEFAULT_BUF_LENGTH) #define AUTO_GAIN -100 #define BUFFER_DUMP 4096 #define FREQUENCIES_LIMIT 1000 static volatile int do_exit = 0; static int lcm_post[17] = {1,1,1,3,1,5,3,7,1,9,5,11,3,13,7,15,1}; static int ACTUAL_BUF_LENGTH; static int *atan_lut = NULL; static int atan_lut_size = 131072; /* 512 KB */ static int atan_lut_coef = 8; struct dongle_state { int exit_flag; pthread_t thread; mirisdr_dev_t *dev; int dev_index; uint32_t freq; uint32_t rate; int gain; uint16_t buf16[MAXIMUM_BUF_LENGTH]; uint32_t buf_len; int ppm_error; int offset_tuning; int direct_sampling; int format; int transfer; int bw; int if_mode; int mute; struct demod_state *demod_target; }; struct demod_state { int exit_flag; pthread_t thread; int16_t lowpassed[MAXIMUM_BUF_LENGTH]; int lp_len; int16_t lp_i_hist[10][6]; int16_t lp_q_hist[10][6]; int16_t result[MAXIMUM_BUF_LENGTH]; int16_t droop_i_hist[9]; int16_t droop_q_hist[9]; int result_len; int rate_in; int rate_out; int rate_out2; int now_r, now_j; int pre_r, pre_j; int prev_index; int downsample; /* min 1, max 256 */ int post_downsample; int output_scale; int squelch_level, conseq_squelch, squelch_hits, terminate_on_squelch; int downsample_passes; int comp_fir_size; int custom_atan; int deemph, deemph_a; int now_lpr; int prev_lpr_index; int dc_block, dc_avg; void (*mode_demod)(struct demod_state*); pthread_rwlock_t rw; pthread_cond_t ready; pthread_mutex_t ready_m; struct output_state *output_target; }; struct output_state { int exit_flag; pthread_t thread; FILE *file; char *filename; int16_t result[MAXIMUM_BUF_LENGTH]; int result_len; int rate; pthread_rwlock_t rw; pthread_cond_t ready; pthread_mutex_t ready_m; }; struct controller_state { int exit_flag; pthread_t thread; uint32_t freqs[FREQUENCIES_LIMIT]; int freq_len; int freq_now; int edge; int wb_mode; pthread_cond_t hop; pthread_mutex_t hop_m; }; // multiple of these, eventually struct dongle_state dongle; struct demod_state demod; struct output_state output; struct controller_state controller; void usage(void) { fprintf(stderr, "miri_fm, a simple narrow band FM demodulator for Mirics based receivers\n\n" "Use:\tmiri_fm -f freq [-options] [filename]\n" "\t-f frequency_to_tune_to [Hz]\n" "\t use multiple -f for scanning (requires squelch)\n" "\t ranges supported, -f 118M:137M:25k\n" "\t[-M modulation (default: fm)]\n" "\t fm, wbfm, raw, am, usb, lsb\n" "\t wbfm == -M fm -s 170k -o 4 -A fast -r 32k -l 0 -E deemp\n" "\t raw mode outputs 2x16 bit IQ pairs\n" "\t[-s sample_rate (default: 24k)]\n" "\t[-d device_index (default: 0)]\n" "\t[-T device_type device variant (default: 0)]\n" "\t 0: Default\n" "\t 1: SDRPlay\n" "\t[-g tuner_gain (default: automatic)]\n" "\t[-m sample format (default: auto]\n" "\t 504: S8 (fastest)\n" "\t 384: S10 +2bits \n" "\t 336: S12\n" "\t 252: S14\n" #if !defined (_WIN32) || defined(__MINGW32__) "\t[-e USB transfer mode (default: 1)]\n" #else "\t[-e USB transfer mode (default: 2)]\n" #endif "\t 1: Isochronous (maximum 196.608 Mbit/s) \n" "\t 2: Bulk (maximum 333Mbit/s, depends on controller type)\n" "\t[-i IF mode (default: ZERO]\n" "\t 0: ZERO\n" "\t 450000: 450 kHz\n" "\t 1620000: 1620kHz\n" "\t 2048000: 2048kHz\n" "\t[-w BW mode (default: 8MHz]\n" "\t 200000: 200kHz\n" "\t 300000: 300kHz\n" "\t 600000: 600kHz\n" "\t 1536000: 1536kHz\n" "\t 5000000: 5MHz\n" "\t 6000000: 6MHz\n" "\t 7000000: 7MHz\n" "\t 8000000: 8MHz\n" "\t[-l squelch_level (default: 0/off)]\n" //"\t for fm squelch is inverted\n" "\t[-o oversampling (default: 1, 4 recommended)]\n" "\t[-p ppm_error (default: 0)]\n" "\t[-E enable_option (default: none)]\n" "\t use multiple -E to enable multiple options\n" "\t edge: enable lower edge tuning\n" "\t dc: enable dc blocking filter\n" "\t deemp: enable de-emphasis filter\n" "\t direct: enable direct sampling\n" "\t offset: enable offset tuning\n" "\tfilename ('-' means stdout)\n" "\t omitting the filename also uses stdout\n\n" "Experimental options:\n" "\t[-r resample_rate (default: none / same as -s)]\n" "\t[-t squelch_delay (default: 10)]\n" "\t +values will mute/scan, -values will exit\n" "\t[-F fir_size (default: off)]\n" "\t enables low-leakage downsample filter\n" "\t size can be 0 or 9. 0 has bad roll off\n" "\t[-A std/fast/lut choose atan math (default: std)]\n" //"\t[-C clip_path (default: off)\n" //"\t (create time stamped raw clips, requires squelch)\n" //"\t (path must have '\%s' and will expand to date_time_freq)\n" //"\t[-H hop_fifo (default: off)\n" //"\t (fifo will contain the active frequency)\n" "\n" "Produces signed 16 bit ints, use Sox or aplay to hear them.\n" "\tmiri_fm ... | play -t raw -r 24k -es -b 16 -c 1 -V1 -\n" "\t | aplay -r 24k -f S16_LE -t raw -c 1\n" "\t -M wbfm | play -r 32k ... \n" "\t -s 22050 | multimon -t raw /dev/stdin\n\n"); exit(1); } #if defined (_WIN32) && !defined(__MINGW32__) BOOL WINAPI sighandler(int signum) { if (CTRL_C_EVENT == signum) { fprintf(stderr, "Signal caught, exiting!\n"); do_exit = 1; mirisdr_cancel_async(dongle.dev); return TRUE; } return FALSE; } #else static void sighandler(int signum) { (void) signum; fprintf(stderr, "Signal caught, exiting!\n"); do_exit = 1; mirisdr_cancel_async(dongle.dev); } #endif /* more cond dumbness */ #define safe_cond_signal(n, m) pthread_mutex_lock(m); pthread_cond_signal(n); pthread_mutex_unlock(m) #define safe_cond_wait(n, m) pthread_mutex_lock(m); pthread_cond_wait(n, m); pthread_mutex_unlock(m) /* {length, coef, coef, coef} and scaled by 2^15 for now, only length 9, optimal way to get +85% bandwidth */ #define CIC_TABLE_MAX 10 int cic_9_tables[][10] = { {0,}, {9, -156, -97, 2798, -15489, 61019, -15489, 2798, -97, -156}, {9, -128, -568, 5593, -24125, 74126, -24125, 5593, -568, -128}, {9, -129, -639, 6187, -26281, 77511, -26281, 6187, -639, -129}, {9, -122, -612, 6082, -26353, 77818, -26353, 6082, -612, -122}, {9, -120, -602, 6015, -26269, 77757, -26269, 6015, -602, -120}, {9, -120, -582, 5951, -26128, 77542, -26128, 5951, -582, -120}, {9, -119, -580, 5931, -26094, 77505, -26094, 5931, -580, -119}, {9, -119, -578, 5921, -26077, 77484, -26077, 5921, -578, -119}, {9, -119, -577, 5917, -26067, 77473, -26067, 5917, -577, -119}, {9, -199, -362, 5303, -25505, 77489, -25505, 5303, -362, -199}, }; void rotate_90_s8(char *buf, uint32_t len) /* 90 rotation is 1+0j, 0+1j, -1+0j, 0-1j or [0, 1, -3, 2, -4, -5, 7, -6] */ { uint32_t i; char tmp; for (i=0; ilp_len) { d->now_r += d->lowpassed[i]; d->now_j += d->lowpassed[i+1]; i += 2; d->prev_index++; if (d->prev_index < d->downsample) { continue; } d->lowpassed[i2] = d->now_r; // * d->output_scale; d->lowpassed[i2+1] = d->now_j; // * d->output_scale; d->prev_index = 0; d->now_r = 0; d->now_j = 0; i2 += 2; } d->lp_len = i2; } int low_pass_simple(int16_t *signal2, int len, int step) // no wrap around, length must be multiple of step { int i, i2, sum; for(i=0; i < len; i+=step) { sum = 0; for(i2=0; i2rate_out; int slow = s->rate_out2; while (i < s->result_len) { s->now_lpr += s->result[i]; i++; s->prev_lpr_index += slow; if (s->prev_lpr_index < fast) { continue; } s->result[i2] = (int16_t)(s->now_lpr / (fast/slow)); s->prev_lpr_index -= fast; s->now_lpr = 0; i2 += 1; } s->result_len = i2; } void fifth_order(int16_t *data, int length, int16_t *hist) /* for half of interleaved data */ { int i; int16_t a, b, c, d, e, f; a = hist[1]; b = hist[2]; c = hist[3]; d = hist[4]; e = hist[5]; f = data[0]; /* a downsample should improve resolution, so don't fully shift */ data[0] = (a + (b+e)*5 + (c+d)*10 + f) >> 4; for (i=4; i> 4; } /* archive */ hist[0] = a; hist[1] = b; hist[2] = c; hist[3] = d; hist[4] = e; hist[5] = f; } void generic_fir(int16_t *data, int length, int *fir, int16_t *hist) /* Okay, not at all generic. Assumes length 9, fix that eventually. */ { int d, temp, sum; for (d=0; d> 15 ; hist[0] = hist[1]; hist[1] = hist[2]; hist[2] = hist[3]; hist[3] = hist[4]; hist[4] = hist[5]; hist[5] = hist[6]; hist[6] = hist[7]; hist[7] = hist[8]; hist[8] = temp; } } /* define our own complex math ops because ARMv5 has no hardware float */ void multiply(int ar, int aj, int br, int bj, int *cr, int *cj) { *cr = ar*br - aj*bj; *cj = aj*br + ar*bj; } int polar_discriminant(int ar, int aj, int br, int bj) { int cr, cj; double angle; multiply(ar, aj, br, -bj, &cr, &cj); angle = atan2((double)cj, (double)cr); return (int)(angle / 3.14159 * (1<<14)); } int fast_atan2(int y, int x) /* pre scaled for int16 */ { int yabs, angle; int pi4=(1<<12), pi34=3*(1<<12); // note pi = 1<<14 if (x==0 && y==0) { return 0; } yabs = y; if (yabs < 0) { yabs = -yabs; } if (x >= 0) { angle = pi4 - pi4 * (x-yabs) / (x+yabs); } else { angle = pi34 - pi4 * (x+yabs) / (yabs-x); } if (y < 0) { return -angle; } return angle; } int polar_disc_fast(int ar, int aj, int br, int bj) { int cr, cj; multiply(ar, aj, br, -bj, &cr, &cj); return fast_atan2(cj, cr); } int atan_lut_init(void) { int i = 0; atan_lut = malloc(atan_lut_size * sizeof(int)); for (i = 0; i < atan_lut_size; i++) { atan_lut[i] = (int) (atan((double) i / (1< 0) {return 1 << 13;} if (cr == 0 && cj < 0) {return -(1 << 13);} if (cj == 0 && cr > 0) {return 0;} if (cj == 0 && cr < 0) {return 1 << 14;} } /* real range -32768 - 32768 use 64x range -> absolute maximum: 2097152 */ x = (cj << atan_lut_coef) / cr; x_abs = abs(x); if (x_abs >= atan_lut_size) { /* we can use linear range, but it is not necessary */ return (cj > 0) ? 1<<13 : -1<<13; } if (x > 0) { return (cj > 0) ? atan_lut[x] : atan_lut[x] - (1<<14); } else { return (cj > 0) ? (1<<14) - atan_lut[-x] : -atan_lut[-x]; } return 0; } void fm_demod(struct demod_state *fm) { int i, pcm; int16_t *lp = fm->lowpassed; pcm = polar_discriminant(lp[0], lp[1], fm->pre_r, fm->pre_j); fm->result[0] = (int16_t)pcm; for (i = 2; i < (fm->lp_len-1); i += 2) { switch (fm->custom_atan) { case 0: pcm = polar_discriminant(lp[i], lp[i+1], lp[i-2], lp[i-1]); break; case 1: pcm = polar_disc_fast(lp[i], lp[i+1], lp[i-2], lp[i-1]); break; case 2: pcm = polar_disc_lut(lp[i], lp[i+1], lp[i-2], lp[i-1]); break; } fm->result[i/2] = (int16_t)pcm; } fm->pre_r = lp[fm->lp_len - 2]; fm->pre_j = lp[fm->lp_len - 1]; fm->result_len = fm->lp_len/2; } void am_demod(struct demod_state *fm) // todo, fix this extreme laziness { int i, pcm; int16_t *lp = fm->lowpassed; int16_t *r = fm->result; for (i = 0; i < fm->lp_len; i += 2) { // hypot uses floats but won't overflow //r[i/2] = (int16_t)hypot(lp[i], lp[i+1]); pcm = lp[i] * lp[i]; pcm += lp[i+1] * lp[i+1]; r[i/2] = (int16_t)sqrt(pcm) * fm->output_scale; } fm->result_len = fm->lp_len/2; // lowpass? (3khz) highpass? (dc) } void usb_demod(struct demod_state *fm) { int i, pcm; int16_t *lp = fm->lowpassed; int16_t *r = fm->result; for (i = 0; i < fm->lp_len; i += 2) { pcm = lp[i] + lp[i+1]; r[i/2] = (int16_t)pcm * fm->output_scale; } fm->result_len = fm->lp_len/2; } void lsb_demod(struct demod_state *fm) { int i, pcm; int16_t *lp = fm->lowpassed; int16_t *r = fm->result; for (i = 0; i < fm->lp_len; i += 2) { pcm = lp[i] - lp[i+1]; r[i/2] = (int16_t)pcm * fm->output_scale; } fm->result_len = fm->lp_len/2; } void raw_demod(struct demod_state *fm) { int i; for (i = 0; i < fm->lp_len; i++) { fm->result[i] = (int16_t)fm->lowpassed[i]; } fm->result_len = fm->lp_len; } void deemph_filter(struct demod_state *fm) { static int avg; // cheating... int i, d; // de-emph IIR // avg = avg * (1 - alpha) + sample * alpha; for (i = 0; i < fm->result_len; i++) { d = fm->result[i] - avg; if (d > 0) { avg += (d + fm->deemph_a/2) / fm->deemph_a; } else { avg += (d - fm->deemph_a/2) / fm->deemph_a; } fm->result[i] = (int16_t)avg; } } void dc_block_filter(struct demod_state *fm) { int i, avg; int64_t sum = 0; for (i=0; i < fm->result_len; i++) { sum += fm->result[i]; } avg = sum / fm->result_len; avg = (avg + fm->dc_avg * 9) / 10; for (i=0; i < fm->result_len; i++) { fm->result[i] -= avg; } fm->dc_avg = avg; } int mad(int16_t *samples, int len, int step) /* mean average deviation */ { int i=0, sum=0, ave=0; if (len == 0) {return 0;} for (i=0; i len2) { tick -= len2; i++; } if (i >= len1) { i = len1 - 1; tick = len2; } } } void arbitrary_downsample(int16_t *buf1, int16_t *buf2, int len1, int len2) /* fractional boxcar lowpass, len1 > len2 */ { int i = 1; int j = 0; int tick = 0; double remainder = 0; double frac; // use integers... buf2[0] = 0; while (j < len2) { frac = 1.0; if ((tick + len2) > len1) { frac = (double)(len1 - tick) / (double)len2;} buf2[j] += (int16_t)((double)buf1[i] * frac + remainder); remainder = (double)buf1[i] * (1.0-frac); tick += len2; i++; if (tick > len1) { j++; buf2[j] = 0; tick -= len1; } if (i >= len1) { i = len1 - 1; tick = len1; } } for (j=0; jdownsample_passes; if (ds_p) { for (i=0; i < ds_p; i++) { fifth_order(d->lowpassed, (d->lp_len >> i), d->lp_i_hist[i]); fifth_order(d->lowpassed+1, (d->lp_len >> i) - 1, d->lp_q_hist[i]); } d->lp_len = d->lp_len >> ds_p; /* droop compensation */ if (d->comp_fir_size == 9 && ds_p <= CIC_TABLE_MAX) { generic_fir(d->lowpassed, d->lp_len, cic_9_tables[ds_p], d->droop_i_hist); generic_fir(d->lowpassed+1, d->lp_len-1, cic_9_tables[ds_p], d->droop_q_hist); } } else { low_pass(d); } /* power squelch */ if (d->squelch_level) { sr = rms(d->lowpassed, d->lp_len, 1); if (sr < d->squelch_level) { d->squelch_hits++; for (i=0; ilp_len; i++) { d->lowpassed[i] = 0; } } else { d->squelch_hits = 0;} } d->mode_demod(d); /* lowpassed -> result */ if (d->mode_demod == &raw_demod) { return; } /* todo, fm noise squelch */ // use nicer filter here too? if (d->post_downsample > 1) { d->result_len = low_pass_simple(d->result, d->result_len, d->post_downsample);} if (d->deemph) { deemph_filter(d);} if (d->dc_block) { dc_block_filter(d);} if (d->rate_out2 > 0) { low_pass_real(d); //arbitrary_resample(d->result, d->result, d->result_len, d->result_len * d->rate_out2 / d->rate_out); } } static void mirisdr_callback(unsigned char *buf, uint32_t len, void *ctx) { int i; struct dongle_state *s = ctx; char *buf8 = (char*) buf; if (do_exit) { return;} if (!ctx) { return;} struct demod_state *d = s->demod_target; if (s->mute) { if (dongle.format == 1) { for (i=0; imute; i++) { buf[i] = 0;} } else { for (i=0; imute * 2; i++) { buf[i] = 0;} } s->mute = 0; } if (!s->offset_tuning) { if (dongle.format == 1) { rotate_90_s8((char*) buf, len); } else { rotate_90_s16((short*) buf, len >> 1); } } if (dongle.format == 1) { for (i=0; i<(int)len; i++) { s->buf16[i] = (int16_t)buf8[i]; } } else { memcpy(s->buf16, buf, len); len>>= 1; for (i = 0; i<(int)len; i++) { /* other parts doesn't expect full short range */ s->buf16[i] = (int16_t)s->buf16[i] / 128; } } pthread_rwlock_wrlock(&d->rw); memcpy(d->lowpassed, s->buf16, 2*len); d->lp_len = len; pthread_rwlock_unlock(&d->rw); safe_cond_signal(&d->ready, &d->ready_m); } static void *dongle_thread_fn(void *arg) { struct dongle_state *s = arg; mirisdr_read_async(s->dev, mirisdr_callback, s, DEFAULT_ASYNC_BUF_NUMBER, s->buf_len); return 0; } static void *demod_thread_fn(void *arg) { struct demod_state *d = arg; struct output_state *o = d->output_target; while (!do_exit) { safe_cond_wait(&d->ready, &d->ready_m); pthread_rwlock_wrlock(&d->rw); full_demod(d); pthread_rwlock_unlock(&d->rw); if (d->exit_flag) { do_exit = 1; } if (d->squelch_level && d->squelch_hits > d->conseq_squelch) { d->squelch_hits = d->conseq_squelch + 1; /* hair trigger */ safe_cond_signal(&controller.hop, &controller.hop_m); continue; } pthread_rwlock_wrlock(&o->rw); memcpy(o->result, d->result, 2*d->result_len); o->result_len = d->result_len; pthread_rwlock_unlock(&o->rw); safe_cond_signal(&o->ready, &o->ready_m); } return 0; } static void *output_thread_fn(void *arg) { struct output_state *s = arg; while (!do_exit) { // use timedwait and pad out under runs safe_cond_wait(&s->ready, &s->ready_m); pthread_rwlock_rdlock(&s->rw); fwrite(s->result, 2, s->result_len, s->file); pthread_rwlock_unlock(&s->rw); } return 0; } static void optimal_settings(int freq, int rate) { // giant ball of hacks // seems unable to do a single pass, 2:1 (void) rate; int capture_freq, capture_rate; struct dongle_state *d = &dongle; struct demod_state *dm = &demod; struct controller_state *cs = &controller; dm->downsample = (1300000 / dm->rate_in) + 1; if (dm->downsample_passes) { dm->downsample_passes = (int)log2(dm->downsample) + 1; dm->downsample = 1 << dm->downsample_passes; } capture_freq = freq; capture_rate = dm->downsample * dm->rate_in; if (!d->offset_tuning) { capture_freq = freq + capture_rate/4;} capture_freq += cs->edge * dm->rate_in / 2; dm->output_scale = (1<<15) / (128 * dm->downsample); if (dm->output_scale < 1) { dm->output_scale = 1;} if (dm->mode_demod == &fm_demod) { dm->output_scale = 1;} d->freq = (uint32_t)capture_freq; d->rate = (uint32_t)capture_rate; } static void *controller_thread_fn(void *arg) { // thoughts for multiple dongles // might be no good using a controller thread if retune/rate blocks int i; struct controller_state *s = arg; if (s->wb_mode) { for (i=0; i < s->freq_len; i++) { s->freqs[i] += 16000;} } /* set up primary channel */ optimal_settings(s->freqs[0], demod.rate_in); if (dongle.direct_sampling) { verbose_direct_sampling(dongle.dev, 1);} if (dongle.offset_tuning) { verbose_offset_tuning(dongle.dev);} /* Set the frequency */ verbose_set_frequency(dongle.dev, dongle.freq); fprintf(stderr, "Oversampling input by: %ix.\n", demod.downsample); fprintf(stderr, "Oversampling output by: %ix.\n", demod.post_downsample); fprintf(stderr, "Buffer size: %0.2fms\n", 1000 * 0.5 * (float)ACTUAL_BUF_LENGTH / (float)dongle.rate); /* Set sample format */ switch (dongle.format) { case 1: mirisdr_set_sample_format(dongle.dev, "504_S8"); break; case 2: mirisdr_set_sample_format(dongle.dev, "384_S16"); break; case 3: mirisdr_set_sample_format(dongle.dev, "336_S16"); break; case 4: mirisdr_set_sample_format(dongle.dev, "252_S16"); break; default: mirisdr_set_sample_format(dongle.dev, "AUTO"); break; } /* Set USB transfer type */ switch (dongle.transfer) { case 1: mirisdr_set_transfer(dongle.dev, "ISOC"); break; case 2: mirisdr_set_transfer(dongle.dev, "BULK"); break; } /* Set IF mode */ mirisdr_set_if_freq(dongle.dev, dongle.if_mode); /* Set bandwidth */ mirisdr_set_bandwidth(dongle.dev, dongle.bw); /* Set the sample rate */ verbose_set_sample_rate(dongle.dev, dongle.rate); fprintf(stderr, "Output at %u Hz.\n", demod.rate_in/demod.post_downsample); while (!do_exit) { safe_cond_wait(&s->hop, &s->hop_m); if (s->freq_len <= 1) { continue;} /* hacky hopping */ s->freq_now = (s->freq_now + 1) % s->freq_len; optimal_settings(s->freqs[s->freq_now], demod.rate_in); mirisdr_set_center_freq(dongle.dev, dongle.freq); dongle.mute = BUFFER_DUMP; } return 0; } void frequency_range(struct controller_state *s, char *arg) { char *start, *stop, *step; int i; start = arg; stop = strchr(start, ':') + 1; stop[-1] = '\0'; step = strchr(stop, ':') + 1; step[-1] = '\0'; for(i=(int)atofs(start); i<=(int)atofs(stop); i+=(int)atofs(step)) { s->freqs[s->freq_len] = (uint32_t)i; s->freq_len++; if (s->freq_len >= FREQUENCIES_LIMIT) { break;} } stop[-1] = ':'; step[-1] = ':'; } void dongle_init(struct dongle_state *s) { s->rate = DEFAULT_SAMPLE_RATE; s->gain = AUTO_GAIN; // tenths of a dB s->mute = 0; s->direct_sampling = 0; s->offset_tuning = 0; s->demod_target = &demod; s->format = 0; #if !defined (_WIN32) || defined(__MINGW32__) s->transfer = 1; #else s->transfer = 2; #endif s->bw = 8000000; s->if_mode = 0; } void demod_init(struct demod_state *s) { s->rate_in = DEFAULT_SAMPLE_RATE; s->rate_out = DEFAULT_SAMPLE_RATE; s->squelch_level = 0; s->conseq_squelch = 10; s->terminate_on_squelch = 0; s->squelch_hits = 11; s->downsample_passes = 0; s->comp_fir_size = 0; s->prev_index = 0; s->post_downsample = 1; // once this works, default = 4 s->custom_atan = 0; s->deemph = 0; s->rate_out2 = -1; // flag for disabled s->mode_demod = &fm_demod; s->pre_j = s->pre_r = s->now_r = s->now_j = 0; s->prev_lpr_index = 0; s->deemph_a = 0; s->now_lpr = 0; s->dc_block = 0; s->dc_avg = 0; pthread_rwlock_init(&s->rw, NULL); pthread_cond_init(&s->ready, NULL); pthread_mutex_init(&s->ready_m, NULL); s->output_target = &output; } void demod_cleanup(struct demod_state *s) { pthread_rwlock_destroy(&s->rw); pthread_cond_destroy(&s->ready); pthread_mutex_destroy(&s->ready_m); } void output_init(struct output_state *s) { s->rate = DEFAULT_SAMPLE_RATE; pthread_rwlock_init(&s->rw, NULL); pthread_cond_init(&s->ready, NULL); pthread_mutex_init(&s->ready_m, NULL); } void output_cleanup(struct output_state *s) { pthread_rwlock_destroy(&s->rw); pthread_cond_destroy(&s->ready); pthread_mutex_destroy(&s->ready_m); } void controller_init(struct controller_state *s) { s->freqs[0] = 100000000; s->freq_len = 0; s->edge = 0; s->wb_mode = 0; pthread_cond_init(&s->hop, NULL); pthread_mutex_init(&s->hop_m, NULL); } void controller_cleanup(struct controller_state *s) { pthread_cond_destroy(&s->hop); pthread_mutex_destroy(&s->hop_m); } void sanity_checks(void) { if (controller.freq_len == 0) { fprintf(stderr, "Please specify a frequency.\n"); exit(1); } if (controller.freq_len >= FREQUENCIES_LIMIT) { fprintf(stderr, "Too many channels, maximum %i.\n", FREQUENCIES_LIMIT); exit(1); } if (controller.freq_len > 1 && demod.squelch_level == 0) { fprintf(stderr, "Please specify a squelch level. Required for scanning multiple frequencies.\n"); exit(1); } } int main(int argc, char **argv) { #if !defined (_WIN32) || defined(__MINGW32__) struct sigaction sigact; #endif int r, opt; int dev_given = 0; int custom_ppm = 0; dongle_init(&dongle); demod_init(&demod); output_init(&output); controller_init(&controller); mirisdr_hw_flavour_t hw_flavour = MIRISDR_HW_DEFAULT; int intval; while ((opt = getopt(argc, argv, "b:d:T:e:f:g:i:l:m:o:p:r:s:t:w:E:F:A:M:h")) != -1) { switch (opt) { case 'd': dongle.dev_index = verbose_device_search(optarg); dev_given = 1; break; case 'T': intval = atoi(optarg); if ((intval >=0) && (intval <= 1)) { hw_flavour = (mirisdr_hw_flavour_t) intval; } break; case 'e': if ((strcmp("ISOC", optarg) == 0) || (strcmp("1", optarg) == 0)) { dongle.transfer = 1;} if ((strcmp("BULK", optarg) == 0) || (strcmp("2", optarg) == 0)) { dongle.transfer = 2;} break; case 'f': if (controller.freq_len >= FREQUENCIES_LIMIT) { break;} if (strchr(optarg, ':')) {frequency_range(&controller, optarg);} else { controller.freqs[controller.freq_len] = (uint32_t)atofs(optarg); controller.freq_len++; } break; case 'g': dongle.gain = (int)(atof(optarg) * 10); break; case 'i': dongle.if_mode = atoi(optarg); break; case 'l': demod.squelch_level = (int)atof(optarg); break; case 'm': if (strcmp("504", optarg) == 0) { dongle.format = 1;} if (strcmp("384", optarg) == 0) { dongle.format = 2;} if (strcmp("336", optarg) == 0) { dongle.format = 3;} if (strcmp("252", optarg) == 0) { dongle.format = 4;} break; case 's': demod.rate_in = (uint32_t)atofs(optarg); demod.rate_out = (uint32_t)atofs(optarg); break; case 'r': output.rate = (int)atofs(optarg); demod.rate_out2 = (int)atofs(optarg); break; case 'o': demod.post_downsample = (int)atof(optarg); if (demod.post_downsample < 1 || demod.post_downsample > MAXIMUM_OVERSAMPLE) { fprintf(stderr, "Oversample must be between 1 and %i\n", MAXIMUM_OVERSAMPLE);} break; case 't': demod.conseq_squelch = (int)atof(optarg); if (demod.conseq_squelch < 0) { demod.conseq_squelch = -demod.conseq_squelch; demod.terminate_on_squelch = 1; } break; case 'p': dongle.ppm_error = atoi(optarg); custom_ppm = 1; break; case 'w': dongle.bw = atoi(optarg); break; case 'E': if (strcmp("edge", optarg) == 0) { controller.edge = 1;} if (strcmp("dc", optarg) == 0) { demod.dc_block = 1;} if (strcmp("deemp", optarg) == 0) { demod.deemph = 1;} if (strcmp("direct", optarg) == 0) { dongle.direct_sampling = 1;} if (strcmp("offset", optarg) == 0) { dongle.offset_tuning = 1;} break; case 'F': demod.downsample_passes = 1; /* truthy placeholder */ demod.comp_fir_size = atoi(optarg); break; case 'A': if (strcmp("std", optarg) == 0) { demod.custom_atan = 0;} if (strcmp("fast", optarg) == 0) { demod.custom_atan = 1;} if (strcmp("lut", optarg) == 0) { atan_lut_init(); demod.custom_atan = 2;} break; case 'M': if (strcmp("fm", optarg) == 0) { demod.mode_demod = &fm_demod;} if (strcmp("raw", optarg) == 0) { demod.mode_demod = &raw_demod;} if (strcmp("am", optarg) == 0) { demod.mode_demod = &am_demod;} if (strcmp("usb", optarg) == 0) { demod.mode_demod = &usb_demod;} if (strcmp("lsb", optarg) == 0) { demod.mode_demod = &lsb_demod;} if (strcmp("wbfm", optarg) == 0) { controller.wb_mode = 1; demod.mode_demod = &fm_demod; demod.rate_in = 170000; demod.rate_out = 170000; demod.rate_out2 = 32000; demod.custom_atan = 1; demod.post_downsample = 4; demod.deemph = 1; demod.squelch_level = 0;} break; case 'h': default: usage(); break; } } /* quadruple sample_rate to limit to Δθ to ±π/2 */ demod.rate_in *= demod.post_downsample; if (!output.rate) { output.rate = demod.rate_out;} sanity_checks(); if (controller.freq_len > 1) { demod.terminate_on_squelch = 0;} if (argc <= optind) { output.filename = "-"; } else { output.filename = argv[optind]; } ACTUAL_BUF_LENGTH = lcm_post[demod.post_downsample] * DEFAULT_BUF_LENGTH; if (!dev_given) { dongle.dev_index = verbose_device_search("0"); } if (dongle.dev_index < 0) { exit(1); } r = mirisdr_open(&dongle.dev, (uint32_t)dongle.dev_index); if (r < 0) { fprintf(stderr, "Failed to open Mirics device #%d.\n", dongle.dev_index); exit(1); } mirisdr_set_hw_flavour(dongle.dev, hw_flavour); #if !defined (_WIN32) || defined(__MINGW32__) sigact.sa_handler = sighandler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGPIPE, &sigact, NULL); #else SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); #endif if (demod.deemph) { demod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * 75e-6))))); } /* Set the tuner gain */ if (dongle.gain == AUTO_GAIN) { verbose_auto_gain(dongle.dev); } else { dongle.gain = nearest_gain(dongle.dev, dongle.gain); verbose_gain_set(dongle.dev, dongle.gain); } if (!custom_ppm) { verbose_ppm_eeprom(dongle.dev, &(dongle.ppm_error)); } verbose_ppm_set(dongle.dev, dongle.ppm_error); if (strcmp(output.filename, "-") == 0) { /* Write samples to stdout */ output.file = stdout; #if defined (_WIN32) && !defined(__MINGW32__) _setmode(_fileno(output.file), _O_BINARY); #endif } else { output.file = fopen(output.filename, "wb"); if (!output.file) { fprintf(stderr, "Failed to open %s\n", output.filename); exit(1); } } //r = mirisdr_set_testmode(dongle.dev, 1); /* Reset endpoint before we start reading from it (mandatory) */ verbose_reset_buffer(dongle.dev); pthread_create(&controller.thread, NULL, controller_thread_fn, (void *)(&controller)); usleep(100000); pthread_create(&output.thread, NULL, output_thread_fn, (void *)(&output)); pthread_create(&demod.thread, NULL, demod_thread_fn, (void *)(&demod)); pthread_create(&dongle.thread, NULL, dongle_thread_fn, (void *)(&dongle)); while (!do_exit) { usleep(100000); } if (do_exit) { fprintf(stderr, "\nUser cancel, exiting...\n");} else { fprintf(stderr, "\nLibrary error %d, exiting...\n", r);} mirisdr_cancel_async(dongle.dev); pthread_join(dongle.thread, NULL); safe_cond_signal(&demod.ready, &demod.ready_m); pthread_join(demod.thread, NULL); safe_cond_signal(&output.ready, &output.ready_m); pthread_join(output.thread, NULL); safe_cond_signal(&controller.hop, &controller.hop_m); pthread_join(controller.thread, NULL); //dongle_cleanup(&dongle); demod_cleanup(&demod); output_cleanup(&output); controller_cleanup(&controller); if (output.file != stdout) { fclose(output.file);} mirisdr_close(dongle.dev); return r >= 0 ? r : -r; } // vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab libmirisdr-4-2.0.0/src/miri_sdr.c000066400000000000000000000244671423227345400166000ustar00rootroot00000000000000/* * MiriSDR * Copyright (C) 2012 by Steve Markgraf * Copyright (C) 2012 by Dimitri Stolnikov * * 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 2 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 . */ #include #include #include #include #include #if !defined (_WIN32) || defined(__MINGW32__) #include #else #include #endif #include "mirisdr.h" #define DEFAULT_SAMPLE_RATE 500000 #define DEFAULT_ASYNC_BUF_NUMBER 32 #define DEFAULT_BUF_LENGTH (16 * 16384) #define MINIMAL_BUF_LENGTH 512 #define MAXIMAL_BUF_LENGTH (256 * 16384) static int do_exit = 0; static mirisdr_dev_t *dev = NULL; void usage(void) { #if defined (_WIN32) && !defined(__MINGW32__) fprintf(stderr, "Usage:\t miri_sdr.exe [device_index] [samplerate in kHz] " "[gain] [frequency in Hz] [filename]\n"); #else fprintf(stderr, "Usage:\t -f frequency_to_tune_to [Hz]\n" "\t[-m sample format (default: auto]\n" "\t 504: S8 (fastest)\n" "\t 384: S10 +2bits \n" "\t 336: S12\n" "\t 252: S14\n" #if !defined (_WIN32) || defined(__MINGW32__) "\t[-e USB transfer mode (default: 1)]\n" #else "\t[-e USB transfer mode (default: 2)]\n" #endif "\t 1: Isochronous (maximum 196.608 Mbit/s) \n" "\t 2: Bulk (maximum 333Mbit/s, depends on controller type)\n" "\t[-i IF mode (default: ZERO]\n" "\t 0: ZERO\n" "\t 450000: 450 kHz\n" "\t 1620000: 1620kHz\n" "\t 2048000: 2048kHz\n" "\t[-w BW mode (default: 8MHz]\n" "\t 200000: 200kHz\n" "\t 300000: 300kHz\n" "\t 600000: 600kHz\n" "\t 1536000: 1536kHz\n" "\t 5000000: 5MHz\n" "\t 6000000: 6MHz\n" "\t 7000000: 7MHz\n" "\t 8000000: 8MHz\n" "\t[-s samplerate (default: 2048000 Hz)]\n" "\t[-d device_index (default: 0)]\n" "\t[-T device_type device variant (default: 0)]\n" "\t 0: Default\n" "\t 1: SDRPlay\n" "\t[-g gain (default: 0 for auto)]\n" "\t[-b output_block_size (default: 16 * 16384)]\n" "\t[-S force sync output (default: async)]\n" "\tfilename (a '-' dumps samples to stdout)\n\n"); #endif exit(1); } #if defined (_WIN32) && !defined(__MINGW32__) BOOL WINAPI sighandler(int signum) { if (CTRL_C_EVENT == signum) { fprintf(stderr, "Signal caught, exiting!\n"); do_exit = 1; mirisdr_cancel_async(dev); return TRUE; } return FALSE; } #else static void sighandler(int signum) { (void) signum; fprintf(stderr, "Signal caught, exiting!\n"); do_exit = 1; mirisdr_cancel_async(dev); } #endif static void mirisdr_callback(unsigned char *buf, uint32_t len, void *ctx) { if (ctx) { if (fwrite(buf, 1, len, (FILE*)ctx) != len) { fprintf(stderr, "Short write, samples lost, exiting!\n"); mirisdr_cancel_async(dev); } } } int main(int argc, char **argv) { #if !defined (_WIN32) || defined(__MINGW32__) struct sigaction sigact; #endif char *filename = NULL; int n_read; int r, opt; int i, gain = 0; int sync_mode = 0; FILE *file; uint8_t *buffer; uint32_t format = 0; #if !defined (_WIN32) || defined(__MINGW32__) uint32_t transfer = 1; #else uint32_t transfer = 2; #endif uint32_t if_mode = 0; uint32_t bw = 8000000; uint32_t dev_index = 0; uint32_t frequency = 100000000; uint32_t samp_rate = DEFAULT_SAMPLE_RATE; uint32_t out_block_size = DEFAULT_BUF_LENGTH; int device_count; char vendor[256] = { 0 }, product[256] = { 0 }, serial[256] = { 0 }; int count; int gains[100]; uint32_t rates[100]; mirisdr_hw_flavour_t hw_flavour = MIRISDR_HW_DEFAULT; int intval; #if !defined (_WIN32) || defined(__MINGW32__) while ((opt = getopt(argc, argv, "b:d:T:e:f:g:i:m:s:w:S::")) != -1) { switch (opt) { case 'b': out_block_size = (uint32_t)atof(optarg); break; case 'd': dev_index = atoi(optarg); break; case 'T': intval = atoi(optarg); if ((intval >=0) && (intval <= 1)) { hw_flavour = (mirisdr_hw_flavour_t) intval; } break; case 'e': if ((strcmp("ISOC", optarg) == 0) || (strcmp("1", optarg) == 0)) { transfer = 1;} if ((strcmp("BULK", optarg) == 0) || (strcmp("2", optarg) == 0)) { transfer = 2;} break; case 'f': frequency = (uint32_t)atof(optarg); break; case 'g': gain = (int)(atof(optarg) * 10); /* tenths of a dB */ break; case 'i': if_mode = atoi(optarg); break; case 'm': if (strcmp("504", optarg) == 0) { format = 1;} if (strcmp("384", optarg) == 0) { format = 2;} if (strcmp("336", optarg) == 0) { format = 3;} if (strcmp("252", optarg) == 0) { format = 4;} break; case 's': samp_rate = (uint32_t)atof(optarg); break; case 'w': bw = atoi(optarg); break; case 'S': sync_mode = 1; break; default: usage(); break; } } if (argc <= optind) { usage(); } else { filename = argv[optind]; } #else if(argc <6) usage(); dev_index = atoi(argv[1]); samp_rate = atoi(argv[2])*1000; gain=(int)(atof(argv[3]) * 10); /* tenths of a dB */ frequency = atoi(argv[4]); filename = argv[5]; #endif if(out_block_size < MINIMAL_BUF_LENGTH || out_block_size > MAXIMAL_BUF_LENGTH ){ fprintf(stderr, "Output block size wrong value, falling back to default\n"); fprintf(stderr, "Minimal length: %u\n", MINIMAL_BUF_LENGTH); fprintf(stderr, "Maximal length: %u\n", MAXIMAL_BUF_LENGTH); out_block_size = DEFAULT_BUF_LENGTH; } buffer = malloc(out_block_size * sizeof(uint8_t)); device_count = mirisdr_get_device_count(); if (!device_count) { fprintf(stderr, "No supported devices found.\n"); exit(1); } fprintf(stderr, "Found %d device(s):\n", device_count); for (i = 0; i < device_count; i++) { mirisdr_get_device_usb_strings(i, vendor, product, serial); fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial); } fprintf(stderr, "\n"); fprintf(stderr, "Using device %d: %s\n", dev_index, mirisdr_get_device_name(dev_index)); r = mirisdr_open(&dev, dev_index); if (r < 0) { fprintf(stderr, "Failed to open mirisdr device #%d.\n", dev_index); exit(1); } mirisdr_set_hw_flavour(dev, hw_flavour); #if !defined (_WIN32) || defined(__MINGW32__) sigact.sa_handler = sighandler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGPIPE, &sigact, NULL); #else SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); #endif count = mirisdr_get_tuner_gains(dev, NULL); fprintf(stderr, "Supported gain values (%d): ", count); count = mirisdr_get_tuner_gains(dev, gains); for (i = 0; i < count; i++) fprintf(stderr, "%.1f ", gains[i] / 10.0); fprintf(stderr, "\n"); r = mirisdr_get_usb_strings(dev, vendor, product, serial); if (r < 0) fprintf(stderr, "WARNING: Failed to read usb strings.\n"); else fprintf(stderr, "%s, %s: SN: %s\n", vendor, product, serial); /* Set the sample rate */ r = mirisdr_set_sample_rate(dev, samp_rate); if (r < 0) fprintf(stderr, "WARNING: Failed to set sample rate.\n"); else { samp_rate = mirisdr_get_sample_rate(dev); fprintf(stderr, "Sample rate is set to %u Hz.\n", samp_rate); } /* Set the frequency */ r = mirisdr_set_center_freq(dev, frequency); if (r < 0) fprintf(stderr, "WARNING: Failed to set center freq.\n"); else fprintf(stderr, "Tuned to %u Hz.\n", frequency); /* Set sample format */ switch (format) { case 1: mirisdr_set_sample_format(dev, "504_S8"); break; case 2: mirisdr_set_sample_format(dev, "384_S16"); break; case 3: mirisdr_set_sample_format(dev, "336_S16"); break; case 4: mirisdr_set_sample_format(dev, "252_S16"); break; default: mirisdr_set_sample_format(dev, "AUTO"); break; } /* Set USB transfer type */ switch (transfer) { case 1: mirisdr_set_transfer(dev, "ISOC"); break; case 2: mirisdr_set_transfer(dev, "BULK"); break; } /* Set IF mode */ mirisdr_set_if_freq(dev, if_mode); /* Set bandwidth */ mirisdr_set_bandwidth(dev, bw); if (0 == gain) { /* Enable automatic gain */ r = mirisdr_set_tuner_gain_mode(dev, 0); if (r < 0) fprintf(stderr, "WARNING: Failed to enable automatic gain.\n"); } else { /* Enable manual gain */ r = mirisdr_set_tuner_gain_mode(dev, 1); if (r < 0) fprintf(stderr, "WARNING: Failed to enable manual gain.\n"); /* Set the tuner gain */ r = mirisdr_set_tuner_gain(dev, gain); if (r < 0) fprintf(stderr, "WARNING: Failed to set tuner gain.\n"); else fprintf(stderr, "Tuner gain set to %f dB.\n", gain/10.0); } if(strcmp(filename, "-") == 0) { /* Write samples to stdout */ file = stdout; } else { file = fopen(filename, "wb"); if (!file) { fprintf(stderr, "Failed to open %s\n", filename); goto out; } } /* Reset endpoint before we start reading from it (mandatory) */ r = mirisdr_reset_buffer(dev); if (r < 0) fprintf(stderr, "WARNING: Failed to reset buffers.\n"); if (sync_mode) { fprintf(stderr, "Reading samples in sync mode...\n"); while (!do_exit) { r = mirisdr_read_sync(dev, buffer, out_block_size, &n_read); if (r < 0) { fprintf(stderr, "WARNING: sync read failed.\n"); break; } if (fwrite(buffer, 1, n_read, file) != (size_t)n_read) { fprintf(stderr, "Short write, samples lost, exiting!\n"); break; } if ((uint32_t)n_read < out_block_size) { fprintf(stderr, "Short read, samples lost, exiting!\n"); break; } } } else { fprintf(stderr, "Reading samples in async mode...\n"); r = mirisdr_read_async(dev, mirisdr_callback, (void *)file, DEFAULT_ASYNC_BUF_NUMBER, out_block_size); } if (do_exit) fprintf(stderr, "\nUser cancel, exiting...\n"); else fprintf(stderr, "\nLibrary error %d, exiting...\n", r); if (file != stdout) fclose(file); mirisdr_close(dev); free (buffer); out: return r >= 0 ? r : -r; } libmirisdr-4-2.0.0/src/reg.c000066400000000000000000000032271423227345400155340ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ int mirisdr_write_reg (mirisdr_dev_t *p, uint8_t reg, uint32_t val) { uint16_t value = (val & 0xff) << 8 | reg; uint16_t index = (val >> 8) & 0xffff; if (!p) goto failed; if (!p->dh) goto failed; #if MIRISDR_DEBUG >= 2 fprintf( stderr, "write reg: 0x%02x, val 0x%08x\n", reg, val); #endif return libusb_control_transfer(p->dh, 0x42, 0x41, value, index, NULL, 0, CTRL_TIMEOUT); failed: return -1; } #define CMD_RESET 0x40 #define CMD_WREG 0x41 #define CMD_RREG 0x42 #define CMD_START_STREAMING 0x43 #define CMD_DOWNLOAD 0x44 #define CMD_STOP_STREAMING 0x45 //WValue = Addr? #define CMD_REEPROM 0x46 //WValue = Addr? #define CMD_WEEPROM 0x47 #define CMD_READ_UNKNOWN 0x48 //wValue = gpio << 8 | val #define CMD_WGPIO 0x49 #define CMD_EXT_WGPIO_BASE 0x4b /* RSP1 GPIO(0x13) & 0x01 = DSB_NOTCH GPIO(0x13) & 0x04 = BROADCAST_NOTCH */libmirisdr-4-2.0.0/src/soft.c000066400000000000000000000365131423227345400157360ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ #include "soft.h" //float band_limits[] = { // 0., 12., 30., 50., 108., 250., 390., 960., 2400, -1. //}; // //uint32_t band_select[] = { // 0xf780, 0xff80, 0xf280, 0xf380, 0xfa80, 0xf680, 0xf380, 0xfa80, 0x0000, 0x0000 //}; //GPIO0 - DAB notch //GPIO2 - Broadcast FM notch hw_switch_freq_plan_t hw_switch_freq_plan_default[] = { {0, MIRISDR_MODE_AM, MIRISDR_UPCONVERT_MIXER_ON, MIRISDR_AM_PORT2, 16, 0xf780}, {12, MIRISDR_MODE_AM, MIRISDR_UPCONVERT_MIXER_ON, MIRISDR_AM_PORT2, 16, 0xff80}, {30, MIRISDR_MODE_AM, MIRISDR_UPCONVERT_MIXER_ON, MIRISDR_AM_PORT2, 16, 0xf280}, {50, MIRISDR_MODE_VHF, 0, 0, 32, 0xf380}, {108, MIRISDR_MODE_B3, 0, 0, 16, 0xfa80}, {250, MIRISDR_MODE_B3, 0, 0, 16, 0xf680}, {259, 6 , 0, 0, 8, 0xf680}, {330, MIRISDR_MODE_B45, 0, 0, 4, 0xf380}, {960, MIRISDR_MODE_BL, 0, 0, 2, 0xfa80}, {2400, -1, 0, 0, 0, 0x0000}, }; hw_switch_freq_plan_t hw_switch_freq_plan_sdrplay[] = { {0, MIRISDR_MODE_AM, MIRISDR_UPCONVERT_MIXER_ON, MIRISDR_AM_PORT2, 16, 0xf580}, {12, MIRISDR_MODE_AM, MIRISDR_UPCONVERT_MIXER_ON, MIRISDR_AM_PORT2, 16, 0xf580}, {30, MIRISDR_MODE_AM, MIRISDR_UPCONVERT_MIXER_ON, MIRISDR_AM_PORT2, 16, 0xf580}, {50, MIRISDR_MODE_VHF, 0, 0, 32, 0xf180}, {112, MIRISDR_MODE_B3, 0, 0, 16, 0xf580}, {250, MIRISDR_MODE_B3, 0, 0, 16, 0xf480}, {261, 6 , 0, 0, 8, 0xf480}, {404, MIRISDR_MODE_B45, 0, 0, 4, 0xf580}, {1000, MIRISDR_MODE_BL, 0, 0, 2, 0xf580}, {2400, -1, 0, 0, 0, 0x0000}, }; hw_switch_freq_plan_t *hw_switch_freq_plan[2] = { hw_switch_freq_plan_default, hw_switch_freq_plan_sdrplay }; #define BIAS_GPIO 3 void update_reg_8(mirisdr_dev_t *p) { mirisdr_write_reg(p, 0x08, p->reg8|(p->bias?(1<<(BIAS_GPIO+8)):0)); } int mirisdr_set_soft(mirisdr_dev_t *p) { uint32_t reg0 = 0, reg2 = 2, reg5 = 5, reg3 = 3; uint64_t n, thresh, frac, lo_div = 0, fvco = 0, rfvco = 0, offset = 0, afc = 0, a, b, c; int i; /*** registr0 - parametry pásma ***/ /*** registr0 - parameters zone ***/ /* pásmo */ /* zone */ i = 0; while (p->freq >= 1000000 * hw_switch_freq_plan[(int) p->hw_flavour][i].low_cut) { if (hw_switch_freq_plan[(int) p->hw_flavour][i].mode < 0) { break; } i++; } hw_switch_freq_plan_t switch_plan = hw_switch_freq_plan[(int) p->hw_flavour][i-1]; #if MIRISDR_DEBUG >= 1 fprintf(stderr, "mirisdr_set_soft: i:%d flavour:%d flow:%u mode:%d up:%d port:%d lo:%d\n", i-1, (int) p->hw_flavour, switch_plan.low_cut, switch_plan.mode, switch_plan.upconvert_mixer_on, switch_plan.am_port, switch_plan.lo_div); #endif if (switch_plan.mode == MIRISDR_MODE_AM) { reg0 |= MIRISDR_MODE_AM << 4; reg0 |= switch_plan.upconvert_mixer_on << 9; reg0 |= switch_plan.am_port << 11; if (switch_plan.upconvert_mixer_on) { offset += 120000000UL; } lo_div = 16; if (switch_plan.am_port == 0) { p->band = MIRISDR_BAND_AM1; } else { p->band = MIRISDR_BAND_AM2; } } else { reg0 |= switch_plan.mode << 4; lo_div = switch_plan.lo_div; if (switch_plan.mode == MIRISDR_MODE_VHF) { p->band = MIRISDR_BAND_VHF; } else if (switch_plan.mode == MIRISDR_MODE_B3) { p->band = MIRISDR_BAND_3; } else if (switch_plan.mode == MIRISDR_MODE_B45) { p->band = MIRISDR_BAND_45; } else if (switch_plan.mode == MIRISDR_MODE_BL) { p->band = MIRISDR_BAND_L; } } // if (p->freq < 50000000) // { // /* AM režim2, antena 2, AM režim1 - 0x61 */ // /* AM mode2, Antena 2, AM mode1 - 0x61 */ // reg0 |= MIRISDR_MODE_AM << 4; // reg0 |= MIRISDR_UPCONVERT_MIXER_ON << 9; // reg0 |= MIRISDR_AM_PORT2 << 11; // /* AM režim je posunutý o 5 * referenční frekvence, tj. o 120 MHz */ // /* AM mode is shifted about 5 * reference frequency, i.e. 120 MHz */ // lo_div = 16; // offset += 120000000UL; // } // else if (p->freq < 108000000) // { // /* VHF */ // reg0 |= MIRISDR_MODE_VHF << 4; // lo_div = 32; // } // else if (p->freq < 330000000) // { // /* B3 */ // reg0 |= MIRISDR_MODE_B3 << 4; // lo_div = 16; // } // else if (p->freq < 960000000) // { // /* B45 */ // reg0 |= MIRISDR_MODE_B45 << 4; // lo_div = 4; // } // else // { // /* BL */ // reg0 |= MIRISDR_MODE_BL << 4; // lo_div = 2; // } /* RF syntetizer je vždy aktivní */ /* RF synthesizer is always active */ reg0 |= MIRISDR_RF_SYNTHESIZER_ON << 10; /* režim IF filtru - zatím nefunguje? */ /* IF filter mode - has not worked? */ switch (p->if_freq) { case MIRISDR_IF_ZERO: reg0 |= MIRISDR_IF_MODE_ZERO << 12; break; case MIRISDR_IF_450KHZ: reg0 |= MIRISDR_IF_MODE_450KHZ << 12; break; case MIRISDR_IF_1620KHZ: reg0 |= MIRISDR_IF_MODE_1620KHZ << 12; break; case MIRISDR_IF_2048KHZ: reg0 |= MIRISDR_IF_MODE_2048KHZ << 12; break; } /* šířka pásma - 8 MHz, nejvyšší možná */ /* Bandwidth - 8 MHz, the highest possible */ switch (p->bandwidth) { case MIRISDR_BW_200KHZ: reg0 |= 0x00 << 14; break; case MIRISDR_BW_300KHZ: reg0 |= 0x01 << 14; break; case MIRISDR_BW_600KHZ: reg0 |= 0x02 << 14; break; case MIRISDR_BW_1536KHZ: reg0 |= 0x03 << 14; break; case MIRISDR_BW_5MHZ: reg0 |= 0x04 << 14; break; case MIRISDR_BW_6MHZ: reg0 |= 0x05 << 14; break; case MIRISDR_BW_7MHZ: reg0 |= 0x06 << 14; break; case MIRISDR_BW_8MHZ: reg0 |= 0x07 << 14; break; } /* xtal frekvence - nepodporujeme změnu */ /* xtal frequency - we do not support change */ switch (p->xtal) { case MIRISDR_XTAL_19_2M: reg0 |= 0x00 << 17; break; case MIRISDR_XTAL_22M: reg0 |= 0x01 << 17; break; case MIRISDR_XTAL_24M: case MIRISDR_XTAL_24_576M: reg0 |= 0x02 << 17; break; case MIRISDR_XTAL_26M: reg0 |= 0x03 << 17; break; case MIRISDR_XTAL_38_4M: reg0 |= 0x04 << 17; break; } /* 4 bity pro režimy snížené spotřeby */ /* 4 bits for power saving modes */ reg0 |= MIRISDR_IF_LPMODE_NORMAL << 20; reg0 |= MIRISDR_VCO_LPMODE_NORMAL << 23; /* vco frekvence, je lepší použít 64bitový rozsah */ /* VCO frequency is better to use a 64-bit range */ fvco = (p->freq + offset) * lo_div; /* posun po hlavní frekvenci */ /* shift the main frequency */ n = fvco / 96000000UL; /* hlavní registr, hrubé ladění */ /* major registry, coarse tuning */ thresh = 96000000UL / lo_div; /* vedlejší registr, jemné ladění */ /* side register, fine tuning */ frac = (fvco % 96000000UL) / lo_div; /* najdeme největší společný dělitel pro thresh a frac */ /* We find the greatest common divisor for thresh and frac */ for (a = thresh, b = frac; a != 0;) { c = a; a = b % a; b = c; } /* dělíme */ /* divided */ thresh /= b; frac /= b; /* v této části musíme rozlišení snížit na maximální rozsah registru */ /* In this section we reduce the resolution to the maximum extent registry */ a = (thresh + 4094) / 4095; thresh = (thresh + (a / 2)) / a; frac = (frac + (a / 2)) / a; rfvco=(96000000UL * (n * thresh * 4096UL + (frac * 4096UL))) / (thresh * 4096UL * lo_div); if(p->freq + offset < rfvco) frac --; rfvco=(96000000UL * (n * thresh * 4096UL + (frac * 4096UL + afc))) / (thresh * 4096UL * lo_div); afc = ((p->freq + offset - rfvco) * thresh * 4096UL * lo_div) /96000000UL; reg3 |= (afc & 4095) << 4; reg5 |= (0xFFF & thresh) << 4; /* rezervováno, musí být 0x28 */ /* Reserved, must be 0x28 */ reg5 |= MIRISDR_RF_SYNTHESIZER_RESERVED_PROGRAMMING << 16; reg2 |= (0xFFF & frac) << 4; reg2 |= (0x3F & n) << 16; reg2 |= MIRISDR_LBAND_LNA_CALIBRATION_OFF << 22; /* kernel driver nastavuje až při změně frekvence */ /* kernel driver adjusts to changing frequencies */ // i = 0; // // while (p->freq >= 1000000 * band_limits[i + 1]) { // i++; // } // // if (band_select[i] != 0) // { // mirisdr_write_reg(p, 0x08, 0xf380); // mirisdr_write_reg(p, 0x08, 0x6280); // mirisdr_write_reg(p, 0x08, band_select[i]); // } //mirisdr_write_reg(p, 0x08, switch_plan.band_select_word); p->reg8=switch_plan.band_select_word; update_reg_8(p); mirisdr_write_reg(p, 0x09, 0x0e); mirisdr_write_reg(p, 0x09, reg3); mirisdr_write_reg(p, 0x09, reg0); mirisdr_write_reg(p, 0x09, reg5); mirisdr_write_reg(p, 0x09, reg2); // if (band_select[i] != 0) // { // mirisdr_write_reg(p, 0x08, 0xf380); // mirisdr_write_reg(p, 0x08, 0x6280); // mirisdr_write_reg(p, 0x08, band_select[i]); // mirisdr_write_reg(p, 0x09, 0x0e); // mirisdr_write_reg(p, 0x09, 0x03); // // mirisdr_write_reg(p, 0x09, reg0); // mirisdr_write_reg(p, 0x09, reg5); // mirisdr_write_reg(p, 0x09, reg2); // } #if MIRISDR_DEBUG >= 1 fprintf( stderr,"sel:%d %x ",i,band_select[i]); fprintf( stderr,"freq: %.2f MHz (offset: %.2f MHz), n: %lu, fraction: %lu/%lu\n", ((double) n + (double) frac / (double) thresh) * 96.0 / (double) lo_div, (double) offset / 1.0e6, (long unsigned)n, (long unsigned)frac, (long unsigned)thresh); #endif return 0; } int mirisdr_set_center_freq(mirisdr_dev_t *p, uint32_t freq) { p->freq = freq; int r = mirisdr_set_soft(p); r += mirisdr_set_gain(p); // restore gain return r; } uint32_t mirisdr_get_center_freq(mirisdr_dev_t *p) { return p->freq; } int mirisdr_set_if_freq(mirisdr_dev_t *p, uint32_t freq) { if (!p) goto failed; switch (freq) { case 0: p->if_freq = MIRISDR_IF_ZERO; break; case 450000: p->if_freq = MIRISDR_IF_450KHZ; break; case 1620000: p->if_freq = MIRISDR_IF_1620KHZ; break; case 2048000: p->if_freq = MIRISDR_IF_2048KHZ; break; default: fprintf(stderr, "unsupported if frequency: %u Hz\n", freq); goto failed; } int r = mirisdr_set_soft(p); r += mirisdr_set_gain(p); // restore gain return r; failed: return -1; } uint32_t mirisdr_get_if_freq(mirisdr_dev_t *p) { if (!p) goto failed; switch (p->if_freq) { case MIRISDR_IF_ZERO: return 0; case MIRISDR_IF_450KHZ: return 450000; case MIRISDR_IF_1620KHZ: return 1620000; case MIRISDR_IF_2048KHZ: return 2048000; } failed: return -1; } /* not supported yet */ int mirisdr_set_xtal_freq(mirisdr_dev_t *p, uint32_t freq) { (void) p; (void) freq; return -1; } uint32_t mirisdr_get_xtal_freq(mirisdr_dev_t *p) { if (!p) goto failed; switch (p->xtal) { case MIRISDR_XTAL_19_2M: return 19200000; case MIRISDR_XTAL_22M: return 22000000; case MIRISDR_XTAL_24M: case MIRISDR_XTAL_24_576M: /* realně 24 MHz ??? */ return 24000000; case MIRISDR_XTAL_26M: return 26000000; case MIRISDR_XTAL_38_4M: return 38400000; } failed: return -1; } int mirisdr_set_bandwidth(mirisdr_dev_t *p, uint32_t bw) { if (!p) goto failed; switch (bw) { case 200000: p->bandwidth = MIRISDR_BW_200KHZ; break; case 300000: p->bandwidth = MIRISDR_BW_300KHZ; break; case 600000: p->bandwidth = MIRISDR_BW_600KHZ; break; case 1536000: p->bandwidth = MIRISDR_BW_1536KHZ; break; case 5000000: p->bandwidth = MIRISDR_BW_5MHZ; break; case 6000000: p->bandwidth = MIRISDR_BW_6MHZ; break; case 7000000: p->bandwidth = MIRISDR_BW_7MHZ; break; case 8000000: p->bandwidth = MIRISDR_BW_8MHZ; break; default: fprintf(stderr, "unsupported bandwidth: %u Hz\n", bw); goto failed; } int r = mirisdr_set_soft(p); r += mirisdr_set_gain(p); // restore gain return r; failed: return -1; } uint32_t mirisdr_get_bandwidth(mirisdr_dev_t *p) { if (!p) goto failed; switch (p->bandwidth) { case MIRISDR_BW_200KHZ: return 200000; case MIRISDR_BW_300KHZ: return 300000; case MIRISDR_BW_600KHZ: return 600000; case MIRISDR_BW_1536KHZ: return 1536000; case MIRISDR_BW_5MHZ: return 5000000; case MIRISDR_BW_6MHZ: return 6000000; case MIRISDR_BW_7MHZ: return 7000000; case MIRISDR_BW_8MHZ: return 8000000; } failed: return -1; } int mirisdr_set_freq_correction(mirisdr_dev_t *p, int ppm) { (void) p; (void) ppm; fprintf(stderr, "frequency correction not implemented yet\n"); return -1; } int mirisdr_set_direct_sampling(mirisdr_dev_t *p, int on) { (void) p; (void) on; fprintf(stderr, "direct sampling not implemented yet\n"); return -1; } int mirisdr_set_offset_tuning(mirisdr_dev_t *p, int on) { if (!p) goto failed; if (on) { p->if_freq = MIRISDR_IF_450KHZ; } else { p->if_freq = MIRISDR_IF_ZERO; } return mirisdr_set_soft(p); failed: return -1; } int mirisdr_set_transfer(mirisdr_dev_t *p, char *v) { if (!p) goto failed; if (!strcmp(v, "BULK")) { p->transfer = MIRISDR_TRANSFER_BULK; } else if (!strcmp(v, "ISOC")) { p->transfer = MIRISDR_TRANSFER_ISOC; } else { fprintf(stderr, "unsupported transfer type: %s\n", v); goto failed; } return 0; failed: return -1; } const char *mirisdr_get_transfer(mirisdr_dev_t *p) { switch (p->transfer) { case MIRISDR_TRANSFER_BULK: return "BULK"; case MIRISDR_TRANSFER_ISOC: return "ISOC"; } return ""; } mirisdr_band_t mirisdr_get_band (mirisdr_dev_t *p) { return p->band; } int mirisdr_set_bias (mirisdr_dev_t *p, int bias) { p->bias=bias; update_reg_8(p); return 0; } int mirisdr_get_bias (mirisdr_dev_t *p) { return p->bias; } libmirisdr-4-2.0.0/src/soft.h000066400000000000000000000043161423227345400157370ustar00rootroot00000000000000 /*** Register 0: IC Mode / Power Control ***/ /* reg0: 4:8 (AM_MODE, VHF_MODE, B3_MODE, B45_MODE, BL_MODE) */ #define MIRISDR_MODE_AM 0x01 #define MIRISDR_MODE_VHF 0x02 #define MIRISDR_MODE_B3 0x04 #define MIRISDR_MODE_B45 0x08 #define MIRISDR_MODE_BL 0x10 /* reg0: 9 (AM_MODE2) */ #define MIRISDR_UPCONVERT_MIXER_OFF 0 #define MIRISDR_UPCONVERT_MIXER_ON 1 /* reg0: 10 (RF_SYNTH) */ #define MIRISDR_RF_SYNTHESIZER_OFF 0 #define MIRISDR_RF_SYNTHESIZER_ON 1 /* reg0: 11 (AM_PORT_SEL) */ #define MIRISDR_AM_PORT1 0 #define MIRISDR_AM_PORT2 1 /* reg0: 12:13 (FIL_MODE_SEL0, FIL_MODE_SEL1) */ #define MIRISDR_IF_MODE_2048KHZ 0 #define MIRISDR_IF_MODE_1620KHZ 1 #define MIRISDR_IF_MODE_450KHZ 2 #define MIRISDR_IF_MODE_ZERO 3 /* reg0: 14:16 (FIL_BW_SEL0 - FIL_BW_SEL2) */ /* reg0: 17:19 (XTAL_SEL0 - XTAL_SEL2) */ /* reg0: 20:22 (IF_LPMODE0 - IF_LPMODE2) */ #define MIRISDR_IF_LPMODE_NORMAL 0 #define MIRISDR_IF_LPMODE_ONLY_Q 1 #define MIRISDR_IF_LPMODE_ONLY_I 2 #define MIRISDR_IF_LPMODE_LOW_POWER 4 /* reg0: 23 (VCO_LPMODE) */ #define MIRISDR_VCO_LPMODE_NORMAL 0 #define MIRISDR_VCO_LPMODE_LOW_POWER 1 /*** Register 2: Synthesizer Programming ***/ /* reg2: 4:15 (FRAC0 - FRAC11) */ /* reg2: 16:21 (INT0 - INT5) */ /* reg2: 22 (LNACAL_EN) */ #define MIRISDR_LBAND_LNA_CALIBRATION_OFF 0 #define MIRISDR_LBAND_LNA_CALIBRATION_ON 1 /*** Register 6: RF Synthesizer Configuration ***/ /* reg5: 4:15 (THRESH0 - THRESH11) */ /* reg5: 16:21 (reserved) */ #define MIRISDR_RF_SYNTHESIZER_RESERVED_PROGRAMMING 0x28 typedef struct { uint32_t low_cut; int mode; int upconvert_mixer_on; int am_port; int lo_div; uint32_t band_select_word; } hw_switch_freq_plan_t; libmirisdr-4-2.0.0/src/streaming.c000066400000000000000000000022231423227345400167430ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ int mirisdr_streaming_start (mirisdr_dev_t *p) { if (!p) goto failed; if (!p->dh) goto failed; libusb_control_transfer(p->dh, 0x42, 0x43, 0x0, 0x0, NULL, 0, CTRL_TIMEOUT); return 0; failed: return -1; } int mirisdr_streaming_stop (mirisdr_dev_t *p) { if (!p) goto failed; if (!p->dh) goto failed; libusb_control_transfer(p->dh, 0x42, 0x45, 0x0, 0x0, NULL, 0, CTRL_TIMEOUT); return 0; failed: return -1; } libmirisdr-4-2.0.0/src/structs.h000066400000000000000000000056541423227345400165010ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ typedef struct mirisdr_device { uint16_t vid; uint16_t pid; const char *name; const char *manufacturer; const char *product; } mirisdr_device_t; struct mirisdr_dev { libusb_context *ctx; struct libusb_device_handle *dh; /* parametry */ uint32_t index; uint32_t freq; uint32_t rate; int gain; int gain_reduction_lna; int gain_reduction_mixbuffer; int gain_reduction_mixer; int gain_reduction_baseband; mirisdr_hw_flavour_t hw_flavour; mirisdr_band_t band; enum { MIRISDR_FORMAT_AUTO_ON = 0, MIRISDR_FORMAT_AUTO_OFF } format_auto; enum { MIRISDR_FORMAT_252_S16 = 0, MIRISDR_FORMAT_336_S16, MIRISDR_FORMAT_384_S16, MIRISDR_FORMAT_504_S16, MIRISDR_FORMAT_504_S8 } format; enum { MIRISDR_BW_200KHZ = 0, MIRISDR_BW_300KHZ, MIRISDR_BW_600KHZ, MIRISDR_BW_1536KHZ, MIRISDR_BW_5MHZ, MIRISDR_BW_6MHZ, MIRISDR_BW_7MHZ, MIRISDR_BW_8MHZ } bandwidth; enum { MIRISDR_IF_ZERO = 0, MIRISDR_IF_450KHZ, MIRISDR_IF_1620KHZ, MIRISDR_IF_2048KHZ } if_freq; enum { MIRISDR_XTAL_19_2M = 0, MIRISDR_XTAL_22M, MIRISDR_XTAL_24M, MIRISDR_XTAL_24_576M, MIRISDR_XTAL_26M, MIRISDR_XTAL_38_4M } xtal; enum { MIRISDR_TRANSFER_BULK = 0, MIRISDR_TRANSFER_ISOC } transfer; /* async */ enum { MIRISDR_ASYNC_INACTIVE = 0, MIRISDR_ASYNC_CANCELING, MIRISDR_ASYNC_RUNNING, MIRISDR_ASYNC_PAUSED, MIRISDR_ASYNC_FAILED } async_status; mirisdr_read_async_cb_t cb; void *cb_ctx; size_t xfer_buf_num; struct libusb_transfer **xfer; unsigned char **xfer_buf; size_t xfer_out_len; size_t xfer_out_pos; unsigned char *xfer_out; uint32_t addr; int driver_active; int bias; int reg8; }; libmirisdr-4-2.0.0/src/sync.c000066400000000000000000000017511423227345400157330ustar00rootroot00000000000000/* * Copyright (C) 2013 by Miroslav Slugen . */ /* pouze pro bulk transfer a je třeba doplnit konverze formátů */ int mirisdr_read_sync (mirisdr_dev_t *p, void *buf, int len, int *n_read) { if (!p) goto failed; return libusb_bulk_transfer(p->dh, 0x81, buf, len, n_read, DEFAULT_BULK_TIMEOUT); failed: return -1; }