pax_global_header00006660000000000000000000000064132556366260014530gustar00rootroot0000000000000052 comment=99b1d38bee9523ad8bc96e13753131e34093b219 airspyhf-1.1.5/000077500000000000000000000000001325563662600133615ustar00rootroot00000000000000airspyhf-1.1.5/CMakeLists.txt000066400000000000000000000022301325563662600161160ustar00rootroot00000000000000#top dir cmake project for libairspyhf cmake_minimum_required(VERSION 2.8) project (airspyhf_all) #provide missing strtoull() for VC11 if(MSVC11) add_definitions(-Dstrtoull=_strtoui64) endif(MSVC11) add_subdirectory(libairspyhf) add_subdirectory(tools) ######################################################################## # Create uninstall target ######################################################################## configure_file( ${PROJECT_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 ) ######################################################################## # Copy Files Win32 only ######################################################################## if(WIN32 AND NOT CMAKE_CROSSCOMPILING) if (NOT DEFINED LIBUSB_LIBRARIES) configure_file( ${CMAKE_CURRENT_BINARY_DIR}/../libs_win32/libusb-1.0.dll COPYONLY) endif() if (NOT DEFINED THREADS_PTHREADS_WIN32_LIBRARY) configure_file( ${CMAKE_CURRENT_BINARY_DIR}/../libs_win32/pthreadGC2.dll COPYONLY) endif() endif() airspyhf-1.1.5/LICENSE000066400000000000000000000027421325563662600143730ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2017, Airspy All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. airspyhf-1.1.5/README.md000066400000000000000000000037661325563662600146540ustar00rootroot00000000000000# User mode driver for Airspy HF+ This repository contains host software (Linux/Windows) for Airspy HF+, a high performance software defined radio for the HF and VHF bands. http://www.airspy.com/airspy-hf-plus ## How to build host software on Windows: ### For VisualStudio 2013 or later: * `git clone https://github.com/airspy/airspyhf.git host` * Download https://github.com/libusb/libusb/releases/download/v1.0.20/libusb-1.0.20.7z * Extract **libusb-1.0.20.7z** to host directory * You should have **host\libusb-1.0.20** * Download ftp://mirrors.kernel.org/sourceware/pthreads-win32/pthreads-w32-2-9-1-release.zip * Extract **pthreads-w32-2-9-1-release.zip** to host directory * You should have **host\libpthread-2-9-1-win** * Navigate to **src** and Launch **airspyhf.sln** with VisualStudio 2013 or later * In Visual Studio, choose **Release**, **x86** or **x64** then **Build Solution** ### For MinGW: `git clone https://github.com/airspy/airspyhf.git host` `cd host` `mkdir build` `cd build` Normal version: `cmake ../ -G "MSYS Makefiles" -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/` Debug version: `cmake ../ -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/` `make` `make install` ## How to build the host software on Linux: ### Prerequisites for Linux (Debian/Ubuntu/Raspbian): `sudo apt-get install build-essential cmake libusb-1.0-0-dev pkg-config` ### Build host software on Linux: `wget https://github.com/airspy/airspyhf/archive/master.zip` `unzip master.zip` `cd airspyhf-master` `mkdir build` `cd build` `cmake ../ -DINSTALL_UDEV_RULES=ON` `make` `sudo make install` `sudo ldconfig` ## Clean CMake temporary files/dirs: `cd airspyhf-master/build` `rm -rf *` ## Principal authors: Ian Gilmour and Youssef Touil http://www.airspy.com This file is part of Airspy HF (with user mode driver based on Airspy R2, itself based on HackRF project see http://greatscottgadgets.com/hackrf/). airspyhf-1.1.5/cmake/000077500000000000000000000000001325563662600144415ustar00rootroot00000000000000airspyhf-1.1.5/cmake/cmake_uninstall.cmake.in000066400000000000000000000025321325563662600212230ustar00rootroot00000000000000# 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) airspyhf-1.1.5/cmake/modules/000077500000000000000000000000001325563662600161115ustar00rootroot00000000000000airspyhf-1.1.5/cmake/modules/FindLIBAIRSPY.cmake000066400000000000000000000034261325563662600212570ustar00rootroot00000000000000# - Try to find the libairspy library # Once done this defines # # LIBAIRSPYHF_FOUND - system has libairspy # LIBAIRSPYHF_INCLUDE_DIR - the libairspy include directory # LIBAIRSPYHF_LIBRARIES - Link these to use libairspy # Copyright (c) 2013 Benjamin Vernoux # if (LIBAIRSPYHF_INCLUDE_DIR AND LIBAIRSPYHF_LIBRARIES) # in cache already set(LIBAIRSPYHF_FOUND TRUE) else (LIBAIRSPYHF_INCLUDE_DIR AND LIBAIRSPYHF_LIBRARIES) IF (NOT WIN32) # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_LIBRARY() calls find_package(PkgConfig) pkg_check_modules(PC_LIBAIRSPYHF QUIET libairspy) ENDIF(NOT WIN32) FIND_PATH(LIBAIRSPYHF_INCLUDE_DIR NAMES airspy.h HINTS $ENV{LIBAIRSPYHF_DIR}/include ${PC_LIBAIRSPYHF_INCLUDEDIR} PATHS /usr/local/include/libairspyhf /usr/include/libairspyhf /usr/local/include /usr/include ${CMAKE_SOURCE_DIR}/../libairspyhf/src /opt/local/include/libairspyhf ${LIBAIRSPYHF_INCLUDE_DIR} ) set(libairspyhf_library_names airspyhf) FIND_LIBRARY(LIBAIRSPYHF_LIBRARIES NAMES ${libairspyhfhf_library_names} HINTS $ENV{LIBAIRSPYHF_DIR}/lib ${PC_LIBAIRSPYHF_LIBDIR} PATHS /usr/local/lib /usr/lib /opt/local/lib ${PC_LIBAIRSPYHF_LIBDIR} ${PC_LIBAIRSPYHF_LIBRARY_DIRS} ${CMAKE_SOURCE_DIR}/../libairspyhfhf/src ) if(LIBAIRSPYHF_INCLUDE_DIR) set(CMAKE_REQUIRED_INCLUDES ${LIBAIRSPYHF_INCLUDE_DIR}) endif() if(LIBAIRSPYHF_LIBRARIES) set(CMAKE_REQUIRED_LIBRARIES ${LIBAIRSPYHF_LIBRARIES}) endif() include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBAIRSPYHF DEFAULT_MSG LIBAIRSPYHF_LIBRARIES LIBAIRSPYHF_INCLUDE_DIR) MARK_AS_ADVANCED(LIBAIRSPYHF_INCLUDE_DIR LIBAIRSPYHF_LIBRARIES) endif (LIBAIRSPYHF_INCLUDE_DIR AND LIBAIRSPYHF_LIBRARIES)airspyhf-1.1.5/cmake/modules/FindThreads.cmake000066400000000000000000000207171325563662600213150ustar00rootroot00000000000000# 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() airspyhf-1.1.5/cmake/modules/FindUSB1.cmake000066400000000000000000000021321325563662600204240ustar00rootroot00000000000000# - Try to find the freetype library # Once done this defines # # LIBUSB_FOUND - system has libusb # LIBUSB_INCLUDE_DIR - the libusb include directory # LIBUSB_LIBRARIES - Link these to use libusb # Copyright (c) 2006, 2008 Laurent Montel, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) # in cache already set(LIBUSB_FOUND TRUE) else (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) find_package(PkgConfig) if(PKG_CONFIG_FOUND) pkg_check_modules(PC_LIBUSB libusb-1.0) endif(PKG_CONFIG_FOUND) FIND_PATH(LIBUSB_INCLUDE_DIR libusb.h PATHS ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS}) FIND_LIBRARY(LIBUSB_LIBRARIES NAMES usb-1.0 PATHS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS}) include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIR) MARK_AS_ADVANCED(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) endif (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) airspyhf-1.1.5/libairspyhf/000077500000000000000000000000001325563662600156755ustar00rootroot00000000000000airspyhf-1.1.5/libairspyhf/CMakeLists.txt000066400000000000000000000105311325563662600204350ustar00rootroot00000000000000# Copyright 2012 Jared Boone # Copyright 2013/2014 Benjamin Vernoux # # This file is part of AirSpy (based on HackRF 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 2, 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; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. # # Based heavily upon the libftdi cmake setup. cmake_minimum_required(VERSION 2.8) project(libairspyhf C) file(READ ${CMAKE_CURRENT_SOURCE_DIR}/src/airspyhf.h AIRSPYHF_H_CONTENTS) STRING(REGEX MATCH "\#define AIRSPYHF_VER_MAJOR[ \t]+([0-9]+)" AIRSPYHF_VER_MJ ${AIRSPYHF_H_CONTENTS}) STRING(REGEX MATCH "([0-9]+)" AIRSPYHF_VER_MJ ${AIRSPYHF_VER_MJ}) STRING(REGEX MATCH "\#define AIRSPYHF_VER_MINOR[ \t]+([0-9]+)" AIRSPYHF_VER_MI ${AIRSPYHF_H_CONTENTS}) STRING(REGEX MATCH "([0-9]+)" AIRSPYHF_VER_MI ${AIRSPYHF_VER_MI}) STRING(REGEX MATCH "\#define AIRSPYHF_VER_REVISION[ \t]+([0-9]+)" AIRSPYHF_VER_RE ${AIRSPYHF_H_CONTENTS}) STRING(REGEX MATCH "([0-9]+)" AIRSPYHF_VER_RE ${AIRSPYHF_VER_RE}) set(AIRSPYHF_VER_MAJOR ${AIRSPYHF_VER_MJ}) set(AIRSPYHF_VER_MINOR ${AIRSPYHF_VER_MI}) set(AIRSPYHF_VER_REVISION ${AIRSPYHF_VER_RE}) set(PACKAGE libairspyhf) set(VERSION_STRING ${AIRSPYHF_VER_MAJOR}.${AIRSPYHF_VER_MINOR}) set(VERSION ${VERSION_STRING}) set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake/modules) set(CMAKE_C_FLAGS_RELEASE "-O3") set(CMAKE_BUILD_TYPE Release) if(APPLE) set(GR_LIBRARY_DIR "lib") if(NOT CMAKE_INSTALL_NAME_DIR) set(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE PATH "Library Install Name Destination Directory" FORCE) endif(NOT CMAKE_INSTALL_NAME_DIR) if(NOT CMAKE_INSTALL_RPATH) set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE PATH "Library Install RPath" FORCE) endif(NOT CMAKE_INSTALL_RPATH) if(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "Do Build Using Library Install RPath" FORCE) endif(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) endif(APPLE) if(MSVC) set(THREADS_USE_PTHREADS_WIN32 true) else() add_definitions(-Wall) INCLUDE(TestBigEndian) TEST_BIG_ENDIAN(BIGENDIAN) if(${BIGENDIAN}) add_definitions(-DAIRSPYHF_BIG_ENDIAN) endif(${BIGENDIAN}) endif() find_package(USB1 REQUIRED) find_package(Threads REQUIRED) include_directories(${LIBUSB_INCLUDE_DIR} ${THREADS_PTHREADS_INCLUDE_DIR}) add_subdirectory(src) ######################################################################## # Create Pkg Config File ######################################################################## FOREACH(inc ${LIBUSB_INCLUDE_DIR}) LIST(APPEND AIRSPYHF_PC_CFLAGS "-I${inc}") ENDFOREACH(inc) # use space-separation format for the pc file STRING(REPLACE ";" " " AIRSPYHF_PC_CFLAGS "${AIRSPYHF_PC_CFLAGS}") STRING(REPLACE ";" " " AIRSPYHF_PC_LIBS "${AIRSPYHF_PC_LIBS}") # unset these vars to avoid hard-coded paths to cross environment IF(CMAKE_CROSSCOMPILING) UNSET(AIRSPYHF_PC_CFLAGS) UNSET(AIRSPYHF_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}/libairspyhf.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libairspyhf.pc @ONLY) INSTALL( FILES ${CMAKE_CURRENT_BINARY_DIR}/libairspyhf.pc DESTINATION lib${LIB_SUFFIX}/pkgconfig ) ######################################################################## # Create uninstall target ######################################################################## if(NOT airspyhf_all_SOURCE_DIR) configure_file( ${PROJECT_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 ) endif() airspyhf-1.1.5/libairspyhf/airspyhf.sln000066400000000000000000000023651325563662600202460ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "airspyhf", "airspyhf.vcxproj", "{4DFFEDB8-DAE3-4460-AD45-4FEC689BFB44}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {4DFFEDB8-DAE3-4460-AD45-4FEC689BFB44}.Debug|x64.ActiveCfg = Debug|x64 {4DFFEDB8-DAE3-4460-AD45-4FEC689BFB44}.Debug|x64.Build.0 = Debug|x64 {4DFFEDB8-DAE3-4460-AD45-4FEC689BFB44}.Debug|x86.ActiveCfg = Debug|Win32 {4DFFEDB8-DAE3-4460-AD45-4FEC689BFB44}.Debug|x86.Build.0 = Debug|Win32 {4DFFEDB8-DAE3-4460-AD45-4FEC689BFB44}.Release|x64.ActiveCfg = Release|x64 {4DFFEDB8-DAE3-4460-AD45-4FEC689BFB44}.Release|x64.Build.0 = Release|x64 {4DFFEDB8-DAE3-4460-AD45-4FEC689BFB44}.Release|x86.ActiveCfg = Release|Win32 {4DFFEDB8-DAE3-4460-AD45-4FEC689BFB44}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal airspyhf-1.1.5/libairspyhf/airspyhf.vcxproj000066400000000000000000000246331325563662600211470ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 {4DFFEDB8-DAE3-4460-AD45-4FEC689BFB44} Win32Proj airspy_2015 8.1 airspyhf DynamicLibrary true v120_xp Unicode DynamicLibrary false v120_xp true Unicode DynamicLibrary true v120_xp Unicode DynamicLibrary false v120_xp true Unicode true ..\..\libpthread-2-9-1-win\include;..\..\libusb-1.0.20\include\libusb-1.0;$(IncludePath) ..\..\libpthread-2-9-1-win\lib\x86;..\..\libusb-1.0.20\MS32\dll;$(LibraryPath) $(SolutionDir)$(PlatformTarget)\$(Configuration)\ $(SolutionDir)$(PlatformTarget)\$(Configuration)\ true ..\..\libpthread-2-9-1-win\include;..\..\libusb-1.0.20\include\libusb-1.0;$(VC_IncludePath);$(WindowsSdk_71A_IncludePath); ..\..\libpthread-2-9-1-win\lib\x64;..\..\libusb-1.0.20\MS64\dll;$(LibraryPath) $(SolutionDir)$(PlatformTarget)\$(Configuration)\ $(SolutionDir)$(PlatformTarget)\$(Configuration)\ false ..\..\libpthread-2-9-1-win\include;..\..\libusb-1.0.20\include\libusb-1.0;$(IncludePath) ..\..\libpthread-2-9-1-win\lib\x86;..\..\libusb-1.0.20\MS32\dll;$(LibraryPath) $(SolutionDir)$(PlatformTarget)\$(Configuration)\ $(SolutionDir)$(PlatformTarget)\$(Configuration)\ false ..\..\libpthread-2-9-1-win\include;..\..\libusb-1.0.20\include\libusb-1.0;$(VC_IncludePath);$(WindowsSdk_71A_IncludePath); ..\..\libpthread-2-9-1-win\lib\x64;..\..\libusb-1.0.20\MS64\dll;$(LibraryPath) $(SolutionDir)$(PlatformTarget)\$(Configuration)\ $(SolutionDir)$(PlatformTarget)\$(Configuration)\ Level3 Disabled WIN32;_DEBUG;_WINDOWS;_USRDLL;AIRSPY_2015_EXPORTS;%(PreprocessorDefinitions) Windows true pthreadVCE2.lib;libusb-1.0.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) Level3 Disabled _DEBUG;_WINDOWS;_USRDLL;AIRSPY_2015_EXPORTS;%(PreprocessorDefinitions) Windows true pthreadVC2.lib;libusb-1.0.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;AIRSPY_2015_EXPORTS;%(PreprocessorDefinitions) MultiThreaded false StreamingSIMDExtensions2 Fast false Windows true true true pthreadVCE2.lib;libusb-1.0.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true NDEBUG;_WINDOWS;_USRDLL;AIRSPY_2015_EXPORTS;%(PreprocessorDefinitions) MultiThreaded Fast false false false Windows true true true pthreadVC2.lib;libusb-1.0.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) airspyhf-1.1.5/libairspyhf/libairspyhf.pc.in000066400000000000000000000004261325563662600211440ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: AirSpy HF+ Library Description: C Utility Library Version: @VERSION@ Cflags: -I${includedir}/libairspyhf/ @AIRSPYHF_PC_CFLAGS@ Libs: -L${libdir} -lairspyhf Libs.private: @AIRSPYHF_PC_LIBS@ airspyhf-1.1.5/libairspyhf/src/000077500000000000000000000000001325563662600164645ustar00rootroot00000000000000airspyhf-1.1.5/libairspyhf/src/CMakeLists.txt000066400000000000000000000106611325563662600212300ustar00rootroot00000000000000# # Copyright (c) 2012, Jared Boone # Copyright (c) 2013, Michael Ossmann # Copyright (c) 2013, Youssef Touil # Copyright (c) 2013/2014, Benjamin Vernoux # # This file is part of AirSpy HF+ (based on HackRF project). # # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # Neither the name of Great Scott Gadgets nor the names of its contributors may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Based heavily upon the libftdi cmake setup. # Targets set(c_sources ${CMAKE_CURRENT_SOURCE_DIR}/airspyhf.c ${CMAKE_CURRENT_SOURCE_DIR}/iqbalancer.c CACHE INTERNAL "List of C sources") set(c_headers ${CMAKE_CURRENT_SOURCE_DIR}/airspyhf.h ${CMAKE_CURRENT_SOURCE_DIR}/iqbalancer.h ${CMAKE_CURRENT_SOURCE_DIR}/airspyhf_commands.h CACHE INTERNAL "List of C headers") if(MINGW) # This gets us DLL resource information when compiling on MinGW. if(NOT CMAKE_RC_COMPILER) set(CMAKE_RC_COMPILER windres.exe) endif() add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/airspyhfrc.obj DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/airspyhf.h COMMAND ${CMAKE_RC_COMPILER} -D GCC_WINDRES -I ${CMAKE_CURRENT_SOURCE_DIR} -I ${CMAKE_CURRENT_BINARY_DIR} -o ${CMAKE_CURRENT_BINARY_DIR}/airspyrchf.obj -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/airspyhf.rc) set(AIRSPYHF_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/airspyhfrc.obj) endif(MINGW) # Dynamic library add_library(airspyhf SHARED ${c_sources} ${AIRSPYHF_DLL_SRCS}) set_target_properties(airspyhf PROPERTIES VERSION ${AIRSPYHF_VER_MAJOR}.${AIRSPYHF_VER_MINOR}.${AIRSPYHF_VER_REVISION}) set_target_properties(airspyhf PROPERTIES SOVERSION 0) # Static library add_library(airspyhf-static STATIC ${c_sources}) if(MSVC) set_target_properties(airspyhf-static PROPERTIES OUTPUT_NAME "airspyhf_static") else() set_target_properties(airspyhf-static PROPERTIES OUTPUT_NAME "airspyhf") endif() set_target_properties(airspyhf PROPERTIES CLEAN_DIRECT_OUTPUT 1) set_target_properties(airspyhf-static PROPERTIES CLEAN_DIRECT_OUTPUT 1) # Dependencies target_link_libraries(airspyhf ${LIBUSB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) # For cygwin just force UNIX OFF and WIN32 ON if( ${CYGWIN} ) SET(UNIX OFF) SET(WIN32 ON) endif( ${CYGWIN} ) if( ${UNIX} ) install(TARGETS airspyhf LIBRARY DESTINATION lib${LIB_SUFFIX} COMPONENT sharedlibs ) install(TARGETS airspyhf-static ARCHIVE DESTINATION lib${LIB_SUFFIX} COMPONENT staticlibs ) install(FILES ${c_headers} DESTINATION include/${PROJECT_NAME} COMPONENT headers ) endif( ${UNIX} ) if( ${WIN32} ) install(TARGETS airspyhf DESTINATION bin COMPONENT sharedlibs ) install(TARGETS airspyhf-static DESTINATION bin COMPONENT staticlibs ) install(FILES ${c_headers} DESTINATION include/${PROJECT_NAME} COMPONENT headers ) endif( ${WIN32} ) airspyhf-1.1.5/libairspyhf/src/airspyhf.c000066400000000000000000000774151325563662600204730ustar00rootroot00000000000000/* Copyright (c) 2013-2018, Youssef Touil Copyright (c) 2013-2017, Ian Gilmour Copyright (c) 2013-2017, Benjamin Vernoux Copyright (c) 2013, Michael Ossmann Copyright (c) 2012, Jared Boone All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Airspy HF+ nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef _WIN32 #define HAVE_STRUCT_TIMESPEC #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include #include "iqbalancer.h" #include "airspyhf.h" #include "airspyhf_commands.h" #ifndef bool typedef int bool; #define true 1 #define false 0 #endif #ifndef M_PI #define M_PI (3.14159265359) #endif #define MAX(a,b) ((a) > (b) ? a : b) #define MIN(a,b) ((a) < (b) ? a : b) #define SAMPLES_TO_TRANSFER (1024 * 16) #define SERIAL_NUMBER_UNUSED (0) #define RAW_BUFFER_COUNT (8) #define AIRSPYHF_SERIAL_SIZE (28) #define MAX_SAMPLERATE_INDEX (100) #define DEFAULT_SAMPLERATE (768000) #define CALIBRATION_MAGIC (0xA5CA71B0) #define ERASE_FLASH_MAGIC0 (0xC0DE) #define ERASE_FLASH_MAGIC1 (0xBABE) #define STR_PREFIX_SERIAL_AIRSPYHF_SIZE (12) static const char str_prefix_serial_airspyhf[STR_PREFIX_SERIAL_AIRSPYHF_SIZE] = { 'A', 'I', 'R', 'S', 'P', 'Y', 'H', 'F', ' ', 'S', 'N', ':' }; #ifdef AIRSPYHF_BIG_ENDIAN #define TO_LE(x) __builtin_bswap32(x) #else #define TO_LE(x) x #endif #pragma pack(push,1) typedef struct { int16_t im; int16_t re; } airspyhf_complex_int16_t; #pragma pack(pop) struct airspyhf_device { libusb_context* usb_context; libusb_device_handle* usb_device; struct libusb_transfer** transfers; airspyhf_sample_block_cb_fn callback; pthread_t transfer_thread; pthread_t consumer_thread; pthread_cond_t consumer_cv; pthread_mutex_t consumer_mp; uint32_t supported_samplerate_count; uint32_t *supported_samplerates; volatile uint32_t current_samplerate; volatile uint32_t freq_hz; volatile uint32_t freq_khz; volatile int32_t freq_shift; volatile int32_t calibration_ppb; uint8_t enable_dsp; airspyhf_complex_float_t vec; iq_balancer_t iq_balancer; uint32_t transfer_count; uint32_t buffer_size; uint32_t dropped_buffers; uint32_t dropped_buffers_queue[RAW_BUFFER_COUNT]; airspyhf_complex_int16_t *received_samples_queue[RAW_BUFFER_COUNT]; volatile bool streaming; volatile bool stop_requested; volatile int received_samples_queue_head; volatile int received_samples_queue_tail; volatile int received_buffer_count; airspyhf_complex_float_t *output_buffer; void* ctx; }; typedef struct calibration_record { uint32_t magic_number; int32_t calibration_ppb; } calibration_record_t; static const uint16_t airspyhf_usb_vid = 0x03EB; static const uint16_t airspyhf_usb_pid = 0x800C; static int airspyhf_config_read(airspyhf_device_t* device, uint8_t *buffer, uint16_t length); static int cancel_transfers(airspyhf_device_t* device) { uint32_t transfer_index; if (device->transfers != NULL) { for (transfer_index = 0; transfer_indextransfer_count; transfer_index++) { if (device->transfers[transfer_index] != NULL) { libusb_cancel_transfer(device->transfers[transfer_index]); } } return AIRSPYHF_SUCCESS; } else { return AIRSPYHF_ERROR; } } static int free_transfers(airspyhf_device_t* device) { int i; uint32_t transfer_index; if (device->transfers != NULL) { free(device->output_buffer); device->output_buffer = NULL; for (transfer_index = 0; transfer_index < device->transfer_count; transfer_index++) { if (device->transfers[transfer_index] != NULL) { free(device->transfers[transfer_index]->buffer); libusb_free_transfer(device->transfers[transfer_index]); device->transfers[transfer_index] = NULL; } } free(device->transfers); device->transfers = NULL; for (i = 0; i < RAW_BUFFER_COUNT; i++) { if (device->received_samples_queue[i] != NULL) { free(device->received_samples_queue[i]); device->received_samples_queue[i] = NULL; } } } return AIRSPYHF_SUCCESS; } static int allocate_transfers(airspyhf_device_t* const device) { int i; uint32_t transfer_index; if (device->transfers == NULL) { device->output_buffer = (airspyhf_complex_float_t *) malloc((device->buffer_size / sizeof(airspyhf_complex_int16_t)) * sizeof(airspyhf_complex_float_t)); for (i = 0; i < RAW_BUFFER_COUNT; i++) { device->received_samples_queue[i] = (airspyhf_complex_int16_t *) malloc(device->buffer_size); if (device->received_samples_queue[i] == NULL) { return AIRSPYHF_ERROR; } memset(device->received_samples_queue[i], 0, device->buffer_size); } device->transfers = (struct libusb_transfer**) calloc(device->transfer_count, sizeof(struct libusb_transfer)); if (device->transfers == NULL) { return AIRSPYHF_ERROR; } for (transfer_index = 0; transfer_indextransfer_count; transfer_index++) { device->transfers[transfer_index] = libusb_alloc_transfer(0); if (device->transfers[transfer_index] == NULL) { return AIRSPYHF_ERROR; } libusb_fill_bulk_transfer( device->transfers[transfer_index], device->usb_device, 0, (unsigned char*) malloc(device->buffer_size), device->buffer_size, NULL, device, 0); if (device->transfers[transfer_index]->buffer == NULL) { return AIRSPYHF_ERROR; } } return AIRSPYHF_SUCCESS; } else { return AIRSPYHF_ERROR; } } static int prepare_transfers(airspyhf_device_t* device, const uint_fast8_t endpoint_address, libusb_transfer_cb_fn callback) { int error; uint32_t transfer_index; if (device->transfers != NULL) { for (transfer_index = 0; transfer_indextransfer_count; transfer_index++) { device->transfers[transfer_index]->endpoint = endpoint_address; device->transfers[transfer_index]->callback = callback; error = libusb_submit_transfer(device->transfers[transfer_index]); if (error != 0) { return AIRSPYHF_ERROR; } } return AIRSPYHF_SUCCESS; } return AIRSPYHF_ERROR; } static void multiply_complex_complex(airspyhf_complex_float_t *a, const airspyhf_complex_float_t *b) { float re = a->re * b->re - a->im * b->im; a->im = a->im * b->re + a->re * b->im; a->re = re; } static void multiply_complex_real(airspyhf_complex_float_t *a, const float b) { a->re *= b; a->im *= b; } static inline void rotate_complex(airspyhf_complex_float_t *vec, const airspyhf_complex_float_t *rot) { multiply_complex_complex(vec, rot); float norm = 1.99f - (vec->re * vec->re + vec->im * vec->im); multiply_complex_real(vec, norm); } static void convert_samples(airspyhf_device_t* device, airspyhf_complex_int16_t *src, airspyhf_complex_float_t *dest, int count) { const float scale = 1.0f / 32768; int i; airspyhf_complex_float_t vec = device->vec; airspyhf_complex_float_t rot; double angle = 2.0 * M_PI * device->freq_shift / (double) device->current_samplerate; rot.re = (float) cos(angle); rot.im = (float) -sin(angle); for (i = 0; i < count; i++) { dest[i].re = src[i].re * scale; dest[i].im = src[i].im * scale; } if (device->enable_dsp) { iq_balancer_process(&device->iq_balancer, dest, count); for (i = 0; i < count; i++) { rotate_complex(&vec, &rot); multiply_complex_complex(&dest[i], &vec); } device->vec = vec; } } static void* consumer_threadproc(void *arg) { int sample_count; airspyhf_complex_int16_t *input_samples; uint32_t dropped_buffers; airspyhf_device_t* device = (airspyhf_device_t*) arg; airspyhf_transfer_t transfer; #ifdef _WIN32 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); #endif pthread_mutex_lock(&device->consumer_mp); while (device->streaming && !device->stop_requested) { while (device->received_buffer_count == 0 && device->streaming && !device->stop_requested) { pthread_cond_wait(&device->consumer_cv, &device->consumer_mp); } if (!device->streaming || device->stop_requested) { break; } input_samples = (airspyhf_complex_int16_t *) device->received_samples_queue[device->received_samples_queue_tail]; dropped_buffers = device->dropped_buffers_queue[device->received_samples_queue_tail]; device->received_samples_queue_tail = (device->received_samples_queue_tail + 1) & (RAW_BUFFER_COUNT - 1); pthread_mutex_unlock(&device->consumer_mp); sample_count = device->buffer_size / sizeof(airspyhf_complex_int16_t); convert_samples(device, input_samples, device->output_buffer, sample_count); transfer.device = device; transfer.ctx = device->ctx; transfer.samples = device->output_buffer; transfer.sample_count = sample_count; transfer.dropped_samples = (uint64_t) dropped_buffers * (uint64_t) sample_count; if (device->callback(&transfer) != 0) { device->stop_requested = true; } pthread_mutex_lock(&device->consumer_mp); device->received_buffer_count--; } pthread_mutex_unlock(&device->consumer_mp); pthread_exit(NULL); return NULL; } static void airspyhf_libusb_transfer_callback(struct libusb_transfer* usb_transfer) { airspyhf_complex_int16_t *temp; airspyhf_device_t* device = (airspyhf_device_t*) usb_transfer->user_data; if (!device->streaming || device->stop_requested) { return; } if (usb_transfer->status == LIBUSB_TRANSFER_COMPLETED && usb_transfer->actual_length == usb_transfer->length) { pthread_mutex_lock(&device->consumer_mp); if (device->received_buffer_count < RAW_BUFFER_COUNT) { temp = device->received_samples_queue[device->received_samples_queue_head]; device->received_samples_queue[device->received_samples_queue_head] = (airspyhf_complex_int16_t *) usb_transfer->buffer; usb_transfer->buffer = (uint8_t *) temp; device->dropped_buffers_queue[device->received_samples_queue_head] = device->dropped_buffers; device->dropped_buffers = 0; device->received_samples_queue_head = (device->received_samples_queue_head + 1) & (RAW_BUFFER_COUNT - 1); device->received_buffer_count++; pthread_cond_signal(&device->consumer_cv); } else { device->dropped_buffers++; } pthread_mutex_unlock(&device->consumer_mp); if (libusb_submit_transfer(usb_transfer) != 0) { device->streaming = false; } } else { device->streaming = false; } } static void* transfer_threadproc(void* arg) { airspyhf_device_t* device = (struct airspyhf_device*) arg; int error; struct timeval timeout = { 0, 500000 }; #ifdef _WIN32 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); #endif while (device->streaming && !device->stop_requested) { error = libusb_handle_events_timeout_completed(device->usb_context, &timeout, NULL); if (error < 0) { if (error != LIBUSB_ERROR_INTERRUPTED) device->streaming = false; } } pthread_exit(NULL); return NULL; } static int kill_io_threads(airspyhf_device_t* device) { if (device->streaming) { device->stop_requested = true; cancel_transfers(device); pthread_mutex_lock(&device->consumer_mp); pthread_cond_signal(&device->consumer_cv); pthread_mutex_unlock(&device->consumer_mp); pthread_join(device->transfer_thread, NULL); pthread_join(device->consumer_thread, NULL); device->stop_requested = false; device->streaming = false; } return AIRSPYHF_SUCCESS; } static int create_io_threads(airspyhf_device_t* device, airspyhf_sample_block_cb_fn callback) { int result; pthread_attr_t attr; if (!device->streaming && !device->stop_requested) { device->callback = callback; device->streaming = true; result = prepare_transfers(device, LIBUSB_ENDPOINT_IN | AIRSPYHF_ENDPOINT_IN, (libusb_transfer_cb_fn)airspyhf_libusb_transfer_callback); if (result != AIRSPYHF_SUCCESS) { return result; } device->received_samples_queue_head = 0; device->received_samples_queue_tail = 0; device->received_buffer_count = 0; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); result = pthread_create(&device->consumer_thread, &attr, consumer_threadproc, device); if (result != 0) { return AIRSPYHF_ERROR; } result = pthread_create(&device->transfer_thread, &attr, transfer_threadproc, device); if (result != 0) { return AIRSPYHF_ERROR; } pthread_attr_destroy(&attr); } else { return AIRSPYHF_ERROR; } return AIRSPYHF_SUCCESS; } static void airspyhf_open_exit(airspyhf_device_t* device) { if (device->usb_device != NULL) { libusb_release_interface(device->usb_device, 0); libusb_close(device->usb_device); device->usb_device = NULL; } libusb_exit(device->usb_context); device->usb_context = NULL; } static void upper_string(unsigned char *string, size_t len) { while (len > 0) { if (*string >= 'a' && *string <= 'z') { *string = *string - 32; } string++; len--; } } static int airspyhf_read_samplerates_from_fw(airspyhf_device_t* device, uint32_t* buffer, const uint32_t len) { int result; result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, AIRSPYHF_GET_SAMPLERATES, 0, len, (unsigned char*) buffer, (len > 0 ? len : 1) * (int16_t) sizeof(uint32_t), 0); if (result < 1) { return AIRSPYHF_ERROR; } return AIRSPYHF_SUCCESS; } static void airspyhf_open_device(airspyhf_device_t* device, int* ret, uint16_t vid, uint16_t pid, uint64_t serial_number_val) { int i; int result; libusb_device_handle** libusb_dev_handle; int serial_number_len; libusb_device_handle* dev_handle; libusb_device *dev; libusb_device** devices = NULL; ssize_t cnt; int serial_descriptor_index; struct libusb_device_descriptor device_descriptor; unsigned char serial_number[AIRSPYHF_SERIAL_SIZE + 1]; libusb_dev_handle = &device->usb_device; *libusb_dev_handle = NULL; cnt = libusb_get_device_list(device->usb_context, &devices); if (cnt < 0) { *ret = AIRSPYHF_ERROR; return; } i = 0; while ((dev = devices[i++]) != NULL) { libusb_get_device_descriptor(dev, &device_descriptor); if ((device_descriptor.idVendor == vid) && (device_descriptor.idProduct == pid)) { if (serial_number_val != SERIAL_NUMBER_UNUSED) { serial_descriptor_index = device_descriptor.iSerialNumber; if (serial_descriptor_index > 0) { if (libusb_open(dev, libusb_dev_handle) != 0) { *libusb_dev_handle = NULL; continue; } dev_handle = *libusb_dev_handle; serial_number_len = libusb_get_string_descriptor_ascii(dev_handle, serial_descriptor_index, serial_number, sizeof(serial_number)); if (serial_number_len == AIRSPYHF_SERIAL_SIZE && !memcmp(str_prefix_serial_airspyhf, serial_number, STR_PREFIX_SERIAL_AIRSPYHF_SIZE)) { uint64_t serial = SERIAL_NUMBER_UNUSED; // use same code to detemine device's serial number as in airspyhf_list_devices() { char *start, *end; serial_number[AIRSPYHF_SERIAL_SIZE] = 0; start = (char*)(serial_number + STR_PREFIX_SERIAL_AIRSPYHF_SIZE); end = NULL; serial = strtoull(start, &end, 16); } if (serial == serial_number_val) { result = libusb_set_configuration(dev_handle, 1); if (result != 0) { libusb_close(dev_handle); *libusb_dev_handle = NULL; continue; } result = libusb_claim_interface(dev_handle, 0); if (result != 0) { libusb_close(dev_handle); *libusb_dev_handle = NULL; continue; } result = libusb_set_interface_alt_setting(dev_handle, 0, 1); if (result != 0) { libusb_close(dev_handle); *libusb_dev_handle = NULL; continue; } break; } else { libusb_close(dev_handle); *libusb_dev_handle = NULL; continue; } } else { libusb_close(dev_handle); *libusb_dev_handle = NULL; continue; } } } else { if (libusb_open(dev, libusb_dev_handle) == 0) { dev_handle = *libusb_dev_handle; result = libusb_set_configuration(dev_handle, 1); if (result != 0) { libusb_close(dev_handle); *libusb_dev_handle = NULL; continue; } result = libusb_claim_interface(dev_handle, 0); if (result != 0) { libusb_close(dev_handle); *libusb_dev_handle = NULL; continue; } result = libusb_set_interface_alt_setting(dev_handle, 0, 1); if (result != 0) { libusb_close(dev_handle); *libusb_dev_handle = NULL; continue; } break; } } } } libusb_free_device_list(devices, 1); dev_handle = device->usb_device; if (dev_handle == NULL) { *ret = AIRSPYHF_ERROR; return; } *ret = AIRSPYHF_SUCCESS; return; } int airspyhf_list_devices(uint64_t *serials, int count) { libusb_device_handle* libusb_dev_handle; struct libusb_context *context; libusb_device** devices = NULL; libusb_device *dev; struct libusb_device_descriptor device_descriptor; int serial_descriptor_index; int serial_number_len; int output_count; int i; unsigned char serial_number[AIRSPYHF_SERIAL_SIZE + 1]; if (serials) { memset(serials, 0, sizeof(uint64_t) * count); } if (libusb_init(&context) != 0) { return AIRSPYHF_ERROR; } if (libusb_get_device_list(context, &devices) < 0) { return AIRSPYHF_ERROR; } i = 0; output_count = 0; while ((dev = devices[i++]) != NULL && (!serials || output_count < count)) { libusb_get_device_descriptor(dev, &device_descriptor); if ((device_descriptor.idVendor == airspyhf_usb_vid) && (device_descriptor.idProduct == airspyhf_usb_pid)) { serial_descriptor_index = device_descriptor.iSerialNumber; if (serial_descriptor_index > 0) { if (libusb_open(dev, &libusb_dev_handle) != 0) { continue; } serial_number_len = libusb_get_string_descriptor_ascii(libusb_dev_handle, serial_descriptor_index, serial_number, sizeof(serial_number)); if (serial_number_len == AIRSPYHF_SERIAL_SIZE && !memcmp(str_prefix_serial_airspyhf, serial_number, STR_PREFIX_SERIAL_AIRSPYHF_SIZE)) { char *start, *end; uint64_t serial; serial_number[AIRSPYHF_SERIAL_SIZE] = 0; start = (char*)(serial_number + STR_PREFIX_SERIAL_AIRSPYHF_SIZE); end = NULL; serial = strtoull(start, &end, 16); if (serial == 0 && start == end) { libusb_close(libusb_dev_handle); continue; } if (serials) { serials[output_count] = serial; } output_count++; } libusb_close(libusb_dev_handle); } } } libusb_free_device_list(devices, 1); libusb_exit(context); return output_count; } static int airspyhf_open_init(airspyhf_device_t** device, uint64_t serial_number) { airspyhf_device_t* lib_device; calibration_record_t record; int libusb_error; int result; *device = NULL; lib_device = (airspyhf_device_t*) calloc(1, sizeof(airspyhf_device_t)); if (lib_device == NULL) { return AIRSPYHF_ERROR; } libusb_error = libusb_init(&lib_device->usb_context); if (libusb_error != 0) { free(lib_device); return AIRSPYHF_ERROR; } airspyhf_open_device(lib_device, &result, airspyhf_usb_vid, airspyhf_usb_pid, serial_number); if (lib_device->usb_device == NULL) { libusb_exit(lib_device->usb_context); free(lib_device); return result; } lib_device->transfers = NULL; lib_device->callback = NULL; lib_device->transfer_count = 16; lib_device->buffer_size = SAMPLES_TO_TRANSFER * sizeof(airspyhf_complex_int16_t); lib_device->streaming = false; lib_device->stop_requested = false; result = airspyhf_read_samplerates_from_fw(lib_device, &lib_device->supported_samplerate_count, 0); if (result == AIRSPYHF_SUCCESS) { lib_device->supported_samplerates = (uint32_t *)malloc(lib_device->supported_samplerate_count * sizeof(uint32_t)); result = airspyhf_read_samplerates_from_fw(lib_device, lib_device->supported_samplerates, lib_device->supported_samplerate_count); if (result != AIRSPYHF_SUCCESS) { free(lib_device->supported_samplerates); lib_device->supported_samplerates = NULL; } } if (result != AIRSPYHF_SUCCESS) { lib_device->supported_samplerate_count = 1; lib_device->supported_samplerates = (uint32_t *) malloc(lib_device->supported_samplerate_count * sizeof(uint32_t)); lib_device->supported_samplerates[0] = DEFAULT_SAMPLERATE; } lib_device->current_samplerate = lib_device->supported_samplerates[0]; result = allocate_transfers(lib_device); if (result != 0) { airspyhf_open_exit(lib_device); free(lib_device); return AIRSPYHF_ERROR; } pthread_cond_init(&lib_device->consumer_cv, NULL); pthread_mutex_init(&lib_device->consumer_mp, NULL); lib_device->freq_hz = 0; lib_device->freq_khz = 0; lib_device->freq_shift = 0; lib_device->vec.re = 1.0f; lib_device->vec.im = 0.0f; lib_device->enable_dsp = 1; if (airspyhf_config_read(lib_device, (uint8_t *) &record, sizeof(record)) == AIRSPYHF_SUCCESS) { if (record.magic_number == CALIBRATION_MAGIC) { lib_device->calibration_ppb = record.calibration_ppb; } else { lib_device->calibration_ppb = 0; } } else { lib_device->calibration_ppb = 0; } iq_balancer_init(&lib_device->iq_balancer); *device = lib_device; return AIRSPYHF_SUCCESS; } void ADDCALL airspyhf_lib_version(airspyhf_lib_version_t* lib_version) { lib_version->major_version = AIRSPYHF_VER_MAJOR; lib_version->minor_version = AIRSPYHF_VER_MINOR; lib_version->revision = AIRSPYHF_VER_REVISION; } int ADDCALL airspyhf_open_sn(airspyhf_device_t** device, uint64_t serial_number) { int result; result = airspyhf_open_init(device, serial_number); return result; } int ADDCALL airspyhf_open(airspyhf_device_t** device) { int result; result = airspyhf_open_init(device, SERIAL_NUMBER_UNUSED); return result; } int ADDCALL airspyhf_close(airspyhf_device_t* device) { int result; result = AIRSPYHF_SUCCESS; if (device != NULL) { result = airspyhf_stop(device); pthread_cond_destroy(&device->consumer_cv); pthread_mutex_destroy(&device->consumer_mp); airspyhf_open_exit(device); free_transfers(device); free(device->supported_samplerates); free(device); } return result; } int ADDCALL airspyhf_get_samplerates(airspyhf_device_t* device, uint32_t* buffer, const uint32_t len) { if (len == 0) { *buffer = device->supported_samplerate_count; } else if (len <= device->supported_samplerate_count) { memcpy(buffer, device->supported_samplerates, len * sizeof(uint32_t)); } else { return AIRSPYHF_ERROR; } return AIRSPYHF_SUCCESS; } int ADDCALL airspyhf_set_samplerate(airspyhf_device_t* device, uint32_t samplerate) { int result; uint32_t i; if (samplerate > MAX_SAMPLERATE_INDEX) { for (i = 0; i < device->supported_samplerate_count; i++) { if (samplerate == device->supported_samplerates[i]) { samplerate = i; break; } } } if (samplerate >= device->supported_samplerate_count) { return AIRSPYHF_ERROR; } libusb_clear_halt(device->usb_device, LIBUSB_ENDPOINT_IN | 1); result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, AIRSPYHF_SET_SAMPLERATE, 0, samplerate, NULL, 0, 0 ); if (result != 0) { return AIRSPYHF_ERROR; } device->current_samplerate = device->supported_samplerates[samplerate]; return AIRSPYHF_SUCCESS; } int ADDCALL airspyhf_set_receiver_mode(airspyhf_device_t* device, receiver_mode_t value) { int result; result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, AIRSPYHF_RECEIVER_MODE, value, 0, NULL, 0, 0); if (result != 0) { return AIRSPYHF_ERROR; } return AIRSPYHF_SUCCESS; } int ADDCALL airspyhf_start(airspyhf_device_t* device, airspyhf_sample_block_cb_fn callback, void* ctx) { int result; memset(device->dropped_buffers_queue, 0, RAW_BUFFER_COUNT * sizeof(uint32_t)); device->dropped_buffers = 0; device->vec.re = 1.0f; device->vec.im = 0.0f; iq_balancer_init(&device->iq_balancer); result = airspyhf_set_receiver_mode(device, RECEIVER_MODE_OFF); if (result != AIRSPYHF_SUCCESS) { return result; } libusb_clear_halt(device->usb_device, LIBUSB_ENDPOINT_IN | AIRSPYHF_ENDPOINT_IN); result = airspyhf_set_receiver_mode(device, RECEIVER_MODE_ON); if (result == AIRSPYHF_SUCCESS) { device->ctx = ctx; result = create_io_threads(device, callback); } return result; } int ADDCALL airspyhf_is_streaming(airspyhf_device_t* device) { return device->streaming; } int ADDCALL airspyhf_stop(airspyhf_device_t* device) { int result1, result2; result1 = kill_io_threads(device); result2 = airspyhf_set_receiver_mode(device, RECEIVER_MODE_OFF); if (result2 != AIRSPYHF_SUCCESS) { return result2; } return result1; } int ADDCALL airspyhf_set_freq(airspyhf_device_t* device, const uint32_t freq_hz) { const int tuning_alignment = 1000; const int if_shift = 5000; const uint32_t lo_low_khz = 200; int result; uint8_t buf[4]; uint32_t adjusted_freq_hz = (uint32_t) ((int64_t) freq_hz * (int64_t) (1000000000LL + device->calibration_ppb) / 1000000000LL); uint32_t freq_khz = MAX(lo_low_khz, (adjusted_freq_hz + if_shift + tuning_alignment / 2) / tuning_alignment); if (device->freq_khz != freq_khz) { buf[0] = (uint8_t) ((freq_khz >> 24) & 0xff); buf[1] = (uint8_t) ((freq_khz >> 16) & 0xff); buf[2] = (uint8_t) ((freq_khz >> 8) & 0xff); buf[3] = (uint8_t) ((freq_khz) & 0xff); result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, AIRSPYHF_SET_FREQ, 0, 0, (unsigned char*)&buf, sizeof(buf), 0); if (result < sizeof(buf)) { return AIRSPYHF_ERROR; } device->freq_khz = freq_khz; } device->freq_hz = freq_hz; device->freq_shift = adjusted_freq_hz - freq_khz * 1000; return AIRSPYHF_SUCCESS; } static int airspyhf_config_write(airspyhf_device_t* device, uint8_t *buffer, uint16_t length) { int result; uint8_t buf[256]; memset(buf, 0, sizeof(buf)); memcpy(buf, buffer, MIN(length, sizeof(buf))); result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, AIRSPYHF_CONFIG_WRITE, 0, 0, buf, sizeof(buf), 0); if (result < sizeof(buf)) { return AIRSPYHF_ERROR; } return AIRSPYHF_SUCCESS; } static int airspyhf_config_read(airspyhf_device_t* device, uint8_t *buffer, uint16_t length) { uint8_t buf[256]; int result; result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, AIRSPYHF_CONFIG_READ, 0, 0, buf, sizeof(buf), 0); memcpy(buffer, buf, MIN(length, sizeof(buf))); if (result < sizeof(buf)) { return AIRSPYHF_ERROR; } return AIRSPYHF_SUCCESS; } int ADDCALL airspyhf_get_calibration(airspyhf_device_t* device, int32_t* ppb) { if (ppb) { *ppb = device->calibration_ppb; return AIRSPYHF_SUCCESS; } return AIRSPYHF_ERROR; } int ADDCALL airspyhf_flash_calibration(airspyhf_device_t* device) { calibration_record_t record; record.magic_number = CALIBRATION_MAGIC; record.calibration_ppb = device->calibration_ppb; if (airspyhf_config_write(device, (uint8_t *)&record, sizeof(record)) != AIRSPYHF_SUCCESS) { return AIRSPYHF_ERROR; } return AIRSPYHF_SUCCESS; } int ADDCALL airspyhf_set_calibration(airspyhf_device_t* device, int32_t ppb) { device->calibration_ppb = ppb; return airspyhf_set_freq(device, device->freq_hz); } int ADDCALL airspyhf_set_optimal_iq_correction_point(airspyhf_device_t* device, float w) { iq_balancer_set_optimal_point(&device->iq_balancer, w); return AIRSPYHF_SUCCESS; } int ADDCALL airspyhf_board_partid_serialno_read(airspyhf_device_t* device, airspyhf_read_partid_serialno_t* read_partid_serialno) { uint8_t length; int result; length = sizeof(airspyhf_read_partid_serialno_t); result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, AIRSPYHF_GET_SERIALNO_BOARDID, 0, 0, (unsigned char*)read_partid_serialno, length, 0); if (result < length) { return AIRSPYHF_ERROR; } return AIRSPYHF_SUCCESS; } int ADDCALL airspyhf_version_string_read(airspyhf_device_t* device, char* version, uint8_t length) { int result; char version_local[MAX_VERSION_STRING_SIZE]; result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, AIRSPYHF_GET_VERSION_STRING, 0, 0, (unsigned char*) version_local, (MAX_VERSION_STRING_SIZE - 1), 0); if (result < 0) { return AIRSPYHF_ERROR; } else { if (length > 0) { memcpy(version, version_local, length - 1); version[length - 1] = 0; return AIRSPYHF_SUCCESS; } else { return AIRSPYHF_ERROR; } } } int ADDCALL airspyhf_set_user_output(airspyhf_device_t* device, airspyhf_user_output_t pin, airspyhf_user_output_state_t value) { int result; result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, AIRSPYHF_SET_USER_OUTPUT, (uint16_t)pin, (uint16_t)value, NULL, 0, 0); if (result < 0) { return AIRSPYHF_ERROR; } return AIRSPYHF_SUCCESS; } int ADDCALL airspyhf_set_hf_agc(airspyhf_device_t* device, uint8_t flag) { int result; result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, AIRSPYHF_SET_HF_AGC, (uint16_t) flag, 0, NULL, 0, 0); if (result < 0) { return AIRSPYHF_ERROR; } return AIRSPYHF_SUCCESS; } int ADDCALL airspyhf_set_hf_agc_threshold(airspyhf_device_t* device, uint8_t flag) { int result; result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, AIRSPYHF_SET_HF_AGC_THRESHOLD, (uint16_t) flag, 0, NULL, 0, 0); if (result < 0) { return AIRSPYHF_ERROR; } return AIRSPYHF_SUCCESS; } int ADDCALL airspyhf_set_hf_att(airspyhf_device_t* device, uint8_t value) { int result; result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, AIRSPYHF_SET_HF_ATT, (uint16_t) value, 0, NULL, 0, 0); if (result < 0) { return AIRSPYHF_ERROR; } return AIRSPYHF_SUCCESS; } int ADDCALL airspyhf_set_hf_lna(airspyhf_device_t* device, uint8_t flag) { int result; result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, AIRSPYHF_SET_HF_LNA, (uint16_t) flag, 0, NULL, 0, 0); if (result < 0) { return AIRSPYHF_ERROR; } return AIRSPYHF_SUCCESS; } int ADDCALL airspyhf_set_lib_dsp(airspyhf_device_t* device, uint8_t flag) { device->enable_dsp = flag; return AIRSPYHF_SUCCESS; }airspyhf-1.1.5/libairspyhf/src/airspyhf.h000066400000000000000000000133031325563662600204620ustar00rootroot00000000000000/* Copyright (c) 2013-2018, Youssef Touil Copyright (c) 2013-2017, Ian Gilmour Copyright (c) 2013-2017, Benjamin Vernoux Copyright (c) 2013, Michael Ossmann Copyright (c) 2012, Jared Boone All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Airspy HF+ nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __AIRSPYHF_H__ #define __AIRSPYHF_H__ #include #define AIRSPYHF_VERSION "1.1.5" #define AIRSPYHF_VER_MAJOR 1 #define AIRSPYHF_VER_MINOR 1 #define AIRSPYHF_VER_REVISION 5 #define AIRSPYHF_ENDPOINT_IN (1) #if defined(_WIN32) && !defined(STATIC_AIRSPYHFPLUS) #define ADD_EXPORTS /* You should define ADD_EXPORTS *only* when building the DLL. */ #ifdef ADD_EXPORTS #define ADDAPI __declspec(dllexport) #else #define ADDAPI __declspec(dllimport) #endif /* Define calling convention in one place, for convenience. */ #define ADDCALL __cdecl #else /* _WIN32 not defined. */ /* Define with no value on non-Windows OSes. */ #define ADDAPI #define ADDCALL #endif #ifdef __cplusplus extern "C" { #endif enum airspyhf_error { AIRSPYHF_SUCCESS = 0, AIRSPYHF_ERROR = -1 }; typedef struct { float re; float im; } airspyhf_complex_float_t; typedef struct { uint32_t part_id; uint32_t serial_no[4]; } airspyhf_read_partid_serialno_t; enum airspyhf_board_id { AIRSPYHF_BOARD_ID_UNKNOWN_AIRSPYHF = 0, AIRSPYHF_BOARD_ID_AIRSPYHF_REV_A = 1, AIRSPYHF_BOARD_ID_INVALID = 0xFF, }; typedef enum { AIRSPYHF_USER_OUTPUT_0 = 0, AIRSPYHF_USER_OUTPUT_1 = 1, AIRSPYHF_USER_OUTPUT_2 = 2, AIRSPYHF_USER_OUTPUT_3 = 3 } airspyhf_user_output_t; typedef enum { AIRSPYHF_USER_OUTPUT_LOW = 0, AIRSPYHF_USER_OUTPUT_HIGH = 1 } airspyhf_user_output_state_t; typedef struct airspyhf_device airspyhf_device_t; typedef struct { airspyhf_device_t* device; void* ctx; airspyhf_complex_float_t* samples; int sample_count; uint64_t dropped_samples; } airspyhf_transfer_t; typedef struct { uint32_t major_version; uint32_t minor_version; uint32_t revision; } airspyhf_lib_version_t; #define MAX_VERSION_STRING_SIZE (64) typedef int (*airspyhf_sample_block_cb_fn) (airspyhf_transfer_t* transfer_fn); extern ADDAPI void ADDCALL airspyhf_lib_version(airspyhf_lib_version_t* lib_version); extern ADDAPI int ADDCALL airspyhf_list_devices(uint64_t *serials, int count); extern ADDAPI int ADDCALL airspyhf_open(airspyhf_device_t** device); extern ADDAPI int ADDCALL airspyhf_open_sn(airspyhf_device_t** device, uint64_t serial_number); extern ADDAPI int ADDCALL airspyhf_close(airspyhf_device_t* device); extern ADDAPI int ADDCALL airspyhf_start(airspyhf_device_t* device, airspyhf_sample_block_cb_fn callback, void* ctx); extern ADDAPI int ADDCALL airspyhf_stop(airspyhf_device_t* device); extern ADDAPI int ADDCALL airspyhf_is_streaming(airspyhf_device_t* device); extern ADDAPI int ADDCALL airspyhf_set_freq(airspyhf_device_t* device, const uint32_t freq_hz); extern ADDAPI int ADDCALL airspyhf_set_lib_dsp(airspyhf_device_t* device, const uint8_t flag); extern ADDAPI int ADDCALL airspyhf_get_samplerates(airspyhf_device_t* device, uint32_t* buffer, const uint32_t len); extern ADDAPI int ADDCALL airspyhf_set_samplerate(airspyhf_device_t* device, uint32_t samplerate); extern ADDAPI int ADDCALL airspyhf_get_calibration(airspyhf_device_t* device, int32_t* ppb); extern ADDAPI int ADDCALL airspyhf_set_calibration(airspyhf_device_t* device, int32_t ppb); extern ADDAPI int ADDCALL airspyhf_set_optimal_iq_correction_point(airspyhf_device_t* device, float w); extern ADDAPI int ADDCALL airspyhf_flash_calibration(airspyhf_device_t* device); extern ADDAPI int ADDCALL airspyhf_board_partid_serialno_read(airspyhf_device_t* device, airspyhf_read_partid_serialno_t* read_partid_serialno); extern ADDAPI int ADDCALL airspyhf_version_string_read(airspyhf_device_t* device, char* version, uint8_t length); extern ADDAPI int ADDCALL airspyhf_set_user_output(airspyhf_device_t* device, airspyhf_user_output_t pin, airspyhf_user_output_state_t value); extern ADDAPI int ADDCALL airspyhf_set_hf_agc(airspyhf_device_t* device, uint8_t flag); extern ADDAPI int ADDCALL airspyhf_set_hf_agc_threshold(airspyhf_device_t* device, uint8_t flag); extern ADDAPI int ADDCALL airspyhf_set_hf_att(airspyhf_device_t* device, uint8_t value); extern ADDAPI int ADDCALL airspyhf_set_hf_lna(airspyhf_device_t* device, uint8_t flag); #ifdef __cplusplus } #endif #endif//__AIRSPYHF_H__ airspyhf-1.1.5/libairspyhf/src/airspyhf_commands.h000066400000000000000000000047401325563662600223500ustar00rootroot00000000000000/* Copyright (c) 2013-2017, Youssef Touil Copyright (c) 2013-2017, Ian Gilmour Copyright (c) 2013-2017, Benjamin Vernoux All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Airspy HF+ nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __AIRSPYHF_COMMANDS_H__ #define __AIRSPYHF_COMMANDS_H__ #include typedef enum { RECEIVER_MODE_OFF = 0, RECEIVER_MODE_ON = 1 } receiver_mode_t; #define AIRSPYHF_CMD_MAX (13) typedef enum { AIRSPYHF_INVALID = 0, AIRSPYHF_RECEIVER_MODE = 1, AIRSPYHF_SET_FREQ = 2, AIRSPYHF_GET_SAMPLERATES = 3, AIRSPYHF_SET_SAMPLERATE = 4, AIRSPYHF_CONFIG_READ = 5, AIRSPYHF_CONFIG_WRITE = 6, AIRSPYHF_GET_SERIALNO_BOARDID = 7, AIRSPYHF_SET_USER_OUTPUT = 8, AIRSPYHF_GET_VERSION_STRING = 9, AIRSPYHF_SET_HF_AGC = 10, AIRSPYHF_SET_HF_AGC_THRESHOLD = 11, AIRSPYHF_SET_HF_ATT = 12, AIRSPYHF_SET_HF_LNA = AIRSPYHF_CMD_MAX, } airspyhf_vendor_request; #endif airspyhf-1.1.5/libairspyhf/src/iqbalancer.c000066400000000000000000000222731325563662600207370ustar00rootroot00000000000000/* Copyright (c) 2016-2018, Youssef Touil All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Airspy HF+ nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "iqbalancer.h" #define MATH_PI 3.14159265359 static uint8_t __window_initialized = 0; static float __window[FFTBins]; static void __init_window() { int i; if (__window_initialized) { return; } const int length = FFTBins - 1; for (i = 0; i <= length; i++) { __window[i] = (float) ( + 0.27105140069342 - 0.43329793923448 * cos(2.0 * MATH_PI * i / length) + 0.21812299954311 * cos(4.0 * MATH_PI * i / length) - 0.06592544638803 * cos(6.0 * MATH_PI * i / length) + 0.01081174209837 * cos(8.0 * MATH_PI * i / length) - 0.00077658482522 * cos(10.0 * MATH_PI * i / length) + 0.00001388721735 * cos(12.0 * MATH_PI * i / length) ); } __window_initialized = 1; } static void window(airspyhf_complex_float_t *buffer, int length) { int i; for (i = 0; i < length; i++) { buffer[i].re *= __window[i]; buffer[i].im *= __window[i]; } } static void fft(airspyhf_complex_float_t *buffer, int length) { int nm1 = length - 1; int nd2 = length / 2; int i, j, jm1, k, l, m, le, le2, ip; airspyhf_complex_float_t u, t, r; m = 0; i = length; while (i > 1) { ++m; i = (i >> 1); } j = nd2; for (i = 1; i < nm1; ++i) { if (i < j) { t = buffer[j]; buffer[j] = buffer[i]; buffer[i] = t; } k = nd2; while (k <= j) { j = j - k; k = k / 2; } j += k; } for (l = 1; l <= m; ++l) { le = 1 << l; le2 = le / 2; u.re = 1.0f; u.im = 0.0f; r.re = (float) cos(MATH_PI / le2); r.im = (float) -sin(MATH_PI / le2); for (j = 1; j <= le2; ++j) { jm1 = j - 1; for (i = jm1; i <= nm1; i += le) { ip = i + le2; t.re = u.re * buffer[ip].re - u.im * buffer[ip].im; t.im = u.im * buffer[ip].re + u.re * buffer[ip].im; buffer[ip].re = buffer[i].re - t.re; buffer[ip].im = buffer[i].im - t.im; buffer[i].re += t.re; buffer[i].im += t.im; } t.re = u.re * r.re - u.im * r.im; t.im = u.im * r.re + u.re * r.im; u.re = t.re; u.im = t.im; } } } static void cancel_dc(iq_balancer_t *iq_balancer, airspyhf_complex_float_t* iq, int length) { int i; float iavg = iq_balancer->iavg; float qavg = iq_balancer->qavg; for (i = 0; i < length; i++) { iavg += DcTimeConst * (iq[i].re - iavg); qavg += DcTimeConst * (iq[i].im - qavg); iq[i].re -= iavg; iq[i].im -= qavg; } iq_balancer->iavg = iavg; iq_balancer->qavg = qavg; } static void adjust_phase(airspyhf_complex_float_t *iq, float phase) { int i; for (i = 0; i < FFTBins; i++) { float re = iq[i].re; float im = iq[i].im; iq[i].re += phase * im; iq[i].im += phase * re; } } static airspyhf_complex_float_t multiply_complex_complex(airspyhf_complex_float_t *a, const airspyhf_complex_float_t *b) { airspyhf_complex_float_t result; result.re = a->re * b->re - a->im * b->im; result.im = a->im * b->re + a->re * b->im; return result; } static float fsign(const float x) { return x >= 0 ? 1.0f : -1.0f; } static float utility(iq_balancer_t *iq_balancer, airspyhf_complex_float_t* iq, float phase) { airspyhf_complex_float_t fftPtr[FFTBins * sizeof(airspyhf_complex_float_t)]; memcpy(fftPtr, iq, FFTBins * sizeof(airspyhf_complex_float_t)); adjust_phase(fftPtr, phase); window(fftPtr, FFTBins); fft(fftPtr, FFTBins); float acc1 = 0.0f; float acc2 = 0.0f; float max1 = 0.0f; float max2 = 0.0f; int count1 = 0; int count2 = 0; for (int i = 1 + BinsToSkip, j = FFTBins - 1 - BinsToSkip; i < FFTBins / 2 - BinsToSkip; i++, j--) { airspyhf_complex_float_t prod = multiply_complex_complex(fftPtr + i, fftPtr + j); float corr = prod.re * prod.re + prod.im * prod.im; float m1 = fftPtr[i].re * fftPtr[i].re + fftPtr[i].im * fftPtr[i].im; float m2 = fftPtr[j].re * fftPtr[j].re + fftPtr[j].im * fftPtr[j].im; if (i >= iq_balancer->optimal_bin - BinsToOptimize / 2 && i <= iq_balancer->optimal_bin + BinsToOptimize / 2) { acc1 += corr; if (max1 < m1) { max1 = m1; } if (max1 < m2) { max1 = m2; } count1++; } else { acc2 += corr; if (max2 < m1) { max2 = m1; } if (max2 < m2) { max2 = m2; } count2++; } } if (count1 == 0) { return acc2; } acc1 /= count1; acc2 /= count2; return acc1 * max1 * BoostFactor + acc2 * max2; } static void estimate_phase_imbalance(iq_balancer_t *iq_balancer, airspyhf_complex_float_t* iq) { float u = utility(iq_balancer, iq, iq_balancer->phase); float phase = iq_balancer->phase + iq_balancer->step; if (phase > MaxPhaseCorrection) { phase = MaxPhaseCorrection; } else if (phase < -MaxPhaseCorrection) { phase = -MaxPhaseCorrection; } float candidateUtility = utility(iq_balancer, iq, phase); if (candidateUtility < u) { iq_balancer->fail = 0; iq_balancer->phase += PhaseAlpha * (phase - iq_balancer->phase); iq_balancer->step *= StepIncrement; if (fabsf(iq_balancer->step) > MaximumStep) { iq_balancer->step = MaximumStep * fsign(iq_balancer->step); } } else { if (++iq_balancer->fail > MaximumFail) { iq_balancer->fail = 0; iq_balancer->step = -iq_balancer->step; } iq_balancer->step *= StepDecrement; if (fabsf(iq_balancer->step) < MinimumStep) { iq_balancer->step = MinimumStep * fsign(iq_balancer->step); } } } static void adjust_phase_amplitude(iq_balancer_t *iq_balancer, airspyhf_complex_float_t* iq, int length) { int i; float scale = 1.0f / (length - 1); for (i = 0; i < length; i++) { float re = iq[i].re; float im = iq[i].im; float phase = (i * iq_balancer->last_phase + (length - 1 - i) * iq_balancer->phase) * scale; iq[i].re += phase * im; iq[i].im += phase * re; re = iq[i].re * iq[i].re; im = iq[i].im * iq[i].im; iq_balancer->iampavg += BalanceTimeConst * (re - iq_balancer->iampavg); iq_balancer->qampavg_pre += BalanceTimeConst * (im - iq_balancer->qampavg_pre); if (iq_balancer->qampavg_pre != 0) { double gain = sqrt(iq_balancer->iampavg / iq_balancer->qampavg_pre); iq_balancer->gain = iq_balancer->gain + iq_balancer->gain_alpha * (gain - iq_balancer->gain); } iq[i].im *= (float) iq_balancer->gain; iq_balancer->qampavg_post += BalanceTimeConst * (iq[i].im * iq[i].im - iq_balancer->qampavg_post); if (iq_balancer->qampavg_post != 0) { double gain_balance = sqrt(iq_balancer->iampavg / iq_balancer->qampavg_post); double alpha_contribution = AlphaContributionScale * fabs(1.0 - gain_balance); if (alpha_contribution < MinAlphaContribution) alpha_contribution = MinAlphaContribution; else if (alpha_contribution > MaxAlphaContribution) alpha_contribution = MaxAlphaContribution; iq_balancer->gain_alpha += BalanceTimeConst * (alpha_contribution - iq_balancer->gain_alpha); } } iq_balancer->last_phase = iq_balancer->phase; } void iq_balancer_process(iq_balancer_t *iq_balancer, airspyhf_complex_float_t* iq, int length) { cancel_dc(iq_balancer, iq, length); uint8_t i = 0; while (length >= FFTBins) { if (++i == SkippedBuffers) { estimate_phase_imbalance(iq_balancer, iq); i = 0; } adjust_phase_amplitude(iq_balancer, iq, FFTBins); iq += FFTBins; length -= FFTBins; } adjust_phase_amplitude(iq_balancer, iq, length); } void iq_balancer_set_optimal_point(iq_balancer_t *iq_balancer, float w) { if (w < 0) { w = -w; } if (w > 0.5f) { w = 0.5; } iq_balancer->optimal_bin = (int) (FFTBins * w); } void iq_balancer_init(iq_balancer_t *iq_balancer) { iq_balancer->iavg = 0.0f; iq_balancer->qavg = 0.0f; iq_balancer->phase = 0.0f; iq_balancer->last_phase = 0.0f; iq_balancer->step = MinimumStep; iq_balancer->optimal_bin = 0; iq_balancer->fail = 0; iq_balancer->gain = 1.0; iq_balancer->gain_alpha = InitialGainAlpha; iq_balancer->iampavg = 0.0; iq_balancer->qampavg_pre = 0.0; iq_balancer->qampavg_post = 0.0; __init_window(); } airspyhf-1.1.5/libairspyhf/src/iqbalancer.h000066400000000000000000000047771325563662600207550ustar00rootroot00000000000000/* Copyright (c) 2016-2018, Youssef Touil All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Airspy HF+ nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __IQ_BALANCER_H__ #define __IQ_BALANCER_H__ #include "airspyhf.h" #define FFTBins 512 #define BinsToSkip 10 #define BinsToOptimize 20 #define BoostFactor 10000 #define SkippedBuffers 4 #define DcTimeConst 1e-5f #define BalanceTimeConst 2.5e-6f #define AlphaContributionScale 0.01f #define MinAlphaContribution 1e-8f #define MaxAlphaContribution 1e-3f #define MaximumFail 10 #define MaximumStep 1e-2f #define MinimumStep 1e-7f #define StepIncrement 1.1f #define StepDecrement 0.9f #define MaxPhaseCorrection 0.2f #define PhaseAlpha 0.01f #define InitialGainAlpha 0.01f typedef struct _iq_balancer_t { float iavg; float qavg; float phase; float last_phase; float step; int optimal_bin; int fail; double gain; double gain_alpha; double iampavg; double qampavg_pre; double qampavg_post; } iq_balancer_t; void iq_balancer_init(iq_balancer_t *iq_balancer); void iq_balancer_set_optimal_point(iq_balancer_t *iq_balancer, float w); void iq_balancer_process(iq_balancer_t *iq_balancer, airspyhf_complex_float_t* iq, int length); #endif airspyhf-1.1.5/tools/000077500000000000000000000000001325563662600145215ustar00rootroot00000000000000airspyhf-1.1.5/tools/52-airspyhf.rules000066400000000000000000000001451325563662600176460ustar00rootroot00000000000000ATTR{idVendor}=="03eb", ATTR{idProduct}=="800c", SYMLINK+="airspyhf-%k", MODE="660", GROUP="plugdev" airspyhf-1.1.5/tools/CMakeLists.txt000066400000000000000000000041431325563662600172630ustar00rootroot00000000000000# Copyright 2012 Jared Boone # Copyright 2013/2014 Benjamin Vernoux # # This file is part of AirSpy (based on HackRF 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 2, 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; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. # # Based heavily upon the libftdi cmake setup. cmake_minimum_required(VERSION 2.8) project(airspyhf-tools C) set(MAJOR_VERSION 0) set(MINOR_VERSION 1) set(PACKAGE airspyhf-tools) set(VERSION_STRING ${MAJOR_VERSION}.${MINOR_VERSION}) set(VERSION ${VERSION_STRING}) set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake/modules) ######################################################################## # Create uninstall target ######################################################################## if(NOT airspyhf_all_SOURCE_DIR) configure_file( ${PROJECT_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 ) endif() ######################################################################## # Install udev rules ######################################################################## option(INSTALL_UDEV_RULES "Install udev rules for AirSpy HF+" OFF) if (INSTALL_UDEV_RULES) install ( FILES 52-airspyhf.rules DESTINATION "/etc/udev/rules.d" COMPONENT "udev" ) else (INSTALL_UDEV_RULES) message (STATUS "Udev rules not being installed, install them with -DINSTALL_UDEV_RULES=ON") endif (INSTALL_UDEV_RULES)