mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2026-10-19 14:02:37 +00:00
Merge branch 'MrCry0-feat/support-bladerf' into next
This commit is contained in:
@@ -71,6 +71,7 @@ Marcus Alagar mvala079@gmail.com Contributor
|
||||
Mathieu Favreau favreau.mathieu@hotmail.com Contributor
|
||||
Miguel Gómez López mgomezl@ing.uc3m.es Contributor
|
||||
Minhaj Uddin Ahmad mahmad12@crimson.ua.edu Contributor
|
||||
Oleksandr Suvorov github@say.od.ua Contributor
|
||||
Pedro Pereira pereirapedrocp@gmail.com Contributor
|
||||
Piyush Gupta piyush04111999@gmail.com Contributor
|
||||
Rodrigo Muñoz rodrigo.munoz@proteinlab.cl Contributor
|
||||
|
||||
@@ -137,6 +137,10 @@ authors:
|
||||
email: wsilberm@google.com
|
||||
family-names: Silberman
|
||||
given-names: Will
|
||||
- alias: MrCry0
|
||||
email: github@say.od.ua
|
||||
family-names: Suvorov
|
||||
given-names: Oleksandr
|
||||
- email: tonetto.dev@gmail.com
|
||||
family-names: Tonetto
|
||||
given-names: Leonardo
|
||||
|
||||
@@ -71,6 +71,8 @@ option(ENABLE_OSMOSDR "Enable the use of OsmoSDR and other front-ends (RTL-based
|
||||
|
||||
option(ENABLE_LIMESDR "Enable the use of LimeSDR and Custom LimeSDR as signal source" OFF)
|
||||
|
||||
option(ENABLE_BLADERF "Enable the use of bladeRF front-ends as signal source, requires libbladeRF" OFF)
|
||||
|
||||
option(ENABLE_POCKETSDR "Enable the use of Pocket SDR FE front-ends as signal source, requires gr-pocketsdr" OFF)
|
||||
|
||||
option(ENABLE_FMCOMMS2 "Enable the use of FMCOMMS4-EBZ + ZedBoard hardware, requires gr-iio" OFF)
|
||||
@@ -387,6 +389,7 @@ set(GNSSSDR_CLANG_MIN_VERSION "3.4.0")
|
||||
set(GNSSSDR_GCC_MIN_VERSION "4.7.2")
|
||||
set(GNSSSDR_GFLAGS_MIN_VERSION "2.1.2")
|
||||
set(GNSSSDR_GNURADIO_MIN_VERSION "3.7.3")
|
||||
set(GNSSSDR_LIBBLADERF_MIN_VERSION "2.6.0")
|
||||
set(GNSSSDR_MAKO_MIN_VERSION "0.4.2")
|
||||
set(GNSSSDR_MATIO_MIN_VERSION "1.5.3")
|
||||
set(GNSSSDR_PROTOBUF_MIN_VERSION "3.0.0")
|
||||
@@ -2893,6 +2896,34 @@ endif()
|
||||
|
||||
|
||||
|
||||
##########################################
|
||||
# libbladeRF - OPTIONAL
|
||||
# https://github.com/Nuand/bladeRF
|
||||
##########################################
|
||||
find_package(LIBBLADERF)
|
||||
set_package_properties(LIBBLADERF PROPERTIES
|
||||
PURPOSE "Used for communication with bladeRF front-ends."
|
||||
TYPE OPTIONAL
|
||||
)
|
||||
if(ENABLE_BLADERF)
|
||||
if(LIBBLADERF_FOUND)
|
||||
message(STATUS "The driver for bladeRF will be compiled.")
|
||||
message(STATUS " You can disable it with 'cmake -DENABLE_BLADERF=OFF ..'")
|
||||
else()
|
||||
if(ENABLE_PACKAGING)
|
||||
message(WARNING "libbladeRF has not been found. Source blocks depending on it will NOT be built.")
|
||||
else()
|
||||
message(FATAL_ERROR "libbladeRF required to build gnss-sdr with the optional BLADERF driver")
|
||||
endif()
|
||||
set(ENABLE_BLADERF OFF)
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "The (optional) driver for bladeRF is not enabled.")
|
||||
message(STATUS " Enable it with 'cmake -DENABLE_BLADERF=ON ..' to add support for bladeRF.")
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
################################################
|
||||
# gr-pocketsdr - OPTIONAL
|
||||
# https://github.com/minhaj6/gr-pocketsdr
|
||||
@@ -3371,6 +3402,7 @@ add_subdirectory(utils)
|
||||
add_feature_info(ENABLE_UHD ENABLE_UHD "Enables UHD_Signal_Source for using RF front-ends from the USRP family. Requires gr-uhd.")
|
||||
add_feature_info(ENABLE_OSMOSDR ENABLE_OSMOSDR "Enables Osmosdr_Signal_Source and RtlTcp_Signal_Source for using RF front-ends compatible with the OsmoSDR driver. Requires gr-osmosdr.")
|
||||
add_feature_info(ENABLE_LIMESDR ENABLE_LIMESDR "Enables Limesdr_Signal_Source. Requires gr-limesdr.")
|
||||
add_feature_info(ENABLE_BLADERF ENABLE_BLADERF "Enables Bladerf_Signal_Source. Requires libbladeRF.")
|
||||
add_feature_info(ENABLE_POCKETSDR ENABLE_POCKETSDR "Enables Pocket_SDR_Signal_Source. Requires gr-pocketsdr.")
|
||||
add_feature_info(ENABLE_FMCOMMS2 ENABLE_FMCOMMS2 "Enables Fmcomms2_Signal_Source for FMCOMMS2/3/4 devices. Requires libiio, libad9361-dev, and gr-iio.")
|
||||
add_feature_info(ENABLE_PLUTOSDR ENABLE_PLUTOSDR "Enables Plutosdr_Signal_Source and Ad936x_Custom_Signal_Source for using ADALM-PLUTO boards. Requires libiio, libad9361-dev, and gr-iio.")
|
||||
|
||||
@@ -171,7 +171,7 @@ dependencies with:
|
||||
|
||||
```
|
||||
$ sudo apt install build-essential cmake git gnuradio-dev gr-limesdr gr-osmosdr \
|
||||
libabsl-dev libad9361-dev libarmadillo-dev libblas-dev \
|
||||
libabsl-dev libad9361-dev libarmadillo-dev libbladerf-dev libblas-dev \
|
||||
libboost-chrono-dev libboost-date-time-dev libboost-dev \
|
||||
libboost-filesystem-dev libboost-serialization-dev libboost-thread-dev \
|
||||
libcpu-features-dev libgtest-dev libiio-dev liblapack-dev libmatio-dev \
|
||||
@@ -183,7 +183,7 @@ On older versions:
|
||||
|
||||
```
|
||||
$ sudo apt install build-essential cmake git gnuradio-dev gr-limesdr gr-osmosdr \
|
||||
libad9361-dev libarmadillo-dev libblas-dev \
|
||||
libad9361-dev libarmadillo-dev libbladerf-dev libblas-dev \
|
||||
libboost-chrono-dev libboost-date-time-dev libboost-dev \
|
||||
libboost-filesystem-dev libboost-serialization-dev libboost-system-dev \
|
||||
libboost-thread-dev \
|
||||
@@ -609,6 +609,36 @@ $ sudo cmake --install build
|
||||
(in order to disable the `Osmosdr_Signal_Source` compilation, you can pass
|
||||
`-DENABLE_OSMOSDR=OFF` to cmake and build GNSS-SDR again).
|
||||
|
||||
#### Build BladeRF support (OPTIONAL)
|
||||
|
||||
GNSS-SDR can talk to Nuand's [bladeRF](https://www.nuand.com/) front-ends
|
||||
(bladeRF x40, x115, and bladeRF 2.0 Micro xA4/xA9) directly through
|
||||
`libbladeRF`, without going through OsmoSDR. This requires `libbladeRF` v2.6.0
|
||||
or newer (needed for reliable bladeRF 2.0 Micro support); older packaged
|
||||
versions (e.g., the one currently in Ubuntu's `universe` repository) are
|
||||
rejected at `cmake` configuration time with a message asking you to upgrade.
|
||||
Install the library and headers (e.g., on Debian / Ubuntu,
|
||||
`sudo apt install libbladerf-dev`, then check its version with
|
||||
`pkg-config --modversion libbladeRF`; if it is older than 2.6.0, build
|
||||
`libbladeRF` from source instead -- see
|
||||
[Nuand's bladeRF repository](https://github.com/Nuand/bladeRF)), then configure
|
||||
GNSS-SDR to build the `Bladerf_Signal_Source` by:
|
||||
|
||||
```
|
||||
$ cmake -S . -B build -DENABLE_BLADERF=ON
|
||||
$ cmake --build build
|
||||
$ sudo cmake --install build
|
||||
```
|
||||
|
||||
(in order to disable the `Bladerf_Signal_Source` compilation, you can pass
|
||||
`-DENABLE_BLADERF=OFF` to cmake and build GNSS-SDR again). A sample
|
||||
configuration file is provided at
|
||||
[conf/RealTime_input/gnss-sdr_GPS_L1_bladeRF_native.conf](./conf/RealTime_input/gnss-sdr_GPS_L1_bladeRF_native.conf).
|
||||
Note that, unlike the `Osmosdr_Signal_Source` path, `libbladeRF` exposes a
|
||||
single overall RX gain instead of separate LNA / VGA1 / VGA2 stages, and only
|
||||
single-channel (SISO) reception is currently supported (bladeRF 2.0 Micro xA9's
|
||||
second RX channel is not yet exposed).
|
||||
|
||||
#### Build FMCOMMS2 based SDR Hardware support (OPTIONAL)
|
||||
|
||||
Install the [libiio](https://github.com/analogdevicesinc/libiio.git) (>=v0.11),
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
# GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
# This file is part of GNSS-SDR.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2011-2026 C. Fernandez-Prades cfernandez(at)cttc.es
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# Tries to find libbladeRF.
|
||||
#
|
||||
# Usage of this module as follows:
|
||||
#
|
||||
# find_package(LIBBLADERF)
|
||||
#
|
||||
# Variables used by this module, they can change the default behaviour and need
|
||||
# to be set before calling find_package:
|
||||
#
|
||||
# LIBBLADERF_ROOT Set this variable to the root installation of
|
||||
# libbladeRF if the module has problems finding
|
||||
# the proper installation path.
|
||||
#
|
||||
# Variables defined by this module:
|
||||
#
|
||||
# LIBBLADERF_FOUND System has libbladeRF libs/headers
|
||||
# LIBBLADERF_LIBRARIES The libbladeRF libraries (bladeRF)
|
||||
# LIBBLADERF_INCLUDE_DIRS The location of libbladeRF headers
|
||||
#
|
||||
# Provides the following imported target:
|
||||
# Bladerf::bladerf
|
||||
#
|
||||
|
||||
if(NOT COMMAND feature_summary)
|
||||
include(FeatureSummary)
|
||||
endif()
|
||||
|
||||
if(NOT PKG_CONFIG_FOUND)
|
||||
include(FindPkgConfig)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED GNSSSDR_LIB_PATHS)
|
||||
include(GnsssdrFindPaths)
|
||||
endif()
|
||||
|
||||
pkg_check_modules(PC_LIBBLADERF libbladeRF)
|
||||
|
||||
if(NOT LIBBLADERF_ROOT)
|
||||
set(LIBBLADERF_ROOT_USER_DEFINED /usr)
|
||||
else()
|
||||
set(LIBBLADERF_ROOT_USER_DEFINED ${LIBBLADERF_ROOT})
|
||||
endif()
|
||||
if(DEFINED ENV{LIBBLADERF_ROOT})
|
||||
set(LIBBLADERF_ROOT_USER_DEFINED
|
||||
${LIBBLADERF_ROOT_USER_DEFINED}
|
||||
$ENV{LIBBLADERF_ROOT}
|
||||
)
|
||||
endif()
|
||||
set(LIBBLADERF_ROOT_USER_DEFINED
|
||||
${LIBBLADERF_ROOT_USER_DEFINED}
|
||||
${CMAKE_INSTALL_PREFIX}
|
||||
)
|
||||
|
||||
find_path(LIBBLADERF_INCLUDE_DIRS
|
||||
NAMES libbladeRF.h
|
||||
HINTS ${PC_LIBBLADERF_INCLUDEDIR}
|
||||
PATHS ${LIBBLADERF_ROOT_USER_DEFINED}/include
|
||||
${GNSSSDR_INCLUDE_PATHS}
|
||||
)
|
||||
|
||||
find_library(LIBBLADERF_LIBRARIES
|
||||
NAMES bladeRF
|
||||
HINTS ${PC_LIBBLADERF_LIBDIR}
|
||||
PATHS ${LIBBLADERF_ROOT_USER_DEFINED}/lib
|
||||
${LIBBLADERF_ROOT_USER_DEFINED}/lib64
|
||||
${GNSSSDR_LIB_PATHS}
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LIBBLADERF DEFAULT_MSG LIBBLADERF_LIBRARIES LIBBLADERF_INCLUDE_DIRS)
|
||||
|
||||
if(PC_LIBBLADERF_VERSION)
|
||||
set(LIBBLADERF_VERSION ${PC_LIBBLADERF_VERSION})
|
||||
endif()
|
||||
|
||||
if(LIBBLADERF_FOUND AND LIBBLADERF_VERSION AND DEFINED GNSSSDR_LIBBLADERF_MIN_VERSION)
|
||||
if(LIBBLADERF_VERSION VERSION_LESS GNSSSDR_LIBBLADERF_MIN_VERSION)
|
||||
message(STATUS "libbladeRF v${LIBBLADERF_VERSION} was found, but GNSS-SDR requires at least v${GNSSSDR_LIBBLADERF_MIN_VERSION}. Please upgrade libbladeRF: https://github.com/Nuand/bladeRF")
|
||||
set(LIBBLADERF_FOUND FALSE)
|
||||
unset(LIBBLADERF_LIBRARIES CACHE)
|
||||
unset(LIBBLADERF_INCLUDE_DIRS CACHE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(LIBBLADERF_FOUND AND LIBBLADERF_VERSION)
|
||||
set_package_properties(LIBBLADERF PROPERTIES
|
||||
DESCRIPTION "Nuand bladeRF library (found: v${LIBBLADERF_VERSION})"
|
||||
)
|
||||
else()
|
||||
set_package_properties(LIBBLADERF PROPERTIES
|
||||
DESCRIPTION "Nuand bladeRF library"
|
||||
)
|
||||
endif()
|
||||
|
||||
set_package_properties(LIBBLADERF PROPERTIES
|
||||
URL "https://github.com/Nuand/bladeRF"
|
||||
)
|
||||
|
||||
if(LIBBLADERF_FOUND AND NOT TARGET Bladerf::bladerf)
|
||||
add_library(Bladerf::bladerf SHARED IMPORTED)
|
||||
set_target_properties(Bladerf::bladerf PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
|
||||
IMPORTED_LOCATION "${LIBBLADERF_LIBRARIES}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${LIBBLADERF_INCLUDE_DIRS}"
|
||||
INTERFACE_LINK_LIBRARIES "${LIBBLADERF_LIBRARIES}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(LIBBLADERF_LIBRARIES LIBBLADERF_INCLUDE_DIRS)
|
||||
@@ -0,0 +1,113 @@
|
||||
; This is a GNSS-SDR configuration file
|
||||
; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/
|
||||
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
; SPDX-FileCopyrightText: (C) 2010-2026 (see AUTHORS file for a list of contributors)
|
||||
|
||||
[GNSS-SDR]
|
||||
|
||||
;######### GLOBAL OPTIONS ##################
|
||||
GNSS-SDR.internal_fs_sps=2000000
|
||||
|
||||
;######### SIGNAL_SOURCE CONFIG ############
|
||||
; Native libbladeRF signal source (requires the -DENABLE_BLADERF=ON building
|
||||
; flag). Works with bladeRF x40, x115, and bladeRF 2.0 Micro xA4/xA9 (single
|
||||
; RX channel). Unlike the Osmosdr_Signal_Source path (see
|
||||
; gnss-sdr_GPS_L1_bladeRF.conf), libbladeRF exposes a single overall RX gain
|
||||
; instead of separate LNA/VGA1/VGA2 stages.
|
||||
SignalSource.implementation=Bladerf_Signal_Source
|
||||
SignalSource.item_type=gr_complex
|
||||
SignalSource.sampling_frequency=2000000
|
||||
SignalSource.freq=1575420000
|
||||
SignalSource.bandwidth=2000000
|
||||
SignalSource.gain=40
|
||||
SignalSource.AGC_enabled=false
|
||||
; Enable to power an active GNSS antenna from the RX bias tee (bladeRF 2.0
|
||||
; Micro only; ignored with a warning on bladeRF1 boards).
|
||||
SignalSource.rx_bias_tee=false
|
||||
; Leave empty to open the first bladeRF found, or set a specific unit's
|
||||
; serial number here.
|
||||
SignalSource.device_serial=
|
||||
SignalSource.samples=0
|
||||
SignalSource.dump=false
|
||||
SignalSource.dump_filename=./signal_source.dat
|
||||
|
||||
;######### SIGNAL_CONDITIONER CONFIG ############
|
||||
SignalConditioner.implementation=Signal_Conditioner
|
||||
|
||||
;######### DATA_TYPE_ADAPTER CONFIG ############
|
||||
DataTypeAdapter.implementation=Pass_Through
|
||||
|
||||
;######### INPUT_FILTER CONFIG ############
|
||||
InputFilter.implementation=Freq_Xlating_Fir_Filter
|
||||
InputFilter.decimation_factor=1
|
||||
InputFilter.input_item_type=gr_complex
|
||||
InputFilter.output_item_type=gr_complex
|
||||
InputFilter.taps_item_type=float
|
||||
InputFilter.number_of_taps=5
|
||||
InputFilter.number_of_bands=2
|
||||
InputFilter.band1_begin=0.0
|
||||
InputFilter.band1_end=0.85
|
||||
InputFilter.band2_begin=0.9
|
||||
InputFilter.band2_end=1.0
|
||||
InputFilter.ampl1_begin=1.0
|
||||
InputFilter.ampl1_end=1.0
|
||||
InputFilter.ampl2_begin=0.0
|
||||
InputFilter.ampl2_end=0.0
|
||||
InputFilter.band1_error=1.0
|
||||
InputFilter.band2_error=1.0
|
||||
InputFilter.filter_type=bandpass
|
||||
InputFilter.grid_density=16
|
||||
InputFilter.dump=false
|
||||
InputFilter.dump_filename=./input_filter.dat
|
||||
|
||||
;######### RESAMPLER CONFIG ############
|
||||
Resampler.implementation=Pass_Through
|
||||
|
||||
;######### CHANNELS GLOBAL CONFIG ############
|
||||
Channels_1C.count=8
|
||||
Channels.in_acquisition=1
|
||||
Channel.signal=1C
|
||||
|
||||
;######### ACQUISITION GLOBAL CONFIG ############
|
||||
Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition
|
||||
Acquisition_1C.item_type=gr_complex
|
||||
Acquisition_1C.coherent_integration_time_ms=1
|
||||
Acquisition_1C.threshold=2.5
|
||||
Acquisition_1C.doppler_max=10000
|
||||
Acquisition_1C.doppler_step=500
|
||||
Acquisition_1C.dump=false
|
||||
Acquisition_1C.dump_filename=./acq_dump.dat
|
||||
|
||||
;######### TRACKING GLOBAL CONFIG ############
|
||||
Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking
|
||||
Tracking_1C.item_type=gr_complex
|
||||
Tracking_1C.pll_bw_hz=40.0;
|
||||
Tracking_1C.dll_bw_hz=2.0;
|
||||
Tracking_1C.order=3;
|
||||
Tracking_1C.early_late_space_chips=0.5;
|
||||
Tracking_1C.dump=false
|
||||
Tracking_1C.dump_filename=./tracking_ch_
|
||||
|
||||
;######### TELEMETRY DECODER GPS CONFIG ############
|
||||
TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder
|
||||
TelemetryDecoder_1C.dump=false
|
||||
|
||||
;######### OBSERVABLES CONFIG ############
|
||||
Observables.implementation=Hybrid_Observables
|
||||
Observables.dump=false
|
||||
Observables.dump_filename=./observables.dat
|
||||
|
||||
;######### PVT CONFIG ############
|
||||
;PVT.implementation=RTKLIB_PVT
|
||||
PVT.positioning_mode=Single
|
||||
PVT.output_rate_ms=100
|
||||
PVT.display_rate_ms=500
|
||||
PVT.iono_model=Broadcast
|
||||
PVT.trop_model=Saastamoinen
|
||||
PVT.flag_rtcm_server=false
|
||||
PVT.flag_rtcm_tty_port=false
|
||||
PVT.rtcm_dump_devname=/dev/pts/1
|
||||
PVT.rtcm_tcp_port=2101
|
||||
PVT.rtcm_MT1019_rate_ms=5000
|
||||
PVT.rtcm_MT1077_rate_ms=1000
|
||||
PVT.rinex_version=2
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
; This is a GNSS-SDR configuration file
|
||||
; The configuration API is described at https://gnss-sdr.org/docs/sp-blocks/
|
||||
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
; SPDX-FileCopyrightText: (C) 2010-2026 (see AUTHORS file for a list of contributors)
|
||||
|
||||
; You can define your own receiver and invoke it by doing
|
||||
; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf
|
||||
;
|
||||
|
||||
[GNSS-SDR]
|
||||
|
||||
;######### GLOBAL OPTIONS ##################
|
||||
GNSS-SDR.internal_fs_sps=8000000
|
||||
GNSS-SDR.Beidou_banned_prns=56,57,58
|
||||
|
||||
|
||||
;######### SIGNAL_SOURCE CONFIG ############
|
||||
; Native libbladeRF signal source (requires the -DENABLE_BLADERF=ON building
|
||||
; flag and libbladeRF v2.6.0+; see gnss-sdr_GPS_L1_bladeRF_native.conf).
|
||||
; One wideband capture centered between the BeiDou B1I band (1561.098 MHz)
|
||||
; and the GLONASS L1 band (~1602 MHz) is split, below, into three sub-bands
|
||||
; by three parallel Freq_Xlating_Fir_Filter chains tapping the same physical
|
||||
; bladeRF stream (SignalSource.RF_channels=3): BeiDou B1I, GPS L1 C/A +
|
||||
; Galileo E1 (co-located at 1575.42 MHz), and GLONASS L1 C/A.
|
||||
; Requires a bladeRF 2.0 Micro (AD9361-based); 56 Msps / 56 MHz bandwidth is
|
||||
; at its maximum supported bandwidth.
|
||||
SignalSource.implementation=Bladerf_Signal_Source
|
||||
SignalSource.item_type=gr_complex
|
||||
SignalSource.sampling_frequency=56000000
|
||||
SignalSource.freq=1584000000
|
||||
SignalSource.bandwidth=56000000
|
||||
SignalSource.gain=40
|
||||
SignalSource.AGC_enabled=false
|
||||
SignalSource.rx_bias_tee=false
|
||||
SignalSource.device_serial=
|
||||
SignalSource.samples=0
|
||||
SignalSource.RF_channels=3
|
||||
SignalSource.dump=false
|
||||
|
||||
|
||||
|
||||
;######### SIGNAL_CONDITIONER CONFIG ############
|
||||
SignalConditioner0.implementation=Signal_Conditioner
|
||||
SignalConditioner1.implementation=Signal_Conditioner
|
||||
SignalConditioner2.implementation=Signal_Conditioner
|
||||
|
||||
;######### DATA_TYPE_ADAPTER CONFIG ############
|
||||
DataTypeAdapter0.implementation=Pass_Through
|
||||
DataTypeAdapter1.implementation=Pass_Through
|
||||
DataTypeAdapter2.implementation=Pass_Through
|
||||
|
||||
;######### INPUT_FILTER CONFIG ############
|
||||
; Sub-band 0: BeiDou B1I (1561.098 MHz), RF_channel_ID=0
|
||||
InputFilter0.implementation=Freq_Xlating_Fir_Filter
|
||||
InputFilter0.decimation_factor=7
|
||||
InputFilter0.input_item_type=gr_complex
|
||||
InputFilter0.output_item_type=gr_complex
|
||||
InputFilter0.taps_item_type=float
|
||||
InputFilter0.filter_type=lowpass
|
||||
InputFilter0.bw=7000000
|
||||
InputFilter0.tw=500000
|
||||
InputFilter0.IF=-22902000
|
||||
InputFilter0.sampling_frequency=56000000
|
||||
InputFilter0.dump=false
|
||||
InputFilter0.dump_filename=./input_filter.dat
|
||||
|
||||
;######### INPUT_FILTER CONFIG ############
|
||||
; Sub-band 1: GPS L1 C/A + Galileo E1 (1575.42 MHz), RF_channel_ID=1
|
||||
InputFilter1.implementation=Freq_Xlating_Fir_Filter
|
||||
InputFilter1.decimation_factor=7
|
||||
InputFilter1.input_item_type=gr_complex
|
||||
InputFilter1.output_item_type=gr_complex
|
||||
InputFilter1.taps_item_type=float
|
||||
InputFilter1.filter_type=lowpass
|
||||
InputFilter1.bw=7000000
|
||||
InputFilter1.tw=500000
|
||||
InputFilter1.IF=-8580000
|
||||
InputFilter1.sampling_frequency=56000000
|
||||
InputFilter1.dump=false
|
||||
InputFilter1.dump_filename=./input_filter.dat
|
||||
|
||||
;######### INPUT_FILTER CONFIG ############
|
||||
; Sub-band 2: GLONASS L1 C/A (~1602 MHz, FDMA), RF_channel_ID=2
|
||||
InputFilter2.implementation=Freq_Xlating_Fir_Filter
|
||||
InputFilter2.decimation_factor=7
|
||||
InputFilter2.input_item_type=gr_complex
|
||||
InputFilter2.output_item_type=gr_complex
|
||||
InputFilter2.taps_item_type=float
|
||||
InputFilter2.filter_type=lowpass
|
||||
InputFilter2.bw=7000000
|
||||
InputFilter2.tw=500000
|
||||
InputFilter2.IF=18000000
|
||||
InputFilter2.sampling_frequency=56000000
|
||||
InputFilter2.dump=false
|
||||
InputFilter2.dump_filename=./input_filter.dat
|
||||
|
||||
;######### RESAMPLER CONFIG ############
|
||||
Resampler0.implementation=Pass_Through
|
||||
Resampler1.implementation=Pass_Through
|
||||
Resampler2.implementation=Pass_Through
|
||||
|
||||
;######### CHANNELS GLOBAL CONFIG ############
|
||||
Channels_1B.count=10
|
||||
Channels_1C.count=10
|
||||
Channels_B1.count=14
|
||||
Channels_1G.count=8
|
||||
|
||||
Channels_1B.RF_channel_ID=1
|
||||
Channels_1C.RF_channel_ID=1
|
||||
Channels_B1.RF_channel_ID=0
|
||||
Channels_1G.RF_channel_ID=2
|
||||
|
||||
|
||||
Channels.in_acquisition=2
|
||||
|
||||
;######### ACQUISITION BEIDOU CONFIG ############
|
||||
Acquisition_B1.implementation=BEIDOU_B1I_PCPS_Acquisition
|
||||
Acquisition_B1.item_type=gr_complex
|
||||
Acquisition_B1.coherent_integration_time_ms=2
|
||||
Acquisition_B1.pfa=0.000002
|
||||
Acquisition_B1.doppler_max=6000
|
||||
Acquisition_B1.doppler_step=100
|
||||
Acquisition_B1.dump=false
|
||||
Acquisition_B1.dump_filename=./bds_acq
|
||||
Acquisition_B1.bit_transition_flag=false
|
||||
|
||||
;######### ACQUISITION GPS CONFIG ############
|
||||
Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition
|
||||
Acquisition_1C.item_type=gr_complex
|
||||
Acquisition_1C.coherent_integration_time_ms=1
|
||||
Acquisition_1C.pfa=0.015
|
||||
Acquisition_1C.doppler_max=6000
|
||||
Acquisition_1C.doppler_step=200
|
||||
Acquisition_1C.max_dwells=4
|
||||
Acquisition_1C.dump=false
|
||||
Acquisition_1C.dump_filename=./acq_dump.dat
|
||||
|
||||
;######### ACQUISITION GALILEO CONFIG ############
|
||||
Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition
|
||||
Acquisition_1B.coherent_integration_time_ms=2
|
||||
Acquisition_1B.pfa=0.025
|
||||
Acquisition_1B.doppler_max=6000
|
||||
Acquisition_1B.doppler_step=200
|
||||
Acquisition_1B.max_dwells=4
|
||||
Acquisition_1B.cboc=true
|
||||
Acquisition_1B.dump=false
|
||||
Acquisition_1B.dump_filename=./acq_dump.dat
|
||||
|
||||
;######### ACQUISITION GLONASS CONFIG ############
|
||||
Acquisition_1G.implementation=GLONASS_L1_CA_PCPS_Acquisition
|
||||
Acquisition_1G.item_type=gr_complex
|
||||
Acquisition_1G.coherent_integration_time_ms=1
|
||||
Acquisition_1G.max_dwells=4
|
||||
Acquisition_1G.pfa=0.02
|
||||
Acquisition_1G.doppler_max=6000
|
||||
Acquisition_1G.doppler_step=100
|
||||
Acquisition_1G.dump=false
|
||||
Acquisition_1G.dump_filename=./G1_acq
|
||||
|
||||
|
||||
|
||||
;######### TRACKING BEIDOU CONFIG ############
|
||||
Tracking_B1.implementation=BEIDOU_B1I_DLL_PLL_Tracking
|
||||
Tracking_B1.item_type=gr_complex
|
||||
Tracking_B1.extend_correlation_symbols=10
|
||||
Tracking_B1.pll_bw_hz=50.0
|
||||
Tracking_B1.dll_bw_hz=2.00
|
||||
Tracking_B1.pll_bw_narrow_hz=15.0
|
||||
Tracking_B1.dll_bw_narrow_hz=1.50
|
||||
Tracking_B1.dump=false
|
||||
Tracking_B1.dump_filename=./epl_tracking_ch_
|
||||
|
||||
;######### TRACKING GPS CONFIG ############
|
||||
Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking
|
||||
Tracking_1C.item_type=gr_complex
|
||||
Tracking_1C.extend_correlation_symbols=10
|
||||
Tracking_1C.early_late_space_chips=0.5
|
||||
Tracking_1C.early_late_space_narrow_chips=0.15
|
||||
Tracking_1C.pll_bw_hz=30.0
|
||||
Tracking_1C.dll_bw_hz=2.0
|
||||
Tracking_1C.pll_bw_narrow_hz=10.0
|
||||
Tracking_1C.dll_bw_narrow_hz=1.50
|
||||
Tracking_1C.fll_bw_hz=10
|
||||
Tracking_1C.enable_fll_pull_in=true
|
||||
Tracking_1C.enable_fll_steady_state=false
|
||||
Tracking_1C.dump=false
|
||||
Tracking_1C.dump_filename=tracking_ch_
|
||||
|
||||
;######### TRACKING GALILEO CONFIG ############
|
||||
Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking
|
||||
Tracking_1B.extend_correlation_symbols=4
|
||||
Tracking_1B.item_type=gr_complex
|
||||
Tracking_1B.pll_bw_hz=30.0
|
||||
Tracking_1B.dll_bw_hz=2.0
|
||||
Tracking_1B.pll_bw_narrow_hz=20.0
|
||||
Tracking_1B.dll_bw_narrow_hz=1.50
|
||||
Tracking_1B.track_pilot=true
|
||||
Tracking_1B.enable_fll_pull_in=true
|
||||
Tracking_1B.enable_fll_steady_state=false
|
||||
Tracking_1B.fll_bw_hz=20
|
||||
|
||||
;######### TRACKING GLONASS CONFIG ############
|
||||
Tracking_1G.implementation=GLONASS_L1_CA_DLL_PLL_Tracking
|
||||
Tracking_1G.item_type=gr_complex
|
||||
Tracking_1G.pll_bw_hz=40
|
||||
Tracking_1G.dll_bw_hz=2.5
|
||||
Tracking_1G.extend_correlation_ms=1
|
||||
Tracking_1G.pll_bw_narrow_hz=20
|
||||
Tracking_1G.dll_bw_narrow_hz=1.5
|
||||
Tracking_1G.dump=false
|
||||
Tracking_1G.dump_filename=./epl_tracking_ch_
|
||||
|
||||
|
||||
|
||||
;######### TELEMETRY DECODER BEIDOU CONFIG ############
|
||||
TelemetryDecoder_B1.implementation=BEIDOU_B1I_Telemetry_Decoder
|
||||
TelemetryDecoder_B1.dump=false
|
||||
|
||||
;######### TELEMETRY DECODER GPS CONFIG ############
|
||||
TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder
|
||||
TelemetryDecoder_1C.dump=false
|
||||
|
||||
;######### TELEMETRY DECODER GALILEO E1B CONFIG ############
|
||||
TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder
|
||||
TelemetryDecoder_1B.dump=false
|
||||
|
||||
;######### TELEMETRY DECODER GLONASS CONFIG ############
|
||||
TelemetryDecoder_1G.implementation=GLONASS_L1_CA_Telemetry_Decoder
|
||||
TelemetryDecoder_1G.dump=false
|
||||
|
||||
|
||||
;######### OBSERVABLES CONFIG ############
|
||||
Observables.implementation=Hybrid_Observables
|
||||
Observables.dump=false
|
||||
Observables.dump_filename=./observables.dat
|
||||
|
||||
;######### PVT CONFIG ############
|
||||
PVT.implementation=RTKLIB_PVT
|
||||
PVT.threshold_reject_GDOP=100
|
||||
PVT.elevation_mask=3
|
||||
PVT.raim_fde=1
|
||||
PVT.positioning_mode=Single ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic
|
||||
PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX
|
||||
PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad
|
||||
PVT.output_rate_ms=100
|
||||
PVT.display_rate_ms=500
|
||||
PVT.enable_rx_clock_correction=true
|
||||
PVT.flag_rtcm_server=false
|
||||
PVT.flag_rtcm_tty_port=false
|
||||
PVT.rtcm_dump_devname=/dev/pts/1
|
||||
PVT.rtcm_tcp_port=2101
|
||||
PVT.rtcm_MT1019_rate_ms=5000
|
||||
PVT.rtcm_MT1077_rate_ms=1000
|
||||
PVT.rinex_version=2
|
||||
@@ -220,6 +220,15 @@ All notable changes to GNSS-SDR will be documented in this file.
|
||||
the RTKLIB navigation structure, and adds `qzss_utc_model.xml`,
|
||||
`qzss_iono.xml`, `qzss_cnav_utc_model.xml`, and `qzss_cnav_iono.xml` to the
|
||||
XML storage output.
|
||||
- Added a `Bladerf_Signal_Source` for interoperability with Nuand's bladeRF
|
||||
front-ends (bladeRF x40, x115, and bladeRF 2.0 Micro xA4/xA9), streaming RX
|
||||
samples directly through `libbladeRF` (requires the `-DENABLE_BLADERF=ON`
|
||||
building flag) instead of going through `gr-osmosdr`. Supports single-channel
|
||||
(SISO) reception, an optional RX bias tee for powering an active antenna on
|
||||
the 2.0 Micro, and exposes a single overall RX gain (unlike the `if_gain` /
|
||||
`rf_gain` split used by `Osmosdr_Signal_Source`). A sample configuration file
|
||||
is provided at `conf/RealTime_input/gnss-sdr_GPS_L1_bladeRF_native.conf`.
|
||||
Contributed by @MrCry0.
|
||||
- Added a new Signal Source implementation `Pocket_SDR_Signal_Source`, which
|
||||
supports
|
||||
[Pocket SDR FE](https://www.datagnss.com/products/pocketsdr-gnss-receiver)
|
||||
|
||||
@@ -101,6 +101,13 @@ if(ENABLE_LIMESDR)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_BLADERF)
|
||||
if(LIBBLADERF_FOUND)
|
||||
list(APPEND OPT_DRIVER_SOURCES bladerf_signal_source.cc)
|
||||
list(APPEND OPT_DRIVER_HEADERS bladerf_signal_source.h)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_POCKETSDR)
|
||||
if(GRPOCKETSDR_FOUND)
|
||||
list(APPEND OPT_DRIVER_SOURCES pocket_sdr_signal_source.cc)
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*!
|
||||
* \file bladerf_signal_source.cc
|
||||
* \brief Signal source for the Nuand bladeRF family of front-ends (bladeRF
|
||||
* x40, x115, and bladeRF 2.0 Micro xA4/xA9), using libbladeRF directly.
|
||||
* \author Oleksandr Suvorov, 2026.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "bladerf_signal_source.h"
|
||||
#include "configuration_interface.h"
|
||||
#include "gnss_frequencies.h"
|
||||
#include "gnss_sdr_string_literals.h"
|
||||
#include "gnss_sdr_valve.h"
|
||||
#include <gnuradio/blocks/file_sink.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
#include <glog/logging.h>
|
||||
#else
|
||||
#include <absl/log/log.h>
|
||||
#endif
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
BladerfSignalSource::BladerfSignalSource(const ConfigurationInterface* configuration,
|
||||
const std::string& role,
|
||||
unsigned int in_stream,
|
||||
unsigned int out_stream,
|
||||
Concurrent_Queue<pmt::pmt_t>* queue)
|
||||
: SignalSourceBase(configuration, role, "Bladerf_Signal_Source"s),
|
||||
item_type_(configuration->property(role + ".item_type", std::string("gr_complex"))),
|
||||
dump_filename_(configuration->property(role + ".dump_filename", std::string("./data/signal_source.dat"))),
|
||||
bladerf_args_(configuration->property(role + ".bladerf_args", std::string())),
|
||||
device_serial_(configuration->property(role + ".device_serial", std::string())),
|
||||
sample_rate_(configuration->property(role + ".sampling_frequency", 2.0e6)),
|
||||
freq_(configuration->property(role + ".freq", FREQ1)),
|
||||
bandwidth_(configuration->property(role + ".bandwidth", sample_rate_)),
|
||||
gain_(configuration->property(role + ".gain", 40.0)),
|
||||
samples_(configuration->property(role + ".samples", int64_t(0))),
|
||||
in_stream_(in_stream),
|
||||
out_stream_(out_stream),
|
||||
num_buffers_(configuration->property(role + ".num_buffers", 32u)),
|
||||
buffer_size_(configuration->property(role + ".buffer_size", 32768u)),
|
||||
num_transfers_(configuration->property(role + ".num_transfers", 16u)),
|
||||
stream_timeout_ms_(configuration->property(role + ".stream_timeout_ms", 3000u)),
|
||||
agc_enabled_(configuration->property(role + ".AGC_enabled", false)),
|
||||
rx_bias_tee_(configuration->property(role + ".rx_bias_tee", false)),
|
||||
dump_(configuration->property(role + ".dump", false))
|
||||
{
|
||||
if (item_type_ != "gr_complex")
|
||||
{
|
||||
std::string error_message = "bladeRF: item_type '" + item_type_ + "' not supported, only 'gr_complex' is supported.";
|
||||
LOG(ERROR) << error_message;
|
||||
throw std::invalid_argument(error_message);
|
||||
}
|
||||
item_size_ = sizeof(gr_complex);
|
||||
|
||||
try
|
||||
{
|
||||
bladerf_source_ = bladerf_make_source_sptr(bladerf_args_, device_serial_,
|
||||
sample_rate_, freq_, bandwidth_, gain_, agc_enabled_, rx_bias_tee_,
|
||||
num_buffers_, buffer_size_, num_transfers_, stream_timeout_ms_);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG(WARNING) << "bladeRF exception: " << e.what();
|
||||
throw std::invalid_argument("Wrong bladeRF arguments");
|
||||
}
|
||||
|
||||
if (samples_ != 0)
|
||||
{
|
||||
DLOG(INFO) << "Send STOP signal after " << samples_ << " samples";
|
||||
valve_ = gnss_sdr_make_valve(item_size_, samples_, queue);
|
||||
DLOG(INFO) << "valve(" << valve_->unique_id() << ")";
|
||||
}
|
||||
|
||||
if (dump_)
|
||||
{
|
||||
DLOG(INFO) << "Dumping output into file " << dump_filename_;
|
||||
file_sink_ = gr::blocks::file_sink::make(item_size_, dump_filename_.c_str());
|
||||
DLOG(INFO) << "file_sink(" << file_sink_->unique_id() << ")";
|
||||
}
|
||||
|
||||
if (in_stream_ > 0)
|
||||
{
|
||||
LOG(ERROR) << "A signal source does not have an input stream";
|
||||
}
|
||||
if (out_stream_ > 1)
|
||||
{
|
||||
LOG(ERROR) << "This implementation only supports one output stream";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BladerfSignalSource::connect(gr::top_block_sptr top_block)
|
||||
{
|
||||
if (samples_ != 0)
|
||||
{
|
||||
top_block->connect(bladerf_source_, 0, valve_, 0);
|
||||
DLOG(INFO) << "connected bladeRF source to valve";
|
||||
if (dump_)
|
||||
{
|
||||
top_block->connect(valve_, 0, file_sink_, 0);
|
||||
DLOG(INFO) << "connected valve to file sink";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dump_)
|
||||
{
|
||||
top_block->connect(bladerf_source_, 0, file_sink_, 0);
|
||||
DLOG(INFO) << "connected bladeRF source to file sink";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BladerfSignalSource::disconnect(gr::top_block_sptr top_block)
|
||||
{
|
||||
if (samples_ != 0)
|
||||
{
|
||||
top_block->disconnect(bladerf_source_, 0, valve_, 0);
|
||||
if (dump_)
|
||||
{
|
||||
top_block->disconnect(valve_, 0, file_sink_, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dump_)
|
||||
{
|
||||
top_block->disconnect(bladerf_source_, 0, file_sink_, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gr::basic_block_sptr BladerfSignalSource::get_left_block()
|
||||
{
|
||||
LOG(WARNING) << "Trying to get signal source left block.";
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
gr::basic_block_sptr BladerfSignalSource::get_right_block()
|
||||
{
|
||||
if (samples_ != 0)
|
||||
{
|
||||
return valve_;
|
||||
}
|
||||
return bladerf_source_;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*!
|
||||
* \file bladerf_signal_source.h
|
||||
* \brief Signal source for the Nuand bladeRF family of front-ends (bladeRF
|
||||
* x40, x115, and bladeRF 2.0 Micro xA4/xA9), using libbladeRF directly.
|
||||
* \author Oleksandr Suvorov, 2026.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef GNSS_SDR_BLADERF_SIGNAL_SOURCE_H
|
||||
#define GNSS_SDR_BLADERF_SIGNAL_SOURCE_H
|
||||
|
||||
#include "bladerf_source.h"
|
||||
#include "concurrent_queue.h"
|
||||
#include "signal_source_base.h"
|
||||
#include <gnuradio/blocks/file_sink.h>
|
||||
#include <pmt/pmt.h>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
/** \addtogroup Signal_Source
|
||||
* \{ */
|
||||
/** \addtogroup Signal_Source_adapters
|
||||
* \{ */
|
||||
|
||||
|
||||
class ConfigurationInterface;
|
||||
|
||||
/*!
|
||||
* \brief This class instantiates the bladeRF signal source, streaming RX
|
||||
* samples directly through libbladeRF (no gr-osmosdr or other intermediate
|
||||
* driver required).
|
||||
*/
|
||||
class BladerfSignalSource : public SignalSourceBase
|
||||
{
|
||||
public:
|
||||
BladerfSignalSource(const ConfigurationInterface* configuration,
|
||||
const std::string& role, unsigned int in_stream,
|
||||
unsigned int out_stream, Concurrent_Queue<pmt::pmt_t>* queue);
|
||||
|
||||
~BladerfSignalSource() = default;
|
||||
|
||||
inline size_t item_size() override
|
||||
{
|
||||
return item_size_;
|
||||
}
|
||||
|
||||
void connect(gr::top_block_sptr top_block) override;
|
||||
void disconnect(gr::top_block_sptr top_block) override;
|
||||
gr::basic_block_sptr get_left_block() override;
|
||||
gr::basic_block_sptr get_right_block() override;
|
||||
|
||||
private:
|
||||
bladerf_source_sptr bladerf_source_;
|
||||
gnss_shared_ptr<gr::block> valve_;
|
||||
gr::blocks::file_sink::sptr file_sink_;
|
||||
|
||||
std::string item_type_;
|
||||
std::string dump_filename_;
|
||||
std::string bladerf_args_;
|
||||
std::string device_serial_;
|
||||
|
||||
double sample_rate_;
|
||||
double freq_;
|
||||
double bandwidth_;
|
||||
double gain_;
|
||||
size_t item_size_;
|
||||
int64_t samples_;
|
||||
|
||||
unsigned int in_stream_;
|
||||
unsigned int out_stream_;
|
||||
unsigned int num_buffers_;
|
||||
unsigned int buffer_size_;
|
||||
unsigned int num_transfers_;
|
||||
unsigned int stream_timeout_ms_;
|
||||
|
||||
bool agc_enabled_;
|
||||
bool rx_bias_tee_;
|
||||
bool dump_;
|
||||
};
|
||||
|
||||
|
||||
/** \} */
|
||||
/** \} */
|
||||
#endif // GNSS_SDR_BLADERF_SIGNAL_SOURCE_H
|
||||
@@ -20,6 +20,11 @@ if(ENABLE_ION)
|
||||
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ion_gsms.h)
|
||||
endif()
|
||||
|
||||
if(ENABLE_BLADERF AND LIBBLADERF_FOUND)
|
||||
set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} bladerf_source.cc)
|
||||
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} bladerf_source.h)
|
||||
endif()
|
||||
|
||||
set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES
|
||||
fifo_reader.cc
|
||||
unpack_byte_2bit_samples.cc
|
||||
@@ -103,6 +108,13 @@ if(ENABLE_RAW_UDP AND PCAP_FOUND)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ENABLE_BLADERF AND LIBBLADERF_FOUND)
|
||||
target_link_libraries(signal_source_gr_blocks
|
||||
PRIVATE
|
||||
Bladerf::bladerf
|
||||
)
|
||||
endif()
|
||||
|
||||
# Fix for Boost Asio < 1.70
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
if((CMAKE_CXX_COMPILER_ID MATCHES "Clang") AND (Boost_VERSION_STRING VERSION_LESS 1.70.0))
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
/*!
|
||||
* \file bladerf_source.cc
|
||||
* \brief GNU Radio source block for Nuand's bladeRF front-ends (bladeRF x40,
|
||||
* x115, and bladeRF 2.0 Micro xA4/xA9), implemented directly against
|
||||
* libbladeRF.
|
||||
* \author Oleksandr Suvorov, 2026.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "bladerf_source.h"
|
||||
#include <gnuradio/io_signature.h>
|
||||
// bladeRF2.h relies on macros defined by libbladeRF.h but does not include
|
||||
// it itself, so this order must be preserved (protected against
|
||||
// clang-format's alphabetical include sorting).
|
||||
// clang-format off
|
||||
#include <libbladeRF.h>
|
||||
#include <bladeRF2.h>
|
||||
// clang-format on
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
#include <glog/logging.h>
|
||||
#else
|
||||
#include <absl/log/log.h>
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr bladerf_channel kRxChannel = BLADERF_CHANNEL_RX(0);
|
||||
|
||||
std::string make_device_identifier(const std::string &bladerf_args, const std::string &device_serial)
|
||||
{
|
||||
if (!bladerf_args.empty())
|
||||
{
|
||||
return bladerf_args;
|
||||
}
|
||||
if (!device_serial.empty())
|
||||
{
|
||||
return "*:serial=" + device_serial;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
void bladerf_source::bladerf_deleter::operator()(struct bladerf *dev) const
|
||||
{
|
||||
if (dev != nullptr)
|
||||
{
|
||||
bladerf_close(dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bladerf_source_sptr bladerf_make_source_sptr(
|
||||
const std::string &bladerf_args,
|
||||
const std::string &device_serial,
|
||||
double sample_rate,
|
||||
double freq,
|
||||
double bandwidth,
|
||||
double gain,
|
||||
bool agc_enabled,
|
||||
bool rx_bias_tee,
|
||||
unsigned int num_buffers,
|
||||
unsigned int buffer_size,
|
||||
unsigned int num_transfers,
|
||||
unsigned int stream_timeout_ms)
|
||||
{
|
||||
return bladerf_source_sptr(new bladerf_source(bladerf_args, device_serial,
|
||||
sample_rate, freq, bandwidth, gain, agc_enabled, rx_bias_tee,
|
||||
num_buffers, buffer_size, num_transfers, stream_timeout_ms));
|
||||
}
|
||||
|
||||
|
||||
bladerf_source::bladerf_source(
|
||||
const std::string &bladerf_args,
|
||||
const std::string &device_serial,
|
||||
double sample_rate,
|
||||
double freq,
|
||||
double bandwidth,
|
||||
double gain,
|
||||
bool agc_enabled,
|
||||
bool rx_bias_tee,
|
||||
unsigned int num_buffers,
|
||||
unsigned int buffer_size,
|
||||
unsigned int num_transfers,
|
||||
unsigned int stream_timeout_ms)
|
||||
: gr::sync_block("bladerf_source",
|
||||
gr::io_signature::make(0, 0, 0),
|
||||
gr::io_signature::make(1, 1, sizeof(gr_complex))),
|
||||
buffer_size_(buffer_size),
|
||||
stream_timeout_ms_(stream_timeout_ms),
|
||||
streaming_(false)
|
||||
{
|
||||
const std::string identifier = make_device_identifier(bladerf_args, device_serial);
|
||||
|
||||
struct bladerf *raw_dev = nullptr;
|
||||
int status = bladerf_open(&raw_dev, identifier.empty() ? nullptr : identifier.c_str());
|
||||
if (status != 0)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "bladeRF: unable to open device '" << identifier << "': " << bladerf_strerror(status);
|
||||
LOG(ERROR) << oss.str();
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
dev_.reset(raw_dev);
|
||||
|
||||
std::cout << "bladeRF: opened board '" << bladerf_get_board_name(dev_.get()) << "'\n";
|
||||
LOG(INFO) << "bladeRF: opened board '" << bladerf_get_board_name(dev_.get()) << "'";
|
||||
|
||||
bladerf_sample_rate actual_sample_rate = 0;
|
||||
status = bladerf_set_sample_rate(dev_.get(), kRxChannel, static_cast<bladerf_sample_rate>(sample_rate), &actual_sample_rate);
|
||||
if (status != 0)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "bladeRF: unable to set sample rate: " << bladerf_strerror(status);
|
||||
LOG(ERROR) << oss.str();
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
std::cout << "bladeRF: actual RX sample rate: " << actual_sample_rate << " [SPS]\n";
|
||||
|
||||
bladerf_bandwidth actual_bandwidth = 0;
|
||||
status = bladerf_set_bandwidth(dev_.get(), kRxChannel, static_cast<bladerf_bandwidth>(bandwidth), &actual_bandwidth);
|
||||
if (status != 0)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "bladeRF: unable to set bandwidth: " << bladerf_strerror(status);
|
||||
LOG(ERROR) << oss.str();
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
std::cout << "bladeRF: actual RX bandwidth: " << actual_bandwidth << " [Hz]\n";
|
||||
|
||||
status = bladerf_set_frequency(dev_.get(), kRxChannel, static_cast<bladerf_frequency>(freq));
|
||||
if (status != 0)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "bladeRF: unable to set frequency: " << bladerf_strerror(status);
|
||||
LOG(ERROR) << oss.str();
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
std::cout << "bladeRF: RX frequency set to " << freq << " [Hz]\n";
|
||||
|
||||
status = bladerf_set_gain_mode(dev_.get(), kRxChannel, agc_enabled ? BLADERF_GAIN_DEFAULT : BLADERF_GAIN_MGC);
|
||||
if (status != 0)
|
||||
{
|
||||
LOG(WARNING) << "bladeRF: unable to set gain mode: " << bladerf_strerror(status);
|
||||
}
|
||||
|
||||
if (!agc_enabled)
|
||||
{
|
||||
status = bladerf_set_gain(dev_.get(), kRxChannel, static_cast<bladerf_gain>(gain));
|
||||
if (status != 0)
|
||||
{
|
||||
LOG(WARNING) << "bladeRF: unable to set gain: " << bladerf_strerror(status);
|
||||
}
|
||||
}
|
||||
|
||||
if (rx_bias_tee)
|
||||
{
|
||||
status = bladerf_set_bias_tee(dev_.get(), kRxChannel, true);
|
||||
if (status != 0)
|
||||
{
|
||||
LOG(WARNING) << "bladeRF: unable to enable RX bias tee (not supported on this board?): " << bladerf_strerror(status);
|
||||
}
|
||||
}
|
||||
|
||||
status = bladerf_sync_config(dev_.get(), BLADERF_RX_X1, BLADERF_FORMAT_SC16_Q11_META,
|
||||
num_buffers, buffer_size_, num_transfers, stream_timeout_ms_);
|
||||
if (status != 0)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "bladeRF: unable to configure synchronous RX stream: " << bladerf_strerror(status);
|
||||
LOG(ERROR) << oss.str();
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
|
||||
raw_buffer_.resize(static_cast<size_t>(buffer_size_) * 2);
|
||||
|
||||
// Hint the GNU Radio scheduler to negotiate a large output buffer for
|
||||
// this block. Without this, the scheduler was observed requesting
|
||||
// noutput_items as small as ~4096 per work() call regardless of how
|
||||
// large a batch this block was willing to hand over, forcing
|
||||
// bladerf_sync_rx() to be invoked far more often than the underlying
|
||||
// stream's buffering (num_buffers * buffer_size_) could absorb any
|
||||
// scheduling delay against, causing frequent RX overruns (confirmed via
|
||||
// BLADERF_META_STATUS_OVERRUN once that reporting was wired up).
|
||||
this->set_min_output_buffer(2097152);
|
||||
}
|
||||
|
||||
|
||||
bool bladerf_source::start()
|
||||
{
|
||||
int status = bladerf_enable_module(dev_.get(), kRxChannel, true);
|
||||
if (status != 0)
|
||||
{
|
||||
LOG(ERROR) << "bladeRF: unable to enable RX module: " << bladerf_strerror(status);
|
||||
return false;
|
||||
}
|
||||
streaming_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool bladerf_source::stop()
|
||||
{
|
||||
if (streaming_)
|
||||
{
|
||||
int status = bladerf_enable_module(dev_.get(), kRxChannel, false);
|
||||
if (status != 0)
|
||||
{
|
||||
LOG(WARNING) << "bladeRF: unable to disable RX module: " << bladerf_strerror(status);
|
||||
}
|
||||
streaming_ = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int bladerf_source::work(int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
{
|
||||
(void)input_items;
|
||||
|
||||
// Honor whatever batch size GNU Radio's scheduler is ready to accept,
|
||||
// instead of artificially capping every call to buffer_size_ (the
|
||||
// underlying stream's per-transfer size, not a limit on bladerf_sync_rx's
|
||||
// own request size). Capping here forced far more, smaller round trips
|
||||
// through bladerf_sync_rx than necessary, which made the source
|
||||
// sensitive to ordinary OS scheduling jitter on any request that missed
|
||||
// its real-time window.
|
||||
const auto num_samples = static_cast<unsigned int>(noutput_items);
|
||||
if (raw_buffer_.size() < static_cast<size_t>(num_samples) * 2)
|
||||
{
|
||||
raw_buffer_.resize(static_cast<size_t>(num_samples) * 2);
|
||||
}
|
||||
|
||||
struct bladerf_metadata meta;
|
||||
std::memset(&meta, 0, sizeof(meta));
|
||||
meta.flags = BLADERF_META_FLAG_RX_NOW;
|
||||
|
||||
const int status = bladerf_sync_rx(dev_.get(), raw_buffer_.data(), num_samples, &meta, stream_timeout_ms_);
|
||||
if (status == BLADERF_ERR_TIMEOUT)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (status != 0)
|
||||
{
|
||||
LOG(ERROR) << "bladeRF: sync_rx failed: " << bladerf_strerror(status);
|
||||
return -1;
|
||||
}
|
||||
if ((meta.status & BLADERF_META_STATUS_OVERRUN) != 0)
|
||||
{
|
||||
LOG(WARNING) << "bladeRF: RX overrun detected, samples were dropped (requested "
|
||||
<< num_samples << ", got " << meta.actual_count << ")";
|
||||
}
|
||||
|
||||
// meta.actual_count reflects how many samples in raw_buffer_ are
|
||||
// actually valid for this call; on a discontinuity it can be less than
|
||||
// num_samples, and reading past it is undefined per libbladeRF's docs.
|
||||
const unsigned int valid_samples = std::min(num_samples, meta.actual_count);
|
||||
|
||||
auto *out = reinterpret_cast<gr_complex *>(output_items[0]);
|
||||
for (unsigned int i = 0; i < valid_samples; i++)
|
||||
{
|
||||
const float i_val = static_cast<float>(raw_buffer_[2 * i]) / 2048.0F;
|
||||
const float q_val = static_cast<float>(raw_buffer_[(2 * i) + 1]) / 2048.0F;
|
||||
out[i] = gr_complex(i_val, q_val);
|
||||
}
|
||||
|
||||
return static_cast<int>(valid_samples);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*!
|
||||
* \file bladerf_source.h
|
||||
* \brief GNU Radio source block for Nuand's bladeRF front-ends (bladeRF x40,
|
||||
* x115, and bladeRF 2.0 Micro xA4/xA9), implemented directly against
|
||||
* libbladeRF.
|
||||
* \author Oleksandr Suvorov, 2026.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef GNSS_SDR_BLADERF_SOURCE_H
|
||||
#define GNSS_SDR_BLADERF_SOURCE_H
|
||||
|
||||
#include "gnss_block_interface.h"
|
||||
#include <gnuradio/sync_block.h>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** \addtogroup Signal_Source
|
||||
* \{ */
|
||||
/** \addtogroup Signal_Source_gnuradio_blocks
|
||||
* \{ */
|
||||
|
||||
|
||||
class bladerf_source;
|
||||
|
||||
using bladerf_source_sptr = gnss_shared_ptr<bladerf_source>;
|
||||
|
||||
bladerf_source_sptr bladerf_make_source_sptr(
|
||||
const std::string &bladerf_args,
|
||||
const std::string &device_serial,
|
||||
double sample_rate,
|
||||
double freq,
|
||||
double bandwidth,
|
||||
double gain,
|
||||
bool agc_enabled,
|
||||
bool rx_bias_tee,
|
||||
unsigned int num_buffers,
|
||||
unsigned int buffer_size,
|
||||
unsigned int num_transfers,
|
||||
unsigned int stream_timeout_ms);
|
||||
|
||||
/*!
|
||||
* \brief This class implements a GNU Radio source block that streams RX
|
||||
* samples from a bladeRF device (single RX channel) using libbladeRF's
|
||||
* synchronous streaming API, converting the device's native
|
||||
* BLADERF_FORMAT_SC16_Q11 samples to gr_complex.
|
||||
*/
|
||||
class bladerf_source : public gr::sync_block
|
||||
{
|
||||
public:
|
||||
~bladerf_source() override = default;
|
||||
|
||||
bool start() override;
|
||||
bool stop() override;
|
||||
|
||||
int work(int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items) override;
|
||||
|
||||
private:
|
||||
friend bladerf_source_sptr bladerf_make_source_sptr(
|
||||
const std::string &bladerf_args,
|
||||
const std::string &device_serial,
|
||||
double sample_rate,
|
||||
double freq,
|
||||
double bandwidth,
|
||||
double gain,
|
||||
bool agc_enabled,
|
||||
bool rx_bias_tee,
|
||||
unsigned int num_buffers,
|
||||
unsigned int buffer_size,
|
||||
unsigned int num_transfers,
|
||||
unsigned int stream_timeout_ms);
|
||||
|
||||
bladerf_source(
|
||||
const std::string &bladerf_args,
|
||||
const std::string &device_serial,
|
||||
double sample_rate,
|
||||
double freq,
|
||||
double bandwidth,
|
||||
double gain,
|
||||
bool agc_enabled,
|
||||
bool rx_bias_tee,
|
||||
unsigned int num_buffers,
|
||||
unsigned int buffer_size,
|
||||
unsigned int num_transfers,
|
||||
unsigned int stream_timeout_ms);
|
||||
|
||||
struct bladerf_deleter
|
||||
{
|
||||
void operator()(struct bladerf *dev) const;
|
||||
};
|
||||
|
||||
std::unique_ptr<struct bladerf, bladerf_deleter> dev_;
|
||||
std::vector<int16_t> raw_buffer_;
|
||||
unsigned int buffer_size_;
|
||||
unsigned int stream_timeout_ms_;
|
||||
bool streaming_;
|
||||
};
|
||||
|
||||
|
||||
/** \} */
|
||||
/** \} */
|
||||
#endif // GNSS_SDR_BLADERF_SOURCE_H
|
||||
@@ -124,6 +124,10 @@ if(ENABLE_LIMESDR)
|
||||
target_compile_definitions(core_receiver PRIVATE -DLIMESDR_DRIVER=1)
|
||||
endif()
|
||||
|
||||
if(ENABLE_BLADERF)
|
||||
target_compile_definitions(core_receiver PRIVATE -DBLADERF_DRIVER=1)
|
||||
endif()
|
||||
|
||||
if(ENABLE_POCKETSDR)
|
||||
target_compile_definitions(core_receiver PRIVATE -DPOCKETSDR_DRIVER=1)
|
||||
endif()
|
||||
|
||||
@@ -146,6 +146,10 @@
|
||||
#include "limesdr_signal_source.h"
|
||||
#endif
|
||||
|
||||
#if BLADERF_DRIVER
|
||||
#include "bladerf_signal_source.h"
|
||||
#endif
|
||||
|
||||
#if POCKETSDR_DRIVER
|
||||
#include "pocket_sdr_signal_source.h"
|
||||
#endif
|
||||
@@ -348,6 +352,12 @@ std::unique_ptr<SignalSourceInterface> get_signal_source_block(
|
||||
return std::make_unique<LimesdrSignalSource>(configuration, role, in_streams, out_streams, queue);
|
||||
}
|
||||
#endif
|
||||
#if BLADERF_DRIVER
|
||||
else if (implementation == "Bladerf_Signal_Source")
|
||||
{
|
||||
return std::make_unique<BladerfSignalSource>(configuration, role, in_streams, out_streams, queue);
|
||||
}
|
||||
#endif
|
||||
#if POCKETSDR_DRIVER
|
||||
else if (implementation == "Pocket_SDR_Signal_Source")
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user