pax_global_header00006660000000000000000000000064132043750120014507gustar00rootroot0000000000000052 comment=4667336afafd95380767b2817289de620d5ee634 SoapyHackRF-soapy-hackrf-0.3.2/000077500000000000000000000000001320437501200162105ustar00rootroot00000000000000SoapyHackRF-soapy-hackrf-0.3.2/.travis.yml000066400000000000000000000030471320437501200203250ustar00rootroot00000000000000######################################################################## ## Travis CI config for SoapyHackRF ## ## * installs hackrf from PPA ## * installs SoapySDR from source ## * confirms build and install ## * checks that drivers load ######################################################################## sudo: required dist: trusty language: cpp compiler: gcc env: global: - INSTALL_PREFIX=/usr/local - SOAPY_SDR_BRANCH=master matrix: - BUILD_TYPE=Debug - BUILD_TYPE=Release before_install: # regular ubuntu packages - sudo add-apt-repository main - sudo add-apt-repository universe # driver development files from ppa - sudo add-apt-repository -y ppa:myriadrf/drivers # update after package changes - sudo apt-get update install: #sdr development files - sudo apt-get install --no-install-recommends -q -y libhackrf-dev # install SoapySDR from source - git clone https://github.com/pothosware/SoapySDR.git - pushd SoapySDR - git checkout ${SOAPY_SDR_BRANCH} - mkdir build && cd build - cmake ../ -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_PYTHON=OFF -DENABLE_PYTHON3=OFF - make && sudo make install - popd script: - mkdir build && cd build - cmake ../ -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} - make && sudo make install # print info about the install - export LD_LIBRARY_PATH=${INSTALL_PREFIX}/lib:${LD_LIBRARY_PATH} - export PATH=${INSTALL_PREFIX}/bin:${PATH} - SoapySDRUtil --info - SoapySDRUtil --check=hackrf SoapyHackRF-soapy-hackrf-0.3.2/CMakeLists.txt000066400000000000000000000031171320437501200207520ustar00rootroot00000000000000######################################################################## # Build Soapy SDR support module for HackRF ######################################################################## cmake_minimum_required(VERSION 2.8.7) project(SoapyHackRF CXX) find_package(SoapySDR "0.4.0" NO_MODULE) if (NOT SoapySDR_FOUND) message(FATAL_ERROR "Soapy SDR development files not found...") endif () list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) find_package(LIBHACKRF) if (NOT LIBHACKRF_FOUND) message(FATAL_ERROR "HackRF development files not found...") endif () message(STATUS "LIBHACKRF_INCLUDE_DIRS - ${LIBHACKRF_INCLUDE_DIRS}") message(STATUS "LIBHACKRF_LIBRARIES - ${LIBHACKRF_LIBRARIES}") include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${LIBHACKRF_INCLUDE_DIRS}) #enable c++11 features if(CMAKE_COMPILER_IS_GNUCXX) #C++11 is a required language feature for this project include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-std=c++11" HAS_STD_CXX11) if(HAS_STD_CXX11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") else(HAS_STD_CXX11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") endif() #disable warnings for unused parameters add_definitions(-Wno-unused-parameter) endif(CMAKE_COMPILER_IS_GNUCXX) if (APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wc++11-extensions") endif(APPLE) SOAPY_SDR_MODULE_UTIL( TARGET HackRFSupport SOURCES HackRF_Registation.cpp HackRF_Settings.cpp HackRF_Streaming.cpp HackRF_Session.cpp LIBRARIES ${LIBHACKRF_LIBRARIES} ) SoapyHackRF-soapy-hackrf-0.3.2/Changelog.txt000066400000000000000000000032221320437501200206370ustar00rootroot00000000000000Release 0.3.2 (2017-11-19) ========================== - Corrected order of gain elements in the Rx direction - Track settings during TX/RX switch for TRX switching - Prevent spin loop in SoapyHackRF::acquireReadBuffer() - Fix edge case in SoapyHackRF::releaseReadBuffer() - Standard style find script for FindLIBHACKRF.cmake Release 0.3.1 (2017-06-19) ========================== - Cache discovered HackRF results for claimed devices Release 0.3.0 (2017-04-29) ========================== - Major cleanup for thread safety and buffer management - Added label convention to hackrf discovery routine - Support filtering specific devices by serial number - Switch to format constants in streaming implementation Release 0.2.2 (2016-10-19) ========================== - New transceiver_mode_t enum for HackRF API changes - Clarified copyright statements in source files - Update debian files for SoapySDR module ABI format Release 0.2.1 (2016-02-29) ========================== - Fixed debian control file Maintainer/Uploaders - Reset buffer counters before activating RX stream - Rx stream switching waits for tx to be consumed Release 0.2.0 (2015-11-20) ========================== - Implemented Tx/Rx automatic stream switching - Implemented automatic gain distribution algorithm - Implemented the direct buffer access API - Implemented getStreamFormats() for SoapySDR v0.4 - Implemented getNativeStreamFormat() for SoapySDR v0.4 - Implemented getStreamArgsInfo() for SoapySDR v0.4 - Created settings API calls for Bias TX control - Moved buffers device arg into stream args Release 0.1.0 (2015-10-10) ========================== - First release of SoapyHackRF support module SoapyHackRF-soapy-hackrf-0.3.2/FindLIBHACKRF.cmake000066400000000000000000000016701320437501200213040ustar00rootroot00000000000000# - Try to find libhackrf # Once done this will define # LIBHACKRF_FOUND - System has libhackrf # LIBHACKRF_INCLUDE_DIRS - The libhackrf include directories # LIBHACKRF_LIBRARIES - The libraries needed to use libhackrf find_package(PkgConfig) pkg_check_modules(PC_LIBHACKRF QUIET libhackrf) find_path(LIBHACKRF_INCLUDE_DIR NAMES hackrf.h HINTS $ENV{LIBHACKRF_DIR}/include ${PC_LIBHACKRF_INCLUDEDIR} ${PC_LIBHACKRF_INCLUDE_DIRS} PATH_SUFFIXES libhackrf ) find_library(LIBHACKRF_LIBRARY NAMES hackrf HINTS $ENV{LIBHACKRF_DIR}/lib ${PC_LIBHACKRF_LIBDIR} ${PC_LIBHACKRF_LIBRARY_DIRS} ) include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBHACKRF DEFAULT_MSG LIBHACKRF_LIBRARY LIBHACKRF_INCLUDE_DIR) mark_as_advanced(LIBHACKRF_INCLUDE_DIR LIBHACKRF_LIBRARY) set(LIBHACKRF_INCLUDE_DIRS ${LIBHACKRF_INCLUDE_DIR}) set(LIBHACKRF_LIBRARIES ${LIBHACKRF_LIBRARY}) SoapyHackRF-soapy-hackrf-0.3.2/HackRF_Registation.cpp000066400000000000000000000073321320437501200223670ustar00rootroot00000000000000/* * The MIT License (MIT) * * Copyright (c) 2015 Wei Jiang * Copyright (c) 2015-2017 Josh Blum * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "SoapyHackRF.hpp" #include static std::map _cachedResults; static std::vector find_HackRF(const SoapySDR::Kwargs &args) { SoapyHackRFSession Sess; std::vector results; hackrf_device_list_t *list; list =hackrf_device_list(); if (list->devicecount > 0) { for (int i = 0; i < list->devicecount; i++) { hackrf_device* device = NULL; uint8_t board_id = BOARD_ID_INVALID; read_partid_serialno_t read_partid_serialno; hackrf_device_list_open(list, i, &device); SoapySDR::Kwargs options; if (device!=NULL) { hackrf_board_id_read(device, &board_id); options["device"] = hackrf_board_id_name((hackrf_board_id) board_id); char version_str[100]; hackrf_version_string_read(device, &version_str[0], 100); options["version"] = version_str; hackrf_board_partid_serialno_read(device, &read_partid_serialno); char part_id_str[100]; sprintf(part_id_str, "%08x%08x", read_partid_serialno.part_id[0], read_partid_serialno.part_id[1]); options["part_id"] = part_id_str; char serial_str[100]; sprintf(serial_str, "%08x%08x%08x%08x", read_partid_serialno.serial_no[0], read_partid_serialno.serial_no[1], read_partid_serialno.serial_no[2], read_partid_serialno.serial_no[3]); options["serial"] = serial_str; //generate a displayable label string with trimmed serial size_t ofs = 0; while (ofs < sizeof(serial_str) and serial_str[ofs] == '0') ofs++; char label_str[100]; sprintf(label_str, "%s #%d %s", options["device"].c_str(), i, serial_str+ofs); options["label"] = label_str; //filter based on serial and idx const bool serialMatch = args.count("serial") == 0 or args.at("serial") == options["serial"]; const bool idxMatch = args.count("hackrf") == 0 or std::stoi(args.at("hackrf")) == i; if (serialMatch and idxMatch) { results.push_back(options); _cachedResults[serial_str] = options; } hackrf_close(device); } } } hackrf_device_list_free(list); //fill in the cached results for claimed handles for (const auto &serial : HackRF_getClaimedSerials()) { if (_cachedResults.count(serial) == 0) continue; if (args.count("serial") != 0 and args.at("serial") != serial) continue; results.push_back(_cachedResults.at(serial)); } return results; } static SoapySDR::Device *make_HackRF(const SoapySDR::Kwargs &args) { return new SoapyHackRF(args); } static SoapySDR::Registry register_hackrf("hackrf", &find_HackRF, &make_HackRF, SOAPY_SDR_ABI_VERSION); SoapyHackRF-soapy-hackrf-0.3.2/HackRF_Session.cpp000066400000000000000000000037441320437501200215250ustar00rootroot00000000000000/* * The MIT License (MIT) * * Copyright (c) 2015 Josh Blum * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "SoapyHackRF.hpp" #include #include #include static std::mutex sessionMutex; static size_t sessionCount = 0; SoapyHackRFSession::SoapyHackRFSession(void) { std::lock_guard lock(sessionMutex); if (sessionCount == 0) { int ret = hackrf_init(); if (ret != HACKRF_SUCCESS) { SoapySDR::logf(SOAPY_SDR_ERROR, "hackrf_init() failed -- %s", hackrf_error_name(hackrf_error(ret))); } } sessionCount++; } SoapyHackRFSession::~SoapyHackRFSession(void) { std::lock_guard lock(sessionMutex); sessionCount--; if (sessionCount == 0) { int ret = hackrf_exit(); if (ret != HACKRF_SUCCESS) { SoapySDR::logf(SOAPY_SDR_ERROR, "hackrf_exit() failed -- %s", hackrf_error_name(hackrf_error(ret))); } } } SoapyHackRF-soapy-hackrf-0.3.2/HackRF_Settings.cpp000066400000000000000000000443271320437501200217040ustar00rootroot00000000000000/* * The MIT License (MIT) * * Copyright (c) 2015-2016 Wei Jiang * Copyright (c) 2015-2017 Josh Blum * Copyright (c) 2017 Kevin Mehall * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "SoapyHackRF.hpp" std::set &HackRF_getClaimedSerials(void) { static std::set serials; return serials; } SoapyHackRF::SoapyHackRF( const SoapySDR::Kwargs &args ) { if (args.count("label") != 0) SoapySDR_logf( SOAPY_SDR_INFO, "Opening %s...", args.at("label").c_str()); _rx_stream.vga_gain=16; _rx_stream.lna_gain=16; _rx_stream.amp_gain=0; _rx_stream.frequency=0; _rx_stream.samplerate=0; _rx_stream.bandwidth=0; _rx_stream.overflow = false; _tx_stream.vga_gain=0; _tx_stream.amp_gain=0; _tx_stream.frequency=0; _tx_stream.samplerate=0; _tx_stream.bandwidth=0; _tx_stream.burst_samps=0; _tx_stream.burst_end=false; _tx_stream.underflow = false; _current_mode=HACKRF_TRANSCEIVER_MODE_OFF; _auto_bandwidth=true; _dev = nullptr; if (args.count("serial") == 0) throw std::runtime_error("no hackrf device matches"); _serial = args.at("serial"); _current_amp = 0; _current_frequency = 0; _current_samplerate = 0; _current_bandwidth=0; int ret = hackrf_open_by_serial(_serial.c_str(), &_dev); if ( ret != HACKRF_SUCCESS ) { SoapySDR_logf( SOAPY_SDR_INFO, "Could not Open HackRF Device" ); throw std::runtime_error("hackrf open failed"); } HackRF_getClaimedSerials().insert(_serial); } SoapyHackRF::~SoapyHackRF( void ) { HackRF_getClaimedSerials().erase(_serial); if ( _dev ) { hackrf_close( _dev ); } /* cleanup device handles */ } /******************************************************************* * Identification API ******************************************************************/ std::string SoapyHackRF::getDriverKey( void ) const { return("HackRF"); } std::string SoapyHackRF::getHardwareKey( void ) const { std::lock_guard lock(_device_mutex); uint8_t board_id=BOARD_ID_INVALID; hackrf_board_id_read(_dev,&board_id); return(hackrf_board_id_name((hackrf_board_id)board_id)); } SoapySDR::Kwargs SoapyHackRF::getHardwareInfo( void ) const { std::lock_guard lock(_device_mutex); SoapySDR::Kwargs info; char version_str[100]; hackrf_version_string_read(_dev, &version_str[0], 100); info["version"] = version_str; read_partid_serialno_t read_partid_serialno; hackrf_board_partid_serialno_read(_dev, &read_partid_serialno); char part_id_str[100]; sprintf(part_id_str, "%08x%08x", read_partid_serialno.part_id[0], read_partid_serialno.part_id[1]); info["part id"] = part_id_str; char serial_str[100]; sprintf(serial_str, "%08x%08x%08x%08x", read_partid_serialno.serial_no[0], read_partid_serialno.serial_no[1], read_partid_serialno.serial_no[2], read_partid_serialno.serial_no[3]); info["serial"] = serial_str; uint16_t clock; hackrf_si5351c_read(_dev,0,&clock); info["clock source"]=(clock==0x51)?"internal":"external"; return(info); } /******************************************************************* * Channels API ******************************************************************/ size_t SoapyHackRF::getNumChannels( const int dir ) const { return(1); } bool SoapyHackRF::getFullDuplex( const int direction, const size_t channel ) const { return(false); } /******************************************************************* * Settings API ******************************************************************/ SoapySDR::ArgInfoList SoapyHackRF::getSettingInfo(void) const { SoapySDR::ArgInfoList setArgs; SoapySDR::ArgInfo biastxArg; biastxArg.key="bias_tx"; biastxArg.value="false"; biastxArg.name="Antenna Bias"; biastxArg.description="Antenna port power control."; biastxArg.type=SoapySDR::ArgInfo::BOOL; setArgs.push_back(biastxArg); return setArgs; } void SoapyHackRF::writeSetting(const std::string &key, const std::string &value) { if(key=="bias_tx"){ std::lock_guard lock(_device_mutex); _tx_stream.bias=(value=="true") ? true : false; int ret=hackrf_set_antenna_enable(_dev,_tx_stream.bias); if(ret!=HACKRF_SUCCESS){ SoapySDR_logf(SOAPY_SDR_INFO,"Failed to apply antenna bias voltage"); } } } std::string SoapyHackRF::readSetting(const std::string &key) const { if (key == "bias_tx") { return _tx_stream.bias?"true":"false"; } return ""; } /******************************************************************* * Antenna API ******************************************************************/ std::vector SoapyHackRF::listAntennas( const int direction, const size_t channel ) const { std::vector options; options.push_back( "TX/RX" ); return(options); } void SoapyHackRF::setAntenna( const int direction, const size_t channel, const std::string &name ) { /* TODO delete this function or throw if name != RX... */ } std::string SoapyHackRF::getAntenna( const int direction, const size_t channel ) const { return("TX/RX"); } /******************************************************************* * Frontend corrections API ******************************************************************/ bool SoapyHackRF::hasDCOffsetMode( const int direction, const size_t channel ) const { return(false); } /******************************************************************* * Gain API ******************************************************************/ std::vector SoapyHackRF::listGains( const int direction, const size_t channel ) const { std::vector options; if ( direction == SOAPY_SDR_RX ) { // in gr-osmosdr/lib/soapy/ soapy_sink_c.cc and soapy_source_c.cc expect if_gain at front and bb_gain at back options.push_back( "LNA" ); // RX: if_gain options.push_back( "AMP" ); // RX: rf_gain options.push_back( "VGA" ); // RX: bb_gain } else { options.push_back( "VGA" ); // TX: if_gain options.push_back( "AMP" ); // TX: rf_gain } return(options); /* * list available gain elements, * the functions below have a "name" parameter */ } void SoapyHackRF::setGainMode( const int direction, const size_t channel, const bool automatic ) { /* enable AGC if the hardware supports it, or remove this function */ } bool SoapyHackRF::getGainMode( const int direction, const size_t channel ) const { return(false); /* ditto for the AGC */ } void SoapyHackRF::setGain( const int direction, const size_t channel, const double value ) { std::lock_guard lock(_device_mutex); int32_t ret(0), gain(0); gain = value; SoapySDR_logf(SOAPY_SDR_DEBUG,"setGain RF %s, channel %d, gain %d", direction == SOAPY_SDR_RX ? "RX" : "TX", channel, gain); if ( direction == SOAPY_SDR_RX ) { if ( gain <= 0 ) { _rx_stream.lna_gain = 0; _rx_stream.vga_gain = 0; _current_amp = 0; }else if ( gain <= (HACKRF_RX_LNA_MAX_DB / 2) + (HACKRF_RX_VGA_MAX_DB / 2) ) { _rx_stream.vga_gain = (gain / 3) & ~0x1; _rx_stream.lna_gain = gain - _rx_stream.vga_gain; _current_amp = 0; }else if ( gain <= ( (HACKRF_RX_LNA_MAX_DB / 2) + (HACKRF_RX_VGA_MAX_DB / 2) + HACKRF_AMP_MAX_DB) ) { _current_amp = HACKRF_AMP_MAX_DB; _rx_stream.vga_gain = ( (gain - _current_amp) / 3) & ~0x1; _rx_stream.lna_gain = gain -_current_amp - _rx_stream.vga_gain; }else if ( gain <= HACKRF_RX_LNA_MAX_DB + HACKRF_RX_VGA_MAX_DB + HACKRF_AMP_MAX_DB ) { _current_amp = HACKRF_AMP_MAX_DB; _rx_stream.vga_gain = (gain - _current_amp) * double(HACKRF_RX_LNA_MAX_DB) / double(HACKRF_RX_VGA_MAX_DB); _rx_stream.lna_gain = gain - _current_amp - _rx_stream.vga_gain; } _rx_stream.amp_gain=_current_amp; ret = hackrf_set_lna_gain( _dev, _rx_stream.lna_gain ); ret |= hackrf_set_vga_gain( _dev, _rx_stream.vga_gain ); ret |= hackrf_set_amp_enable( _dev, (_current_amp > 0) ? 1 : 0 ); }else if ( direction == SOAPY_SDR_TX ) { if ( gain <= 0 ) { _current_amp = 0; _tx_stream.vga_gain = 0; }else if ( gain <= (HACKRF_TX_VGA_MAX_DB / 2) ) { _current_amp = 0; _tx_stream.vga_gain = gain; }else if ( gain <= HACKRF_TX_VGA_MAX_DB + HACKRF_AMP_MAX_DB ) { _current_amp = HACKRF_AMP_MAX_DB; _tx_stream.vga_gain = gain - HACKRF_AMP_MAX_DB; } _tx_stream.amp_gain=_current_amp; ret = hackrf_set_txvga_gain( _dev, _tx_stream.vga_gain ); ret |= hackrf_set_amp_enable( _dev, (_current_amp > 0) ? 1 : 0 ); } if ( ret != HACKRF_SUCCESS ) { SoapySDR::logf( SOAPY_SDR_ERROR, "setGain(%f) returned %s", value, hackrf_error_name( (hackrf_error) ret ) ); } } void SoapyHackRF::setGain( const int direction, const size_t channel, const std::string &name, const double value ) { std::lock_guard lock(_device_mutex); SoapySDR_logf(SOAPY_SDR_DEBUG,"setGain %s %s, channel %d, gain %d", name.c_str(), direction == SOAPY_SDR_RX ? "RX" : "TX", channel, (int)value); if ( name == "AMP" ) { _current_amp = value; _current_amp = (_current_amp > 0)?HACKRF_AMP_MAX_DB : 0; //clip to possible values if(direction == SOAPY_SDR_RX){ _rx_stream.amp_gain=_current_amp; }else if (direction ==SOAPY_SDR_TX){ _tx_stream.amp_gain=_current_amp; } if( ((direction == SOAPY_SDR_RX) && (_current_mode == HACKRF_TRANSCEIVER_MODE_RX)) || ((direction == SOAPY_SDR_TX) && (_current_mode == HACKRF_TRANSCEIVER_MODE_TX)) ) { if ( _dev != NULL ) { int ret = hackrf_set_amp_enable( _dev, (_current_amp > 0)?1 : 0 ); if ( ret != HACKRF_SUCCESS ) { SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_amp_enable(%f) returned %s", _current_amp, hackrf_error_name( (hackrf_error) ret ) ); } } } }else if ( direction == SOAPY_SDR_RX and name == "LNA" ) { _rx_stream.lna_gain = value; if ( _dev != NULL ) { int ret = hackrf_set_lna_gain( _dev, _rx_stream.lna_gain ); if ( ret != HACKRF_SUCCESS ) { SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_lna_gain(%f) returned %s", _rx_stream.lna_gain, hackrf_error_name( (hackrf_error) ret ) ); } } }else if ( direction == SOAPY_SDR_RX and name == "VGA" ) { _rx_stream.vga_gain = value; if ( _dev != NULL ) { int ret = hackrf_set_vga_gain( _dev, _rx_stream.vga_gain ); if ( ret != HACKRF_SUCCESS ) { SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_vga_gain(%f) returned %s", _rx_stream.vga_gain, hackrf_error_name( (hackrf_error) ret ) ); } } }else if ( direction == SOAPY_SDR_TX and name == "VGA" ) { _tx_stream.vga_gain = value; if ( _dev != NULL ) { int ret = hackrf_set_txvga_gain( _dev, _tx_stream.vga_gain ); if ( ret != HACKRF_SUCCESS ) { SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_txvga_gain(%f) returned %s", _tx_stream.vga_gain, hackrf_error_name( (hackrf_error) ret ) ); } } } /* set individual gain element by name */ } double SoapyHackRF::getGain( const int direction, const size_t channel, const std::string &name ) const { std::lock_guard lock(_device_mutex); double gain = 0.0; if ( direction == SOAPY_SDR_RX and name == "AMP" ) { gain = -_rx_stream.amp_gain; }else if ( direction == SOAPY_SDR_TX and name == "AMP" ) { gain = _tx_stream.amp_gain; }else if ( direction == SOAPY_SDR_RX and name == "LNA" ) { gain = _rx_stream.lna_gain; }else if ( direction == SOAPY_SDR_RX and name == "VGA" ) { gain = _rx_stream.vga_gain; }else if ( direction == SOAPY_SDR_TX and name == "VGA" ) { gain = _tx_stream.vga_gain; } return(gain); } SoapySDR::Range SoapyHackRF::getGainRange( const int direction, const size_t channel, const std::string &name ) const { if ( name == "AMP" ) return(SoapySDR::Range( 0, HACKRF_AMP_MAX_DB ) ); if ( direction == SOAPY_SDR_RX and name == "LNA" ) return(SoapySDR::Range( 0, HACKRF_RX_LNA_MAX_DB ) ); if ( direction == SOAPY_SDR_RX and name == "VGA" ) return(SoapySDR::Range( 0, HACKRF_RX_VGA_MAX_DB ) ); if ( direction == SOAPY_SDR_TX and name == "VGA" ) return(SoapySDR::Range( 0, HACKRF_TX_VGA_MAX_DB ) ); return(SoapySDR::Range( 0, 0 ) ); } /******************************************************************* * Frequency API ******************************************************************/ void SoapyHackRF::setFrequency( const int direction, const size_t channel, const std::string &name, const double frequency, const SoapySDR::Kwargs &args ) { if ( name == "BB" ) return; if ( name != "RF" ) throw std::runtime_error( "setFrequency(" + name + ") unknown name" ); std::lock_guard lock(_device_mutex); _current_frequency = frequency; if(direction==SOAPY_SDR_RX){ _rx_stream.frequency=_current_frequency; } if(direction==SOAPY_SDR_TX){ _tx_stream.frequency=_current_frequency; } if ( _dev != NULL ) { int ret = hackrf_set_freq( _dev, _current_frequency ); if ( ret != HACKRF_SUCCESS ) { SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_freq(%f) returned %s", _current_frequency, hackrf_error_name( (hackrf_error) ret ) ); } } } double SoapyHackRF::getFrequency( const int direction, const size_t channel, const std::string &name ) const { if ( name == "BB" ) return(0.0); if ( name != "RF" ) throw std::runtime_error( "getFrequency(" + name + ") unknown name" ); std::lock_guard lock(_device_mutex); double freq(0.0); if(direction==SOAPY_SDR_RX){ freq = _rx_stream.frequency; } if(direction==SOAPY_SDR_TX){ freq = _tx_stream.frequency; } return(freq); } SoapySDR::ArgInfoList SoapyHackRF::getFrequencyArgsInfo(const int direction, const size_t channel) const { SoapySDR::ArgInfoList freqArgs; // TODO: frequency arguments return freqArgs; } std::vector SoapyHackRF::listFrequencies( const int direction, const size_t channel ) const { std::vector names; names.push_back( "RF" ); return(names); } SoapySDR::RangeList SoapyHackRF::getFrequencyRange( const int direction, const size_t channel, const std::string &name ) const { if ( name == "BB" ) return(SoapySDR::RangeList( 1, SoapySDR::Range( 0.0, 0.0 ) ) ); if ( name != "RF" ) throw std::runtime_error( "getFrequencyRange(" + name + ") unknown name" ); return(SoapySDR::RangeList( 1, SoapySDR::Range( 0, 7250000000ull ) ) ); } /******************************************************************* * Sample Rate API ******************************************************************/ void SoapyHackRF::setSampleRate( const int direction, const size_t channel, const double rate ) { std::lock_guard lock(_device_mutex); _current_samplerate = rate; if(direction==SOAPY_SDR_RX){ _rx_stream.samplerate=_current_samplerate; } if(direction==SOAPY_SDR_TX){ _tx_stream.samplerate=_current_samplerate; } if ( _dev != NULL ) { int ret = hackrf_set_sample_rate( _dev, _current_samplerate ); if(_auto_bandwidth){ _current_bandwidth=hackrf_compute_baseband_filter_bw_round_down_lt(_current_samplerate); if(direction==SOAPY_SDR_RX){ _rx_stream.bandwidth=_current_bandwidth; } if(direction==SOAPY_SDR_TX){ _tx_stream.bandwidth=_current_bandwidth; } ret|=hackrf_set_baseband_filter_bandwidth(_dev,_current_bandwidth); } if ( ret != HACKRF_SUCCESS ) { SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_sample_rate(%f) returned %s", _current_samplerate, hackrf_error_name( (hackrf_error) ret ) ); throw std::runtime_error( "setSampleRate()" ); } } } double SoapyHackRF::getSampleRate( const int direction, const size_t channel ) const { std::lock_guard lock(_device_mutex); double samp(0.0); if(direction==SOAPY_SDR_RX){ samp= _rx_stream.samplerate; } if(direction==SOAPY_SDR_TX){ samp= _tx_stream.samplerate; } return(samp); } std::vector SoapyHackRF::listSampleRates( const int direction, const size_t channel ) const { std::vector options; for ( double r = 1e6; r <= 20e6; r += 1e6 ) { options.push_back( r ); } return(options); } void SoapyHackRF::setBandwidth( const int direction, const size_t channel, const double bw ) { std::lock_guard lock(_device_mutex); _current_bandwidth = hackrf_compute_baseband_filter_bw(bw); if(direction==SOAPY_SDR_RX){ _rx_stream.bandwidth=_current_bandwidth; } if(direction==SOAPY_SDR_TX){ _tx_stream.bandwidth=_current_bandwidth; } if(_current_bandwidth > 0){ _auto_bandwidth=false; if ( _dev != NULL ) { int ret = hackrf_set_baseband_filter_bandwidth( _dev, _current_bandwidth ); if ( ret != HACKRF_SUCCESS ) { SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_baseband_filter_bandwidth(%f) returned %s", _current_bandwidth, hackrf_error_name( (hackrf_error) ret ) ); throw std::runtime_error( "setBandwidth()" ); } } }else{ _auto_bandwidth=true; } } double SoapyHackRF::getBandwidth( const int direction, const size_t channel ) const { std::lock_guard lock(_device_mutex); double bw(0.0); if(direction==SOAPY_SDR_RX){ bw = _rx_stream.bandwidth; } if(direction==SOAPY_SDR_TX){ bw = _tx_stream.bandwidth; } return (bw); } std::vector SoapyHackRF::listBandwidths( const int direction, const size_t channel ) const { std::vector options; options.push_back( 1750000 ); options.push_back( 2500000 ); options.push_back( 3500000 ); options.push_back( 5000000 ); options.push_back( 5500000 ); options.push_back( 6000000 ); options.push_back( 7000000 ); options.push_back( 8000000 ); options.push_back( 9000000 ); options.push_back( 10000000 ); options.push_back( 12000000 ); options.push_back( 14000000 ); options.push_back( 15000000 ); options.push_back( 20000000 ); options.push_back( 24000000 ); options.push_back( 28000000 ); return(options); } SoapyHackRF-soapy-hackrf-0.3.2/HackRF_Streaming.cpp000066400000000000000000000613601320437501200220310ustar00rootroot00000000000000/* * The MIT License (MIT) * * Copyright (c) 2015-2016 Wei Jiang * Copyright (c) 2015-2017 Josh Blum * Copyright (c) 2017 Kevin Mehall * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "SoapyHackRF.hpp" #include #include #include #include #include //min int _hackrf_rx_callback( hackrf_transfer *transfer ) { SoapyHackRF* obj = (SoapyHackRF *) transfer->rx_ctx; return(obj->hackrf_rx_callback( (int8_t *) transfer->buffer, transfer->valid_length ) ); } int _hackrf_tx_callback( hackrf_transfer *transfer ) { SoapyHackRF* obj = (SoapyHackRF *) transfer->tx_ctx; return(obj->hackrf_tx_callback( (int8_t *) transfer->buffer, transfer->valid_length ) ); } int SoapyHackRF::hackrf_rx_callback( int8_t *buffer, int32_t length ) { std::unique_lock lock(_buf_mutex); _rx_stream.buf_tail = (_rx_stream.buf_head + _rx_stream.buf_count) % _rx_stream.buf_num; memcpy(_rx_stream.buf[_rx_stream.buf_tail], buffer, length ); if ( _rx_stream.buf_count == _rx_stream.buf_num ) { _rx_stream.overflow=true; _rx_stream.buf_head = (_rx_stream.buf_head + 1) % _rx_stream.buf_num; }else { _rx_stream.buf_count++; } _buf_cond.notify_one(); return(0); } int SoapyHackRF::hackrf_tx_callback( int8_t *buffer, int32_t length ) { std::unique_lock lock(_buf_mutex); if ( _tx_stream.buf_count == 0 ) { memset( buffer, 0, length ); _tx_stream.underflow=true; }else { memcpy( buffer, _tx_stream.buf[_tx_stream.buf_tail], length ); _tx_stream.buf_tail = (_tx_stream.buf_tail + 1) % _tx_stream.buf_num; _tx_stream.buf_count--; if(_tx_stream.burst_end) { _tx_stream.burst_samps -= (length/BYTES_PER_SAMPLE); if(_tx_stream.burst_samps < 0 ) { _tx_stream.burst_end = false; _tx_stream.burst_samps = 0; return -1; } } } _buf_cond.notify_one(); return(0); } std::vector SoapyHackRF::getStreamFormats(const int direction, const size_t channel) const { std::vector formats; formats.push_back(SOAPY_SDR_CS8); formats.push_back(SOAPY_SDR_CS16); formats.push_back(SOAPY_SDR_CF32); formats.push_back(SOAPY_SDR_CF64); return formats; } std::string SoapyHackRF::getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const { fullScale = 128; return SOAPY_SDR_CS8; } SoapySDR::ArgInfoList SoapyHackRF::getStreamArgsInfo(const int direction, const size_t channel) const { SoapySDR::ArgInfoList streamArgs; SoapySDR::ArgInfo buffersArg; buffersArg.key="buffers"; buffersArg.value = std::to_string(BUF_NUM); buffersArg.name = "Buffer Count"; buffersArg.description = "Number of buffers per read."; buffersArg.units = "buffers"; buffersArg.type = SoapySDR::ArgInfo::INT; streamArgs.push_back(buffersArg); return streamArgs; } void SoapyHackRF::Stream::allocate_buffers() { buf = (int8_t * *) malloc( buf_num * sizeof(int8_t *) ); if ( buf ) { for ( unsigned int i = 0; i < buf_num; ++i ) { buf[i] = (int8_t *) malloc( buf_len ); } } } void SoapyHackRF::Stream::clear_buffers() { if ( buf ) { for ( unsigned int i = 0; i < buf_num; ++i ) { if ( buf[i] ) { free( buf[i] ); } } free( buf ); buf = NULL; } buf_count = 0; buf_tail = 0; buf_head = 0; remainderSamps = 0; remainderOffset = 0; remainderBuff = nullptr; remainderHandle = -1; } SoapySDR::Stream *SoapyHackRF::setupStream( const int direction, const std::string &format, const std::vector &channels, const SoapySDR::Kwargs &args ) { std::lock_guard lock(_device_mutex); if ( channels.size() > 1 or( channels.size() > 0 and channels.at( 0 ) != 0 ) ) { throw std::runtime_error( "setupStream invalid channel selection" ); } if(direction==SOAPY_SDR_RX){ if (_rx_stream.opened) { throw std::runtime_error("RX stream already opened"); } if ( format == SOAPY_SDR_CS8 ) { SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS8." ); _rx_stream.format = HACKRF_FORMAT_INT8; }else if ( format == SOAPY_SDR_CS16 ) { SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS16." ); _rx_stream.format = HACKRF_FORMAT_INT16; }else if ( format == SOAPY_SDR_CF32 ) { SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF32." ); _rx_stream.format= HACKRF_FORMAT_FLOAT32; }else if(format==SOAPY_SDR_CF64){ SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF64." ); _rx_stream.format= HACKRF_FORMAT_FLOAT64; }else throw std::runtime_error( "setupStream invalid format " + format ); _rx_stream.buf_num = BUF_NUM; if ( args.count( "buffers" ) != 0 ) { try { int numBuffers_in = std::stoi(args.at("buffers")); if (numBuffers_in > 0) { _rx_stream.buf_num = numBuffers_in; } } catch (const std::invalid_argument &){} } _rx_stream.allocate_buffers(); _rx_stream.opened = true; return RX_STREAM; } else if(direction==SOAPY_SDR_TX){ if (_tx_stream.opened) { throw std::runtime_error("TX stream already opened"); } if ( format == SOAPY_SDR_CS8 ) { SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS8." ); _tx_stream.format = HACKRF_FORMAT_INT8; }else if ( format == SOAPY_SDR_CS16 ) { SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS16." ); _tx_stream.format = HACKRF_FORMAT_INT16; }else if ( format == SOAPY_SDR_CF32 ) { SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF32." ); _tx_stream.format= HACKRF_FORMAT_FLOAT32; }else if(format==SOAPY_SDR_CF64){ SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF64." ); _tx_stream.format= HACKRF_FORMAT_FLOAT64; }else throw std::runtime_error( "setupStream invalid format " + format ); _tx_stream.buf_num = BUF_NUM; if ( args.count( "buffers" ) != 0 ) { try { int numBuffers_in = std::stoi(args.at("buffers")); if (numBuffers_in > 0) { _tx_stream.buf_num = numBuffers_in; } } catch (const std::invalid_argument &){} } _tx_stream.allocate_buffers(); _tx_stream.opened = true; return TX_STREAM; } else { throw std::runtime_error("Invalid direction"); } } void SoapyHackRF::closeStream( SoapySDR::Stream *stream ) { std::lock_guard lock(_device_mutex); if (stream == RX_STREAM) { _rx_stream.clear_buffers(); _rx_stream.opened = false; } else if (stream == TX_STREAM) { _tx_stream.clear_buffers(); _tx_stream.opened = false; } } size_t SoapyHackRF::getStreamMTU( SoapySDR::Stream *stream ) const { if(stream == RX_STREAM){ return _rx_stream.buf_len/BYTES_PER_SAMPLE; } else if(stream == TX_STREAM){ return _tx_stream.buf_len/BYTES_PER_SAMPLE; } else { throw std::runtime_error("Invalid stream"); } } int SoapyHackRF::activateStream( SoapySDR::Stream *stream, const int flags, const long long timeNs, const size_t numElems ) { if(stream == RX_STREAM){ std::lock_guard lock(_device_mutex); if(_current_mode==HACKRF_TRANSCEIVER_MODE_RX) return 0; if(_current_mode==HACKRF_TRANSCEIVER_MODE_TX){ if(_tx_stream.burst_end){ while(hackrf_is_streaming(_dev)==HACKRF_TRUE) std::this_thread::sleep_for(std::chrono::milliseconds(10)); } hackrf_stop_tx(_dev); // determine what (if any) settings need to be changed for RX; only applicable if there is both a source and sink block // sample_rate if(_current_samplerate != _rx_stream.samplerate) { _current_samplerate = _rx_stream.samplerate; SoapySDR_logf(SOAPY_SDR_DEBUG, "activateStream - Set RX samplerate to %f", _current_samplerate); hackrf_set_sample_rate(_dev,_current_samplerate); } // frequency if(_current_frequency != _rx_stream.frequency) { _current_frequency = _rx_stream.frequency; SoapySDR_logf(SOAPY_SDR_DEBUG, "activateStream - Set RX frequency to %lu", _current_frequency); hackrf_set_freq(_dev,_current_frequency); } // frequency_correction; assume RX and TX use the same correction // This will be the setting of whichever block was last added to the flow graph // RF Gain (RF Amp for TX & RX) if(_current_amp != _rx_stream.amp_gain) { _current_amp = _rx_stream.amp_gain; SoapySDR_logf(SOAPY_SDR_DEBUG, "activateStream - Set RX amp gain to %d", _current_amp); hackrf_set_amp_enable(_dev,(_current_amp > 0)?1 : 0 ); } // IF Gain (LNA for RX; VGA_TX for TX) // BB Gain (VGA for RX; n/a for TX) // These are independant values in the hackrf, so no need to change // Bandwidth if(_current_bandwidth !=_rx_stream.bandwidth) { _current_bandwidth =_rx_stream.bandwidth; SoapySDR_logf(SOAPY_SDR_DEBUG, "activateStream - Set RX bandwidth to %d", _current_bandwidth); hackrf_set_baseband_filter_bandwidth(_dev,_current_bandwidth); } } SoapySDR_logf(SOAPY_SDR_DEBUG, "Start RX"); //reset buffer tracking before streaming { _rx_stream.buf_count = 0; _rx_stream.buf_head = 0; _rx_stream.buf_tail = 0; } int ret = hackrf_start_rx(_dev, _hackrf_rx_callback, (void *) this); if (ret != HACKRF_SUCCESS) { SoapySDR::logf(SOAPY_SDR_ERROR, "hackrf_start_rx() failed -- %s", hackrf_error_name(hackrf_error(ret))); } ret=hackrf_is_streaming(_dev); if (ret==HACKRF_ERROR_STREAMING_EXIT_CALLED){ hackrf_close(_dev); hackrf_open_by_serial(_serial.c_str(), &_dev); _current_frequency=_rx_stream.frequency; hackrf_set_freq(_dev,_current_frequency); _current_samplerate=_rx_stream.samplerate; hackrf_set_sample_rate(_dev,_current_samplerate); _current_bandwidth=_rx_stream.bandwidth; hackrf_set_baseband_filter_bandwidth(_dev,_current_bandwidth); _current_amp=_rx_stream.amp_gain; hackrf_set_amp_enable(_dev,(_current_amp > 0)?1 : 0 ); hackrf_set_lna_gain(_dev,_rx_stream.lna_gain); hackrf_set_vga_gain(_dev,_rx_stream.vga_gain); hackrf_start_rx(_dev,_hackrf_rx_callback,(void *) this); ret=hackrf_is_streaming(_dev); } if(ret!=HACKRF_TRUE){ SoapySDR_logf(SOAPY_SDR_ERROR,"Activate RX Stream Failed."); return SOAPY_SDR_STREAM_ERROR; } _current_mode = HACKRF_TRANSCEIVER_MODE_RX; } else if (stream == TX_STREAM) { std::lock_guard lock(_device_mutex); if((flags & SOAPY_SDR_END_BURST)!=0 and numElems!=0) { if(_current_mode==HACKRF_TRANSCEIVER_MODE_RX){ _tx_stream.buf_head=0; _tx_stream.buf_tail=0; _tx_stream.burst_end = true; _tx_stream.burst_samps = numElems; } } if(_current_mode==HACKRF_TRANSCEIVER_MODE_TX) return 0; if(_current_mode==HACKRF_TRANSCEIVER_MODE_RX){ hackrf_stop_rx(_dev); // determine what (if any) settings need to be changed for TX; only applicable if there is both a source and sink block // sample_rate if(_current_samplerate != _tx_stream.samplerate) { _current_samplerate=_tx_stream.samplerate; SoapySDR_logf(SOAPY_SDR_DEBUG, "activateStream - Set TX samplerate to %f", _current_samplerate); hackrf_set_sample_rate(_dev,_current_samplerate); } // frequency if(_current_frequency != _tx_stream.frequency) { _current_frequency=_tx_stream.frequency; SoapySDR_logf(SOAPY_SDR_DEBUG, "activateStream - Set TX frequency to %lu", _current_frequency); hackrf_set_freq(_dev,_current_frequency); } // frequency_correction; assume RX and TX use the same correction // This will be the setting of whichever block was last added to the flow graph // RF Gain (RF Amp for TX & RX) if(_current_amp != _tx_stream.amp_gain) { _current_amp=_tx_stream.amp_gain; SoapySDR_logf(SOAPY_SDR_DEBUG, "activateStream - Set TX amp gain to %d", _current_amp); hackrf_set_amp_enable(_dev,(_current_amp > 0)?1 : 0 ); } // IF Gain (LNA for RX, VGA_TX for TX) // BB Gain (VGA for RX, n/a for TX) // These are independant values in the hackrf, so no need to change // Bandwidth if(_current_bandwidth !=_tx_stream.bandwidth) { _current_bandwidth =_tx_stream.bandwidth; SoapySDR_logf(SOAPY_SDR_DEBUG, "activateStream - Set RX bandwidth to %d", _current_bandwidth); hackrf_set_baseband_filter_bandwidth(_dev,_current_bandwidth); } } SoapySDR_logf( SOAPY_SDR_DEBUG, "Start TX" ); int ret = hackrf_start_tx( _dev, _hackrf_tx_callback, (void *) this ); if (ret != HACKRF_SUCCESS) { SoapySDR::logf(SOAPY_SDR_ERROR, "hackrf_start_tx() failed -- %s", hackrf_error_name(hackrf_error(ret))); } ret=hackrf_is_streaming(_dev); if (ret==HACKRF_ERROR_STREAMING_EXIT_CALLED){ hackrf_close(_dev); hackrf_open_by_serial(_serial.c_str(), &_dev); _current_frequency=_tx_stream.frequency; hackrf_set_freq(_dev,_current_frequency); _current_samplerate=_tx_stream.samplerate; hackrf_set_sample_rate(_dev,_current_samplerate); _current_bandwidth=_tx_stream.bandwidth; hackrf_set_baseband_filter_bandwidth(_dev,_current_bandwidth); _current_amp=_rx_stream.amp_gain; hackrf_set_amp_enable(_dev,(_current_amp > 0)?1 : 0 ); hackrf_set_txvga_gain(_dev,_tx_stream.vga_gain); hackrf_set_antenna_enable(_dev,_tx_stream.bias); hackrf_start_tx(_dev,_hackrf_tx_callback,(void *) this); ret=hackrf_is_streaming(_dev); } if(ret!=HACKRF_TRUE){ SoapySDR_logf(SOAPY_SDR_ERROR,"Activate TX Stream Failed."); return SOAPY_SDR_STREAM_ERROR; } _current_mode = HACKRF_TRANSCEIVER_MODE_TX; } return(0); } int SoapyHackRF::deactivateStream( SoapySDR::Stream *stream, const int flags, const long long timeNs ) { if(stream == RX_STREAM){ std::lock_guard lock(_device_mutex); if(_current_mode==HACKRF_TRANSCEIVER_MODE_RX) { int ret = hackrf_stop_rx(_dev); if (ret != HACKRF_SUCCESS) { SoapySDR::logf(SOAPY_SDR_ERROR, "hackrf_stop_rx() failed -- %s", hackrf_error_name(hackrf_error(ret))); } _current_mode = HACKRF_TRANSCEIVER_MODE_OFF; } } else if(stream == TX_STREAM) { std::lock_guard lock(_device_mutex); if(_current_mode==HACKRF_TRANSCEIVER_MODE_TX) { int ret = hackrf_stop_tx(_dev); if (ret != HACKRF_SUCCESS) { SoapySDR::logf(SOAPY_SDR_ERROR, "hackrf_stop_tx() failed -- %s", hackrf_error_name(hackrf_error(ret))); } _current_mode = HACKRF_TRANSCEIVER_MODE_OFF; } } return(0); } void readbuf(int8_t * src, void * dst, uint32_t len,uint32_t format,size_t offset){ if(format==HACKRF_FORMAT_INT8){ int8_t *samples_cs8=(int8_t *) dst+offset*BYTES_PER_SAMPLE; for (uint32_t i=0;i> 8); dst[i*BYTES_PER_SAMPLE+1] = (int8_t) (samples_cs16[i*BYTES_PER_SAMPLE+1] >> 8); } }else if(format==HACKRF_FORMAT_FLOAT32){ float *samples_cf32=(float *) src+offset*BYTES_PER_SAMPLE; for (uint32_t i=0;igetStreamMTU(stream)); size_t samp_avail=0; if(_rx_stream.remainderHandle >= 0){ const size_t n =std::min(_rx_stream.remainderSamps,returnedElems); if(nreleaseReadBuffer(stream,_rx_stream.remainderHandle); _rx_stream.remainderHandle=-1; _rx_stream.remainderOffset=0; } if(n==returnedElems) return returnedElems; } size_t handle; int ret = this->acquireReadBuffer(stream, handle, (const void **)&_rx_stream.remainderBuff, flags, timeNs, timeoutUs); if (ret < 0) return ret; _rx_stream.remainderHandle=handle; _rx_stream.remainderSamps=ret; const size_t n =std::min((returnedElems-samp_avail),_rx_stream.remainderSamps); readbuf(_rx_stream.remainderBuff,buffs[0],n,_rx_stream.format,samp_avail); _rx_stream.remainderSamps -=n; _rx_stream.remainderOffset +=n; if(_rx_stream.remainderSamps==0){ this->releaseReadBuffer(stream,_rx_stream.remainderHandle); _rx_stream.remainderHandle=-1; _rx_stream.remainderOffset=0; } return(returnedElems); } int SoapyHackRF::writeStream( SoapySDR::Stream *stream, const void * const *buffs, const size_t numElems, int &flags, const long long timeNs, const long timeoutUs ) { if(stream != TX_STREAM){ return SOAPY_SDR_NOT_SUPPORTED; } size_t returnedElems = std::min(numElems,this->getStreamMTU(stream)); size_t samp_avail = 0; if(_tx_stream.remainderHandle>=0){ const size_t n =std::min(_tx_stream.remainderSamps,returnedElems); if(nreleaseWriteBuffer(stream,_tx_stream.remainderHandle,_tx_stream.remainderOffset,flags,timeNs); _tx_stream.remainderHandle=-1; _tx_stream.remainderOffset=0; } if(n==returnedElems) return returnedElems; } size_t handle; int ret=this->acquireWriteBuffer(stream,handle,(void **)&_tx_stream.remainderBuff,timeoutUs); if (ret<0)return ret; _tx_stream.remainderHandle=handle; _tx_stream.remainderSamps=ret; const size_t n =std::min((returnedElems-samp_avail),_tx_stream.remainderSamps); writebuf(buffs[0],_tx_stream.remainderBuff,n,_tx_stream.format,samp_avail); _tx_stream.remainderSamps -=n; _tx_stream.remainderOffset +=n; if(_tx_stream.remainderSamps==0){ this->releaseWriteBuffer(stream,_tx_stream.remainderHandle,_tx_stream.remainderOffset,flags,timeNs); _tx_stream.remainderHandle=-1; _tx_stream.remainderOffset=0; } return returnedElems; } int SoapyHackRF::readStreamStatus( SoapySDR::Stream *stream, size_t &chanMask, int &flags, long long &timeNs, const long timeoutUs ){ if(stream != TX_STREAM){ return SOAPY_SDR_NOT_SUPPORTED; } //calculate when the loop should exit const auto timeout = std::chrono::duration_cast(std::chrono::microseconds(timeoutUs)); const auto exitTime = std::chrono::high_resolution_clock::now() + timeout; //poll for status events until the timeout expires while (true) { if(_tx_stream.underflow){ _tx_stream.underflow=false; SoapySDR::log(SOAPY_SDR_SSI, "U"); return SOAPY_SDR_UNDERFLOW; } //sleep for a fraction of the total timeout const auto sleepTimeUs = std::min(1000, timeoutUs/10); std::this_thread::sleep_for(std::chrono::microseconds(sleepTimeUs)); //check for timeout expired const auto timeNow = std::chrono::high_resolution_clock::now(); if (exitTime < timeNow) return SOAPY_SDR_TIMEOUT; } } int SoapyHackRF::acquireReadBuffer( SoapySDR::Stream *stream, size_t &handle, const void **buffs, int &flags, long long &timeNs, const long timeoutUs) { if(stream != RX_STREAM){ return SOAPY_SDR_NOT_SUPPORTED; } if ( _current_mode!=HACKRF_TRANSCEIVER_MODE_RX ) { //wait for tx to be consumed before switching { std::unique_lock lock( _buf_mutex ); if (not _buf_cond.wait_for(lock, std::chrono::microseconds(timeoutUs), [this]{return this->_tx_stream.buf_count == 0;})) return SOAPY_SDR_TIMEOUT; } int ret=this->activateStream(stream); if(ret<0) return ret; } std::unique_lock lock( _buf_mutex ); while (_rx_stream.buf_count == 0) { _buf_cond.wait_for(lock, std::chrono::microseconds(timeoutUs)); if (_rx_stream.buf_count == 0) return SOAPY_SDR_TIMEOUT; } if(_rx_stream.overflow) { flags|=SOAPY_SDR_END_ABRUPT; _rx_stream.overflow=false; SoapySDR::log(SOAPY_SDR_SSI,"O"); return SOAPY_SDR_OVERFLOW; } handle=_rx_stream.buf_head; _rx_stream.buf_head = (_rx_stream.buf_head + 1) % _rx_stream.buf_num; this->getDirectAccessBufferAddrs(stream,handle,(void **)buffs); return this->getStreamMTU(stream); } void SoapyHackRF::releaseReadBuffer( SoapySDR::Stream *stream, const size_t handle) { if(stream != RX_STREAM){ throw std::runtime_error("Invalid stream"); } std::unique_lock lock( _buf_mutex ); _rx_stream.buf_count--; } int SoapyHackRF::acquireWriteBuffer( SoapySDR::Stream *stream, size_t &handle, void **buffs, const long timeoutUs) { if(stream != TX_STREAM){ return SOAPY_SDR_NOT_SUPPORTED; } if(_current_mode!=HACKRF_TRANSCEIVER_MODE_TX) { int ret=this->activateStream(stream); if(ret<0) return ret; } std::unique_lock lock( _buf_mutex ); while ( _tx_stream.buf_count == _tx_stream.buf_num ) { _buf_cond.wait_for(lock, std::chrono::microseconds(timeoutUs)); if (_tx_stream.buf_count == _tx_stream.buf_num) return SOAPY_SDR_TIMEOUT; } handle=_tx_stream.buf_head; _tx_stream.buf_head = (_tx_stream.buf_head + 1) % _tx_stream.buf_num; this->getDirectAccessBufferAddrs(stream,handle,buffs); if(_tx_stream.burst_end){ if((_tx_stream.burst_samps - int32_t(this->getStreamMTU(stream))) < 0){ memset(buffs[0],0,this->getStreamMTU(stream)); return _tx_stream.burst_samps; } } return this->getStreamMTU(stream); } void SoapyHackRF::releaseWriteBuffer( SoapySDR::Stream *stream, const size_t handle, const size_t numElems, int &flags, const long long timeNs) { if (stream == TX_STREAM) { std::unique_lock lock( _buf_mutex ); _tx_stream.buf_count++; } else { throw std::runtime_error("Invalid stream"); } } size_t SoapyHackRF::getNumDirectAccessBuffers( SoapySDR::Stream *stream) { if (stream == RX_STREAM) { return _rx_stream.buf_num; } else if(stream == TX_STREAM){ return _tx_stream.buf_num; } else { throw std::runtime_error("Invalid stream"); } } int SoapyHackRF::getDirectAccessBufferAddrs( SoapySDR::Stream *stream, const size_t handle, void **buffs) { if (stream == RX_STREAM) { buffs[0]=(void *)_rx_stream.buf[handle]; } else if (stream == TX_STREAM) { buffs[0]=(void *)_tx_stream.buf[handle]; } else { throw std::runtime_error("Invalid stream"); } return 0; } SoapyHackRF-soapy-hackrf-0.3.2/LICENSE000066400000000000000000000020541320437501200172160ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SoapyHackRF-soapy-hackrf-0.3.2/README.md000066400000000000000000000027141320437501200174730ustar00rootroot00000000000000# Soapy SDR module for Hack RF ## Build Status - Travis: [![Travis Build Status](https://travis-ci.org/pothosware/SoapyHackRF.svg?branch=master)](https://travis-ci.org/pothosware/SoapyHackRF) ## Dependencies * SoapySDR - https://github.com/pothosware/SoapySDR/wiki * libhackrf - https://github.com/mossmann/hackrf/wiki ## Documentation * https://github.com/pothosware/SoapyHackRF/wiki ## Licensing information The MIT License (MIT) Copyright (c) 2015 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SoapyHackRF-soapy-hackrf-0.3.2/SoapyHackRF.hpp000066400000000000000000000240771320437501200210450ustar00rootroot00000000000000/* * The MIT License (MIT) * * Copyright (c) 2015 Wei Jiang * Copyright (c) 2015-2017 Josh Blum * Copyright (c) 2017 Kevin Mehall * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #pragma once #include #include #include #include #include #include #include #define BUF_LEN 262144 #define BUF_NUM 15 #define BYTES_PER_SAMPLE 2 #define HACKRF_RX_VGA_MAX_DB 62 #define HACKRF_TX_VGA_MAX_DB 47 #define HACKRF_RX_LNA_MAX_DB 40 #define HACKRF_AMP_MAX_DB 14 enum HackRF_Format { HACKRF_FORMAT_FLOAT32 =0, HACKRF_FORMAT_INT16 =1, HACKRF_FORMAT_INT8 =2, HACKRF_FORMAT_FLOAT64 =3, }; typedef enum { HACKRF_TRANSCEIVER_MODE_OFF = 0, HACKRF_TRANSCEIVER_MODE_RX = 1, HACKRF_TRANSCEIVER_MODE_TX = 2, } HackRF_transceiver_mode_t; std::set &HackRF_getClaimedSerials(void); /*! * The session object manages hackrf_init/exit * with a process-wide reference count. */ class SoapyHackRFSession { public: SoapyHackRFSession(void); ~SoapyHackRFSession(void); }; class SoapyHackRF : public SoapySDR::Device { public: SoapyHackRF( const SoapySDR::Kwargs & args ); ~SoapyHackRF( void ); /******************************************************************* * Identification API ******************************************************************/ std::string getDriverKey( void ) const; std::string getHardwareKey( void ) const; SoapySDR::Kwargs getHardwareInfo( void ) const; /******************************************************************* * Channels API ******************************************************************/ size_t getNumChannels( const int ) const; bool getFullDuplex( const int direction, const size_t channel ) const; /******************************************************************* * Stream API ******************************************************************/ std::vector getStreamFormats(const int direction, const size_t channel) const; std::string getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const; SoapySDR::ArgInfoList getStreamArgsInfo(const int direction, const size_t channel) const; SoapySDR::Stream *setupStream( const int direction, const std::string &format, const std::vector &channels = std::vector(), const SoapySDR::Kwargs &args = SoapySDR::Kwargs() ); void closeStream( SoapySDR::Stream *stream ); size_t getStreamMTU( SoapySDR::Stream *stream ) const; int activateStream( SoapySDR::Stream *stream, const int flags = 0, const long long timeNs = 0, const size_t numElems = 0 ); int deactivateStream( SoapySDR::Stream *stream, const int flags = 0, const long long timeNs = 0 ); int readStream( SoapySDR::Stream *stream, void * const *buffs, const size_t numElems, int &flags, long long &timeNs, const long timeoutUs = 100000 ); int writeStream( SoapySDR::Stream *stream, const void * const *buffs, const size_t numElems, int &flags, const long long timeNs = 0, const long timeoutUs = 100000); int readStreamStatus( SoapySDR::Stream *stream, size_t &chanMask, int &flags, long long &timeNs, const long timeoutUs ); int acquireReadBuffer( SoapySDR::Stream *stream, size_t &handle, const void **buffs, int &flags, long long &timeNs, const long timeoutUs = 100000); void releaseReadBuffer( SoapySDR::Stream *stream, const size_t handle); int acquireWriteBuffer( SoapySDR::Stream *stream, size_t &handle, void **buffs, const long timeoutUs = 100000); void releaseWriteBuffer( SoapySDR::Stream *stream, const size_t handle, const size_t numElems, int &flags, const long long timeNs = 0); size_t getNumDirectAccessBuffers(SoapySDR::Stream *stream); int getDirectAccessBufferAddrs(SoapySDR::Stream *stream, const size_t handle, void **buffs); /******************************************************************* * Settings API ******************************************************************/ SoapySDR::ArgInfoList getSettingInfo(void) const; void writeSetting(const std::string &key, const std::string &value); std::string readSetting(const std::string &key) const; /******************************************************************* * Antenna API ******************************************************************/ std::vector listAntennas( const int direction, const size_t channel ) const; void setAntenna( const int direction, const size_t channel, const std::string &name ); std::string getAntenna( const int direction, const size_t channel ) const; /******************************************************************* * Frontend corrections API ******************************************************************/ bool hasDCOffsetMode( const int direction, const size_t channel ) const; /******************************************************************* * Gain API ******************************************************************/ std::vector listGains( const int direction, const size_t channel ) const; void setGainMode( const int direction, const size_t channel, const bool automatic ); bool getGainMode( const int direction, const size_t channel ) const; void setGain( const int direction, const size_t channel, const double value ); void setGain( const int direction, const size_t channel, const std::string &name, const double value ); double getGain( const int direction, const size_t channel, const std::string &name ) const; SoapySDR::Range getGainRange( const int direction, const size_t channel, const std::string &name ) const; /******************************************************************* * Frequency API ******************************************************************/ void setFrequency( const int direction, const size_t channel, const std::string &name, const double frequency, const SoapySDR::Kwargs &args = SoapySDR::Kwargs() ); double getFrequency( const int direction, const size_t channel, const std::string &name ) const; SoapySDR::ArgInfoList getFrequencyArgsInfo(const int direction, const size_t channel) const; std::vector listFrequencies( const int direction, const size_t channel ) const; SoapySDR::RangeList getFrequencyRange( const int direction, const size_t channel, const std::string &name ) const; /******************************************************************* * Sample Rate API ******************************************************************/ void setSampleRate( const int direction, const size_t channel, const double rate ); double getSampleRate( const int direction, const size_t channel ) const; std::vector listSampleRates( const int direction, const size_t channel ) const; void setBandwidth( const int direction, const size_t channel, const double bw ); double getBandwidth( const int direction, const size_t channel ) const; std::vector listBandwidths( const int direction, const size_t channel ) const; /******************************************************************* * HackRF callback ******************************************************************/ int hackrf_tx_callback( int8_t *buffer, int32_t length ); int hackrf_rx_callback( int8_t *buffer, int32_t length ); private: SoapySDR::Stream* const TX_STREAM = (SoapySDR::Stream*) 0x1; SoapySDR::Stream* const RX_STREAM = (SoapySDR::Stream*) 0x2; struct Stream { Stream(): opened(false), buf_num(BUF_NUM), buf_len(BUF_LEN), buf(nullptr), buf_head(0), buf_tail(0), buf_count(0), remainderHandle(-1), remainderSamps(0), remainderOffset(0), remainderBuff(nullptr), format(HACKRF_FORMAT_INT8) {} bool opened; uint32_t buf_num; uint32_t buf_len; int8_t **buf; uint32_t buf_head; uint32_t buf_tail; uint32_t buf_count; int32_t remainderHandle; size_t remainderSamps; size_t remainderOffset; int8_t* remainderBuff; uint32_t format; ~Stream() { clear_buffers(); } void clear_buffers(); void allocate_buffers(); }; struct RXStream: Stream { uint32_t vga_gain; uint32_t lna_gain; uint8_t amp_gain; double samplerate; uint32_t bandwidth; uint64_t frequency; bool overflow; }; struct TXStream: Stream { uint32_t vga_gain; uint8_t amp_gain; double samplerate; uint32_t bandwidth; uint64_t frequency; bool bias; bool underflow; bool burst_end; int32_t burst_samps; } ; RXStream _rx_stream; TXStream _tx_stream; bool _auto_bandwidth; hackrf_device * _dev; std::string _serial; uint64_t _current_frequency; double _current_samplerate; uint32_t _current_bandwidth; uint8_t _current_amp; /// Mutex protecting all use of the hackrf device _dev and other instance variables. /// Most of the hackrf API is thread-safe because it only calls libusb, however /// the activateStream() method in this library can close and re-open the device, /// so all use of _dev must be protected mutable std::mutex _device_mutex; std::mutex _buf_mutex; std::condition_variable _buf_cond; HackRF_transceiver_mode_t _current_mode; SoapyHackRFSession _sess; }; SoapyHackRF-soapy-hackrf-0.3.2/debian/000077500000000000000000000000001320437501200174325ustar00rootroot00000000000000SoapyHackRF-soapy-hackrf-0.3.2/debian/changelog000066400000000000000000000017741320437501200213150ustar00rootroot00000000000000soapyhackrf (0.3.2-1) unstable; urgency=low * Release 0.3.2 (2017-11-19) -- Josh Blum Sun, 19 Nov 2017 15:39:14 -0000 soapyhackrf (0.3.1-1) unstable; urgency=low * Release 0.3.1 (2017-06-19) -- Josh Blum Mon, 19 Jun 2017 20:18:21 -0000 soapyhackrf (0.3.0-1) unstable; urgency=low * Release 0.3.0 (2017-04-29) -- Josh Blum Sat, 29 Apr 2017 15:04:55 -0000 soapyhackrf (0.2.2) unstable; urgency=low * Release 0.2.2 (2016-10-19) -- Josh Blum Wed, 19 Oct 2016 11:25:17 -0700 soapyhackrf (0.2.1) unstable; urgency=low * Release 0.2.1 (2016-02-29) -- Josh Blum Mon, 29 Feb 2016 13:19:38 -0800 soapyhackrf (0.2.0) unstable; urgency=low * Release 0.2.0 (2015-11-20) -- Josh Blum Fri, 23 Oct 2015 18:39:30 -0700 soapyhackrf (0.1.0) unstable; urgency=low * Release 0.1.0 (2015-10-10) -- Josh Blum Sat, 10 Oct 2015 11:34:51 -0700 SoapyHackRF-soapy-hackrf-0.3.2/debian/compat000066400000000000000000000000021320437501200206300ustar00rootroot000000000000009 SoapyHackRF-soapy-hackrf-0.3.2/debian/control000066400000000000000000000017731320437501200210450ustar00rootroot00000000000000Source: soapyhackrf Section: libs Priority: optional Maintainer: jocover Uploaders: Josh Blum Build-Depends: debhelper (>= 9.0.0), cmake, libhackrf-dev, libsoapysdr-dev Standards-Version: 3.9.8 Homepage: https://github.com/pothosware/SoapyHackRF/wiki Vcs-Git: https://github.com/pothosware/SoapyHackRF.git Vcs-Browser: https://github.com/pothosware/SoapyHackRF Package: soapysdr0.6-module-hackrf Architecture: any Multi-Arch: same Depends: ${shlibs:Depends}, ${misc:Depends} Description: Soapy HackRF - HackRF device support for Soapy SDR. A Soapy module that supports HackRF devices within the Soapy API. Package: soapysdr-module-hackrf Architecture: all Depends: soapysdr0.6-module-hackrf, ${misc:Depends} Description: Soapy HackRF - HackRF device support for Soapy SDR. A Soapy module that supports HackRF devices within the Soapy API. . This is an empty dependency package that pulls in the HackRF module for the default version of libsoapysdr. SoapyHackRF-soapy-hackrf-0.3.2/debian/copyright000066400000000000000000000025001320437501200213620ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: soapyhackrf Source: https://github.com/pothosware/SoapyHackRF/wiki Files: * Copyright: Copyright (c) 2015-2016 Wei Jiang Copyright (c) 2015-2017 Josh Blum Copyright (c) 2017 Kevin Mehall License: MIT Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: . The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. . THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SoapyHackRF-soapy-hackrf-0.3.2/debian/docs000066400000000000000000000000121320437501200202760ustar00rootroot00000000000000README.md SoapyHackRF-soapy-hackrf-0.3.2/debian/rules000077500000000000000000000006161320437501200205150ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) export DEB_HOST_MULTIARCH # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 %: dh $@ --buildsystem=cmake --parallel override_dh_auto_configure: dh_auto_configure -- -DLIB_SUFFIX="/$(DEB_HOST_MULTIARCH)" override_dh_installchangelogs: dh_installchangelogs Changelog.txt SoapyHackRF-soapy-hackrf-0.3.2/debian/soapysdr0.6-module-hackrf.install000066400000000000000000000000121320437501200256220ustar00rootroot00000000000000usr/lib/* SoapyHackRF-soapy-hackrf-0.3.2/debian/source/000077500000000000000000000000001320437501200207325ustar00rootroot00000000000000SoapyHackRF-soapy-hackrf-0.3.2/debian/source/format000066400000000000000000000000141320437501200221400ustar00rootroot000000000000003.0 (quilt) SoapyHackRF-soapy-hackrf-0.3.2/self_test.py000066400000000000000000000056221320437501200205570ustar00rootroot00000000000000import SoapySDR from SoapySDR import * #SOAPY_SDR_* constants import numpy as np import time if __name__ == "__main__": hackrf = SoapySDR.Device(dict(driver="hackrf")) print hackrf hackrf.setSampleRate(SOAPY_SDR_RX, 0, 8e6) hackrf.setSampleRate(SOAPY_SDR_TX, 0, 8e6) """ for i in range(5): print(" Make rx stream #%d"%i) rxStream = hackrf.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32, [0]) for j in range(5): numSampsTotal = 10000 print(" Activate, get %d samples, Deactivate #%d"%(numSampsTotal, j)) hackrf.activateStream(rxStream) buff = np.array([0]*1024, np.complex64) while numSampsTotal > 0: sr = hackrf.readStream(rxStream, [buff], buff.size, timeoutUs=int(1e6)) #print sr assert(sr.ret > 0) numSampsTotal -= sr.ret hackrf.deactivateStream(rxStream) hackrf.closeStream(rxStream) for i in range(5): print(" Make tx stream #%d"%i) txStream = hackrf.setupStream(SOAPY_SDR_TX, SOAPY_SDR_CF32, [0]) for j in range(5): numSampsTotal = 10000 print(" Activate, send %d samples, Deactivate #%d"%(numSampsTotal, j)) hackrf.activateStream(txStream) buff = np.array([0]*1024, np.complex64) while numSampsTotal != 0: size = min(buff.size, numSampsTotal) sr = hackrf.writeStream(txStream, [buff], size) #print sr if not (sr.ret > 0): print("Fail %s, %d"%(sr, numSampsTotal)) assert(sr.ret > 0) numSampsTotal -= sr.ret hackrf.deactivateStream(txStream) hackrf.closeStream(txStream) """ #################################################################### #setup both streams at once #################################################################### rxStream = hackrf.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32, [0]) txStream = hackrf.setupStream(SOAPY_SDR_TX, SOAPY_SDR_CF32, [0]) hackrf.activateStream(rxStream) hackrf.activateStream(txStream) numSampsTotal = 10000 hackrf.activateStream(rxStream) buff = np.array([0]*1024, np.complex64) while numSampsTotal > 0: sr = hackrf.readStream(rxStream, [buff], buff.size, timeoutUs=int(1e6)) #print sr assert(sr.ret > 0) numSampsTotal -= sr.ret numSampsTotal = 10000 buff = np.array([0]*1024, np.complex64) while numSampsTotal != 0: size = min(buff.size, numSampsTotal) sr = hackrf.writeStream(txStream, [buff], size) #print sr if not (sr.ret > 0): print("Fail %s, %d"%(sr, numSampsTotal)) assert(sr.ret > 0) numSampsTotal -= sr.ret hackrf.deactivateStream(rxStream) hackrf.deactivateStream(txStream) hackrf.closeStream(rxStream) hackrf.closeStream(txStream)