From 3567468023f43f2a1281cce6dce78670c7dd867f Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 3 Nov 2020 22:11:19 +0100 Subject: [PATCH 01/19] KiwiSDR: fixed issue in local network. Fixes #435 --- plugins/samplesource/kiwisdr/kiwisdrworker.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/samplesource/kiwisdr/kiwisdrworker.cpp b/plugins/samplesource/kiwisdr/kiwisdrworker.cpp index 614454d94..ad93db7dd 100644 --- a/plugins/samplesource/kiwisdr/kiwisdrworker.cpp +++ b/plugins/samplesource/kiwisdr/kiwisdrworker.cpp @@ -86,8 +86,7 @@ void KiwiSDRWorker::onBinaryMessageReceived(const QByteArray &message) if (message[0] == 'M' && message[1] == 'S' && message[2] == 'G') { QStringList al = QString::fromUtf8(message).split(' '); - if (al[1] == "audio_init=0" && - al[2] == "audio_rate=12000") + if (al.size() > 2 && al[2] == "audio_rate=12000") { m_webSocket.sendTextMessage("SET AR OK in=12000 out=48000"); m_webSocket.sendTextMessage("SERVER DE CLIENT KiwiAngel SND"); @@ -157,4 +156,4 @@ void KiwiSDRWorker::onServerAddressChanged(QString serverAddress) void KiwiSDRWorker::tick() { m_webSocket.sendTextMessage("SET keepalive"); -} \ No newline at end of file +} From b67705a625f003f9ed1a3c11848abc49990de4ba Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 3 Nov 2020 23:44:13 +0100 Subject: [PATCH 02/19] Windows build: upgrade to Qt 5.13.2 --- cmake/Modules/QtLocator.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/Modules/QtLocator.cmake b/cmake/Modules/QtLocator.cmake index 72f759ebe..d70bc2e78 100644 --- a/cmake/Modules/QtLocator.cmake +++ b/cmake/Modules/QtLocator.cmake @@ -4,10 +4,10 @@ IF(MSVC) # look for user-registry pointing to qtcreator GET_FILENAME_COMPONENT(QT_BIN [HKEY_CURRENT_USER\\Software\\Classes\\Applications\\QtProject.QtCreator.pro\\shell\\Open\\Command] PATH) - # get root path so we can search for 5.3, 5.4, 5.5, etc + # get root path so we can search for 5.10, 5.11, 5.12, etc STRING(REPLACE "/Tools" ";" QT_BIN "${QT_BIN}") LIST(GET QT_BIN 0 QT_BIN) - FILE(GLOB QT_VERSIONS "${QT_BIN}/5.*") + FILE(GLOB QT_VERSIONS "${QT_BIN}/5.1*") LIST(SORT QT_VERSIONS) # assume the latest version will be last alphabetically @@ -29,7 +29,7 @@ IF(MSVC) set(QT_MSVC 2015) else() MATH(EXPR QT_MSVC "2000 + (${MSVC_VERSION} - 600) / 100") - endif() + endif() # check for 64-bit os # may need to be removed for older compilers as it wasn't always offered From 2a86bc566afe983bd91950731fe1f70815d118a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Sun, 1 Nov 2020 13:01:32 +0100 Subject: [PATCH 03/19] Temporary switch to forks --- .gitmodules | 2 +- external/CMakeLists.txt | 15 +++++++++------ external/windows | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.gitmodules b/.gitmodules index e3dbe3009..77e5c5a7f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "external/windows"] path = external/windows - url = https://github.com/f4exb/sdrangel-windows-libraries.git + url = https://github.com/kasper93/sdrangel-windows-libraries.git diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 275b5d88b..5f8e8a809 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -10,7 +10,7 @@ # which version/tag/checkout to use set(CODEC2_TAG "v0.9.2") set(CM256CC_TAG c0e92b92aca3d1d36c990b642b937c64d363c559) -set(MBELIB_TAG 9a04ed5c78176a9965f3d43f7aa1b1f5330e771f) +set(MBELIB_TAG fe83b32c6a60cdd7bce8cecf3c7a0b9ec87a7667) set(SERIALDV_TAG "v1.1.4") set(DSDCC_TAG "v1.9.0") set(LIMESUITE_TAG "v20.01.0") @@ -219,11 +219,17 @@ endif (NOT APPLE AND (NOT CM256CC_FOUND OR CM256CC_EXTERNAL)) if ((NOT LIBDSDCC_FOUND OR LIBDSDCC_EXTERNAL) AND (NOT LIBMBE_FOUND OR LIBMBE_EXTERNAL)) set(USE_MBELIB OFF) + if (WIN32) + set(LIBMBE_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/libmbe.lib" CACHE INTERNAL "") + elseif (LINUX) + set(LIBMBE_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libmbe${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") + endif () ExternalProject_Add(mbelib - GIT_REPOSITORY https://github.com/szechyjs/mbelib.git + GIT_REPOSITORY https://github.com/kasper93/mbelib.git GIT_TAG ${MBELIB_TAG} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/mbelib" CMAKE_ARGS -DDISABLE_TEST=ON ${DEFAULT_OUTPUT_DIRECTORIES} + BUILD_BYPRODUCTS "${LIBMBE_LIBRARIES}" INSTALL_COMMAND "" TEST_COMMAND "" ) @@ -234,10 +240,7 @@ if ((NOT LIBDSDCC_FOUND OR LIBDSDCC_EXTERNAL) AND (NOT LIBMBE_FOUND OR LIBMBE_EX set(LIBMBE_EXTERNAL ON CACHE INTERNAL "") set(LIBMBE_INCLUDE_DIR "${source_dir}" CACHE INTERNAL "") if (WIN32) - set(LIBMBE_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/mbe.lib" CACHE INTERNAL "") - install(FILES "${SDRANGEL_BINARY_BIN_DIR}/mbe${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") - elseif (LINUX) - set(LIBMBE_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libmbe${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") + install(FILES "${SDRANGEL_BINARY_BIN_DIR}/libmbe${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") elseif (APPLE) set(LIBMBE_LIBRARIES "${binary_dir}/libmbe${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") install(DIRECTORY "${binary_dir}/" DESTINATION "${INSTALL_LIB_DIR}" diff --git a/external/windows b/external/windows index f781c2fa4..fd7d2b7a2 160000 --- a/external/windows +++ b/external/windows @@ -1 +1 @@ -Subproject commit f781c2fa49717ff509fdb82eb50c1c55bd64b41d +Subproject commit fd7d2b7a202631642ced85cf4268ec46987a4d60 From 70434765d7bb726dd829a5b17c188321f0f2b2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Sun, 1 Nov 2020 13:03:13 +0100 Subject: [PATCH 04/19] Add support for VS2019 and Ninja - Specify byproducts in external projects - Use external Boost - Remove hacky Qt detection - Fix CRT mismatch in external projects (fixes SoapySDR on Windows) - Minor fixes --- .appveyor.yml | 41 +-- CMakeLists.txt | 43 ++-- cmake/Modules/DeployQt.cmake | 4 + cmake/Modules/QtLocator.cmake | 48 ---- cmake/ci/build_sdrangel.sh | 21 +- debian/rules | 5 +- devices/plutosdr/CMakeLists.txt | 1 - devices/usrp/CMakeLists.txt | 9 +- external/CMakeLists.txt | 233 +++++++++++------- plugins/channelrx/chanalyzer/CMakeLists.txt | 4 - plugins/channelrx/demodatv/CMakeLists.txt | 1 - plugins/channelrx/demodbfm/CMakeLists.txt | 1 - plugins/channelrx/filesink/CMakeLists.txt | 1 - plugins/channelrx/localsink/CMakeLists.txt | 1 - plugins/channelrx/remotesink/CMakeLists.txt | 1 - plugins/channeltx/localsource/CMakeLists.txt | 1 - plugins/channeltx/mod802.15.4/CMakeLists.txt | 1 - plugins/channeltx/remotesource/CMakeLists.txt | 1 - .../samplesink/remoteoutput/CMakeLists.txt | 1 - plugins/samplesink/usrpoutput/CMakeLists.txt | 5 - plugins/samplesource/kiwisdr/CMakeLists.txt | 1 - .../samplesource/remoteinput/CMakeLists.txt | 1 - plugins/samplesource/usrpinput/CMakeLists.txt | 5 - sdrbase/CMakeLists.txt | 2 +- sdrbase/ambe/ambeengine.cpp | 6 +- sdrbase/ambe/ambeengine.h | 2 +- sdrbase/util/serialutil.cpp | 4 +- sdrgui/CMakeLists.txt | 1 - 28 files changed, 201 insertions(+), 244 deletions(-) delete mode 100644 cmake/Modules/QtLocator.cmake mode change 100644 => 100755 cmake/ci/build_sdrangel.sh diff --git a/.appveyor.yml b/.appveyor.yml index ed3fd8934..b798601d2 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -9,36 +9,41 @@ matrix: fast_finish: false environment: -# my_variable: -# secure: kyU5TaXRoily6q/QLRLqal2xCFGWEdnb8AJIu7FknsUQyj1wjRGmqC2My+Wfszod matrix: - - TARGET: vs2017gui - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' - # RelWithDebInfo + - TARGET: vs2019gui + APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2019' configuration: Release - # CMAKE_CUSTOM_OPTIONS: "-DENABLE_EXTERNAL_LIBRARIES=OFF" - CMAKE_CUSTOM_OPTIONS: "-DFORCE_SSE41=ON -DQT_MISSING=OFF -DDEBUG_OUTPUT=ON -DENABLE_MIRISDR=OFF -DBUILD_SERVER=OFF" - CMAKE_GENERATOR: "Visual Studio 15 2017 Win64" + CMAKE_CUSTOM_OPTIONS: "-DCMAKE_BUILD_TYPE=Release \ + -DFORCE_SSE41=ON \ + -DDEBUG_OUTPUT=ON \ + -DENABLE_MIRISDR=OFF \ + -DBUILD_SERVER=OFF \ + -DCMAKE_PREFIX_PATH=C:\\Qt\\5.15.1\\msvc2019_64;C:\\Libraries\\boost_1_73_0" + CMAKE_GENERATOR: Ninja - TARGET: ubuntu2004prod APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu2004 - CMAKE_CUSTOM_OPTIONS: "-DFORCE_SSE41=ON -DDEBUG_OUTPUT=ON -DENABLE_EXTERNAL_LIBRARIES=ON" + CC: "gcc-9" + CXX: "g++-9" + CMAKE_CUSTOM_OPTIONS: "-DCMAKE_BUILD_TYPE=Release \ + -DFORCE_SSE41=ON \ + -DDEBUG_OUTPUT=ON \ + -DENABLE_EXTERNAL_LIBRARIES=ON" -# image: -# - &linux Ubuntu1804 -# - matrix: { only: [ image: *linux ] } for: - matrix: only: - - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' + - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2019' cache: - C:\ProgramData\chocolatey\bin - C:\ProgramData\chocolatey\lib - #- C:\Tools\vcpkg\installed build_script: + - call "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" + # Install GNU patch as applying patches with git fails in BladeRF tree + - choco install patch - git submodule update --init --recursive - mkdir build && cd build - - cmake ..\ -G "%CMAKE_GENERATOR%" %CMAKE_CUSTOM_OPTIONS% - - cmake --build . --config Release --target PACKAGE + - cmake .. -G "%CMAKE_GENERATOR%" %CMAKE_CUSTOM_OPTIONS% + - cmake --build . --config Release --target package artifacts: # push installer executable path: build\*.exe name: installer @@ -76,7 +81,7 @@ for: libopus-dev libcodec2-dev libairspy-dev libhackrf-dev \ libbladerf-dev libsoapysdr-dev libiio-dev libuhd-dev \ python3-mako python3-cheetah python3-numpy \ - autoconf automake libtool + autoconf automake libtool ninja-build - sh: if [[ ! "${CMAKE_CUSTOM_OPTIONS}" =~ "ENABLE_EXTERNAL_LIBRARIES=ON" ]]; then bash cmake/ci/build_cm256cc.sh; fi - sh: if [[ ! "${CMAKE_CUSTOM_OPTIONS}" =~ "ENABLE_EXTERNAL_LIBRARIES=ON" ]]; then bash cmake/ci/build_mbelib.sh; fi - sh: if [[ ! "${CMAKE_CUSTOM_OPTIONS}" =~ "ENABLE_EXTERNAL_LIBRARIES=ON" ]]; then bash cmake/ci/build_serialdv.sh; fi @@ -90,7 +95,7 @@ for: - sh: bash -c export - sh: bash -c pwd build_script: - - sh: bash cmake/ci/build_sdrangel.sh + - sh: ./cmake/ci/build_sdrangel.sh test_script: # debian build path - sh: ./obj-x86_64-linux-gnu/sdrangelbench diff --git a/CMakeLists.txt b/CMakeLists.txt index f64c31ac0..b87aa5052 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,6 @@ -cmake_minimum_required(VERSION 3.1.0) +cmake_minimum_required(VERSION 3.16.0) -# force 64bit on windows because we have only that library -# TODO discuss because, at this days, a dsp software should be 64bit -# if(WIN32 AND NOT CMAKE_GENERATOR_PLATFORM AND NOT CMAKE_C_COMPILER AND NOT CMAKE_CXX_COMPILER) -# set(CMAKE_GENERATOR_PLATFORM "x64" CACHE INTERNAL "") -# endif() +set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") project(sdrangel) @@ -192,39 +188,35 @@ elseif(APPLE) "${CMAKE_BINARY_DIR}/Info.plist" @ONLY) elseif (WIN32) # check compiler version - if(MSVC_VERSION GREATER 1910 AND MSVC_VERSION LESS 1919) + if(MSVC_VERSION GREATER 1920 AND MSVC_VERSION LESS 1929) + set(VS2019 ON) + elseif(MSVC_VERSION GREATER 1910 AND MSVC_VERSION LESS 1919) set(VS2017 ON) elseif(MSVC_VERSION GREATER 1899 AND MSVC_VERSION LESS 1910) set(VS2015 ON) endif() - if(NOT VS2015 AND NOT VS2017) - message(FATAL_ERROR "You must use Microsoft Visual Studio 2015 or 2017 as compiler") + if(NOT VS2015 AND NOT VS2017 AND NOT VS2019) + message(FATAL_ERROR "You must use Microsoft Visual Studio 2015, 2017 or 2019 as compiler") endif() - # used on code but not defined on VS2017 - add_definitions(-D__WINDOWS__) - # compile with full multicore - set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} /MP /w") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /w") - - # find Qt folder - if(DEFINED QT_PATH) - set (QT_MISSING False) + if(MSVC) + add_compile_definitions(/MP) endif() - include(QtLocator) # in alternative we can use ExternalProject set(EXTERNAL_LIBRARY_FOLDER "${CMAKE_SOURCE_DIR}/external/windows") - set(BOOST_ROOT "${EXTERNAL_LIBRARY_FOLDER}/boost" CACHE INTERNAL "") - set(BOOST_LIBRARYDIR "${EXTERNAL_LIBRARY_FOLDER}/boost/lib64-msvc-14.1" CACHE INTERNAL "") set(FFTW3F_FOUND ON CACHE INTERNAL "") set(FFTW3F_INCLUDE_DIRS "${EXTERNAL_LIBRARY_FOLDER}/fftw-3/include" CACHE INTERNAL "") set(FFTW3F_LIBRARIES "${EXTERNAL_LIBRARY_FOLDER}/fftw-3/libfftw3f-3.lib" CACHE INTERNAL "") set(LIBUSB_INCLUDE_DIR "${EXTERNAL_LIBRARY_FOLDER}/libusb/include" CACHE INTERNAL "") set(LIBUSB_LIBRARIES "${EXTERNAL_LIBRARY_FOLDER}/libusb/MS64/dll/libusb-1.0.lib" CACHE INTERNAL "") - set(OpenCV_DIR "${EXTERNAL_LIBRARY_FOLDER}/opencv" CACHE INTERNAL "") + if(VS2019) + set(OpenCV_DIR "${EXTERNAL_LIBRARY_FOLDER}/opencv4" CACHE INTERNAL "") + else() + set(OpenCV_DIR "${EXTERNAL_LIBRARY_FOLDER}/opencv" CACHE INTERNAL "") + endif() set(PKG_CONFIG_EXECUTABLE "${EXTERNAL_LIBRARY_FOLDER}/pkg-config-lite/bin/pkg-config.exe" CACHE INTERNAL "") set(SOAPYSUPPORT_DIR "${EXTERNAL_LIBRARY_FOLDER}/soapysdr-support" CACHE INTERNAL "") @@ -260,7 +252,6 @@ elseif (WIN32) # used on fixup_bundle phase set(WINDOWS_FIXUP_BUNDLE_LIB_DIRS - "${Qt5_DIR}../../../bin" "${EXTERNAL_LIBRARY_FOLDER}/fftw-3" "${EXTERNAL_LIBRARY_FOLDER}/libusb/MS64/dll" "${EXTERNAL_LIBRARY_FOLDER}/ffmpeg/bin" @@ -371,11 +362,7 @@ if(WIN32) set(OpenCV_ARCH "86") endif() - if(VS2015) - set(OpenCV_LIBS_BIN_DIR "${OpenCV_DIR}/x${OpenCV_ARCH}/vc14/bin" CACHE INTERNAL "") - elseif(VS2017) - set(OpenCV_LIBS_BIN_DIR "${OpenCV_DIR}/x${OpenCV_ARCH}/vc15/bin" CACHE INTERNAL "") - endif() + set(OpenCV_LIBS_BIN_DIR "${OpenCV_DIR}/x${OpenCV_ARCH}/${OpenCV_RUNTIME}/bin" CACHE INTERNAL "") set(WINDOWS_FIXUP_BUNDLE_LIB_DIRS "${WINDOWS_FIXUP_BUNDLE_LIB_DIRS}" diff --git a/cmake/Modules/DeployQt.cmake b/cmake/Modules/DeployQt.cmake index d8a1d2d79..d302cf203 100644 --- a/cmake/Modules/DeployQt.cmake +++ b/cmake/Modules/DeployQt.cmake @@ -25,6 +25,8 @@ function(windeployqt target bindir qmldir) --dir "${bindir}" --qmldir "${qmldir}" --multimedia + --websockets + --opengl \"$\" COMMENT "Deploying Qt..." ) @@ -38,6 +40,8 @@ function(windeployqt target bindir qmldir) --dir "${bindir}/winqt" --qmldir "${qmldir}" --multimedia + --websockets + --opengl \"$\" COMMENT "Deploying Qt..." ) diff --git a/cmake/Modules/QtLocator.cmake b/cmake/Modules/QtLocator.cmake deleted file mode 100644 index d70bc2e78..000000000 --- a/cmake/Modules/QtLocator.cmake +++ /dev/null @@ -1,48 +0,0 @@ -SET(QT_MISSING True) -# msvc only; mingw will need different logic -IF(MSVC) - # look for user-registry pointing to qtcreator - GET_FILENAME_COMPONENT(QT_BIN [HKEY_CURRENT_USER\\Software\\Classes\\Applications\\QtProject.QtCreator.pro\\shell\\Open\\Command] PATH) - - # get root path so we can search for 5.10, 5.11, 5.12, etc - STRING(REPLACE "/Tools" ";" QT_BIN "${QT_BIN}") - LIST(GET QT_BIN 0 QT_BIN) - FILE(GLOB QT_VERSIONS "${QT_BIN}/5.1*") - LIST(SORT QT_VERSIONS) - - # assume the latest version will be last alphabetically - LIST(REVERSE QT_VERSIONS) - - LIST(GET QT_VERSIONS 0 QT_VERSION) - - # fix any double slashes which seem to be common - STRING(REPLACE "//" "/" QT_VERSION "${QT_VERSION}") - - # do some math trickery to guess folder - # - qt uses (e.g.) "msvc2012" - # - cmake uses (e.g.) "1800" - # - see also https://cmake.org/cmake/help/v3.0/variable/MSVC_VERSION.html - # checkcompiler version - if(MSVC_VERSION GREATER 1910 AND MSVC_VERSION LESS 1919) - set(QT_MSVC 2017) - elseif(MSVC_VERSION GREATER 1899 AND MSVC_VERSION LESS 1910) - set(QT_MSVC 2015) - else() - MATH(EXPR QT_MSVC "2000 + (${MSVC_VERSION} - 600) / 100") - endif() - - # check for 64-bit os - # may need to be removed for older compilers as it wasn't always offered - IF(CMAKE_SYSTEM_PROCESSOR MATCHES 64) - SET(QT_MSVC "${QT_MSVC}_64") - ENDIF() - SET(QT_PATH "${QT_VERSION}/msvc${QT_MSVC}") - SET(QT_MISSING False) -ENDIF() - -# use Qt_DIR approach so you can find Qt after cmake has been invoked -IF(NOT QT_MISSING) - MESSAGE("-- Qt found: ${QT_PATH}") - SET(Qt5_DIR "${QT_PATH}/lib/cmake/Qt5/") - SET(Qt5Test_DIR "${QT_PATH}/lib/cmake/Qt5Test") -ENDIF() diff --git a/cmake/ci/build_sdrangel.sh b/cmake/ci/build_sdrangel.sh old mode 100644 new mode 100755 index d42142561..8ea5358b3 --- a/cmake/ci/build_sdrangel.sh +++ b/cmake/ci/build_sdrangel.sh @@ -1,26 +1,17 @@ -#!/bin/sh - -if [ "${TRAVIS_OS_NAME}" == "osx" ]; then - JOBS=$(sysctl -n hw.ncpu) -elif [ "${TRAVIS_OS_NAME}" == "linux" ] || [ ${CI_LINUX} = true ]; then - JOBS=$(nproc --all) -else - JOBS=1 -fi - +#!/bin/sh -e if [ "${TRAVIS_OS_NAME}" == "linux" ] || [ ${CI_LINUX} = true ]; then debuild -i -us -uc -b else - mkdir build && cd build - cmake .. "${CMAKE_CUSTOM_OPTIONS}" + mkdir -p build; cd build + cmake .. -GNinja ${CMAKE_CUSTOM_OPTIONS} case "${CMAKE_CUSTOM_OPTIONS}" in *BUNDLE=ON*) - make -j${JOBS} package + cmake --build . --target package ;; *) - make -j${JOBS} + cmake --build . ;; - esac + esac fi diff --git a/debian/rules b/debian/rules index b73828347..c131bc0e1 100755 --- a/debian/rules +++ b/debian/rules @@ -1,11 +1,14 @@ #!/usr/bin/make -f %: - dh $@ --parallel + dh $@ --parallel --buildsystem=cmake+ninja # FORCE_SSE41 will be not accepted upstream override_dh_auto_configure: dh_auto_configure -- -DFORCE_SSE41=ON -DENABLE_EXTERNAL_LIBRARIES=ON -DDEBUG_OUTPUT=ON +override_dh_auto_test: + echo "Skipping test step" + # permit the packaging with /usr/local/lib libraries (from `make install`) # you can also use `export DEB_DH_SHLIBDEPS_ARGS_ALL=--dpkg-shlibdeps-params=--ignore-missing-info` # not a good idea! diff --git a/devices/plutosdr/CMakeLists.txt b/devices/plutosdr/CMakeLists.txt index db56a61d0..4a58a5b33 100644 --- a/devices/plutosdr/CMakeLists.txt +++ b/devices/plutosdr/CMakeLists.txt @@ -19,7 +19,6 @@ set(plutosdrdevice_HEADERS include_directories( ${LIBIIO_INCLUDE_DIR} ${ICONV_INCLUDE_DIR} - ${Boost_INCLUDE_DIRS} ) add_library(plutosdrdevice SHARED diff --git a/devices/usrp/CMakeLists.txt b/devices/usrp/CMakeLists.txt index 31803536f..ce6fd890f 100644 --- a/devices/usrp/CMakeLists.txt +++ b/devices/usrp/CMakeLists.txt @@ -1,8 +1,3 @@ -if(WIN32) - # ${Boost_LIBRARY_DIRS} is empty on windows - link_directories(${BOOST_LIBRARYDIR}) -endif() - project(usrpdevice) @@ -20,7 +15,6 @@ set(usrpdevice_HEADERS include_directories( ${UHD_INCLUDE_DIR} - ${Boost_INCLUDE_DIRS} ) add_library(usrpdevice SHARED @@ -30,10 +24,9 @@ add_library(usrpdevice SHARED set_target_properties(usrpdevice PROPERTIES DEFINE_SYMBOL "devices_EXPORTS") -link_directories(${Boost_LIBRARY_DIRS}) - target_link_libraries(usrpdevice ${UHD_LIBRARIES} + Boost::disable_autolinking sdrbase ) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 5f8e8a809..63d515b57 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -37,7 +37,7 @@ include(ExternalProject) # default build destination in windows to avoid Release/Debug folder if (WIN32) # the build will be output on the same folder of sdrangel - set(DEFAULT_OUTPUT_DIRECTORIES + set(COMMON_CMAKE_ARGS -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${SDRANGEL_BINARY_BIN_DIR} -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG=${SDRANGEL_BINARY_BIN_DIR} -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE=${SDRANGEL_BINARY_BIN_DIR} @@ -52,7 +52,7 @@ if (WIN32) -DCMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO=${SDRANGEL_BINARY_LIB_DIR} ) elseif (LINUX) - set(DEFAULT_OUTPUT_DIRECTORIES + set(COMMON_CMAKE_ARGS -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${EXTERNAL_BUILD_LIBRARIES}/bin -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG=${EXTERNAL_BUILD_LIBRARIES}/bin -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE=${EXTERNAL_BUILD_LIBRARIES}/bin @@ -68,6 +68,19 @@ elseif (LINUX) ) endif () +if(CMAKE_MSVC_RUNTIME_LIBRARY) + list(APPEND COMMON_CMAKE_ARGS -DCMAKE_POLICY_DEFAULT_CMP0091:STRING=NEW) + list(APPEND COMMON_CMAKE_ARGS -DCMAKE_MSVC_RUNTIME_LIBRARY=${CMAKE_MSVC_RUNTIME_LIBRARY}) +endif() + +if(CMAKE_BUILD_TYPE) + list(APPEND COMMON_CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}) +endif() + +list(APPEND COMMON_CMAKE_ARGS -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}) +list(APPEND COMMON_CMAKE_ARGS -DCMAKE_CXX_STANDARD_REQUIRED=${CMAKE_CXX_STANDARD_REQUIRED}) +list(APPEND COMMON_CMAKE_ARGS -DCMAKE_CXX_EXTENSIONS=${CMAKE_CXX_EXTENSIONS}) + if (LINUX) # macro that create symbolic links macro(makeLink src dest target) @@ -159,11 +172,17 @@ endif (AUTO_EXTERNAL_LIBRARIES) if (NOT WIN32 AND (NOT CODEC2_FOUND OR CODEC2_EXTERNAL)) # needs speexdsp + if (WIN32) + set(CODEC2_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/codec2.lib" CACHE INTERNAL "") + elseif (LINUX) + set(CODEC2_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libcodec2${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") + endif () ExternalProject_Add(codec2 GIT_REPOSITORY https://github.com/drowe67/codec2.git GIT_TAG ${CODEC2_TAG} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/codec2" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} + CMAKE_ARGS ${COMMON_CMAKE_ARGS} + BUILD_BYPRODUCTS "${CODEC2_LIBRARIES}" INSTALL_COMMAND "" TEST_COMMAND "" ) @@ -186,16 +205,22 @@ endif (NOT WIN32 AND (NOT CODEC2_FOUND OR CODEC2_EXTERNAL)) if (NOT APPLE AND (NOT CM256CC_FOUND OR CM256CC_EXTERNAL)) # needs boost + if (WIN32) + set(CM256CC_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/cm256cc.lib" CACHE INTERNAL "") + elseif (LINUX) + set(CM256CC_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libcm256cc${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") + endif () + string(REPLACE ";" "|" CMAKE_PREFIX_PATH_SEP "${CMAKE_PREFIX_PATH}") ExternalProject_Add(cm256cc GIT_REPOSITORY https://github.com/f4exb/cm256cc.git GIT_TAG ${CM256CC_TAG} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/cm256cc" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} + LIST_SEPARATOR | + CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DBUILD_TOOLS=OFF - -DBOOST_ROOT="${BOOST_ROOT}" - -DBoost_INCLUDE_DIR=${Boost_INCLUDE_DIRS} - -DBoost_INCLUDE_DIRS=${Boost_INCLUDE_DIRS} + -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH_SEP} -DENABLE_DISTRIBUTION=ON + BUILD_BYPRODUCTS "${CM256CC_LIBRARIES}" INSTALL_COMMAND "" TEST_COMMAND "" ) @@ -205,10 +230,7 @@ if (NOT APPLE AND (NOT CM256CC_FOUND OR CM256CC_EXTERNAL)) # we need cm256cc/library.h set(CM256CC_INCLUDE_DIR "${EXTERNAL_BUILD_LIBRARIES}/cm256cc/src" CACHE INTERNAL "") if (WIN32) - set(CM256CC_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/cm256cc.lib" CACHE INTERNAL "") install(FILES "${SDRANGEL_BINARY_BIN_DIR}/cm256cc${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") - elseif (LINUX) - set(CM256CC_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libcm256cc${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") elseif (APPLE) # kept in case of relaxation of APPLE exclusion set(CM256CC_LIBRARIES "${binary_dir}/libcm256cc${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") install(DIRECTORY "${binary_dir}/" DESTINATION "${INSTALL_LIB_DIR}" @@ -228,7 +250,7 @@ if ((NOT LIBDSDCC_FOUND OR LIBDSDCC_EXTERNAL) AND (NOT LIBMBE_FOUND OR LIBMBE_EX GIT_REPOSITORY https://github.com/kasper93/mbelib.git GIT_TAG ${MBELIB_TAG} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/mbelib" - CMAKE_ARGS -DDISABLE_TEST=ON ${DEFAULT_OUTPUT_DIRECTORIES} + CMAKE_ARGS -DDISABLE_TEST=ON ${COMMON_CMAKE_ARGS} BUILD_BYPRODUCTS "${LIBMBE_LIBRARIES}" INSTALL_COMMAND "" TEST_COMMAND "" @@ -251,12 +273,17 @@ endif ((NOT LIBDSDCC_FOUND OR LIBDSDCC_EXTERNAL) AND (NOT LIBMBE_FOUND OR LIBMBE if (NOT LIBSERIALDV_FOUND OR LIBSERIALDV_EXTERNAL) # Works on MacOS with a dummy serialDV + if (WIN32) + set(LIBSERIALDV_LIBRARY "${SDRANGEL_BINARY_LIB_DIR}/serialdv.lib" CACHE INTERNAL "") + elseif (LINUX) + set(LIBSERIALDV_LIBRARY "${EXTERNAL_BUILD_LIBRARIES}/lib/libserialdv${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") + endif () ExternalProject_Add(serialdv GIT_REPOSITORY https://github.com/f4exb/serialDV.git GIT_TAG ${SERIALDV_TAG} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/serialdv" - CMAKE_ARGS -DBUILD_TOOL=OFF ${DEFAULT_OUTPUT_DIRECTORIES} - INSTALL_COMMAND "" + CMAKE_ARGS -DBUILD_TOOL=OFF ${COMMON_CMAKE_ARGS} + BUILD_BYPRODUCTS "${LIBSERIALDV_LIBRARY}" INSTALL_COMMAND "" TEST_COMMAND "" ) @@ -266,11 +293,9 @@ if (NOT LIBSERIALDV_FOUND OR LIBSERIALDV_EXTERNAL) set(LIBSERIALDV_EXTERNAL ON CACHE INTERNAL "") set(LIBSERIALDV_INCLUDE_DIR "${source_dir}" CACHE INTERNAL "") if (WIN32) - set(LIBSERIALDV_LIBRARY "${SDRANGEL_BINARY_LIB_DIR}/serialdv.lib" CACHE INTERNAL "") makeCopyDir("${source_dir}" "${source_dir}/dsp" serialdv) install(FILES "${SDRANGEL_BINARY_BIN_DIR}/serialdv${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") elseif (LINUX) - set(LIBSERIALDV_LIBRARY "${EXTERNAL_BUILD_LIBRARIES}/lib/libserialdv${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") # because sdrbase/dsp/dvserialworker.h use dsp/dvcontroller.h # so we need a link makeLink("${source_dir}" "${source_dir}/dsp" serialdv) @@ -286,17 +311,23 @@ if (NOT LIBSERIALDV_FOUND OR LIBSERIALDV_EXTERNAL) endif (NOT LIBSERIALDV_FOUND OR LIBSERIALDV_EXTERNAL) if ((NOT LIBDSDCC_FOUND OR LIBDSDCC_EXTERNAL) AND LIBMBE_FOUND) + if (WIN32) + set(LIBDSDCC_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/dsdcc.lib" CACHE INTERNAL "") + elseif (LINUX) + set(LIBDSDCC_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libdsdcc${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") + endif () ExternalProject_Add(dsdcc GIT_REPOSITORY https://github.com/f4exb/dsdcc.git GIT_TAG ${DSDCC_TAG} DEPENDS ${DSDCC_DEPENDS} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/dsdcc" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} + CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DBUILD_TOOL=OFF -DUSE_MBELIB=${USE_MBELIB} -DLIBMBE_INCLUDE_DIR=${LIBMBE_INCLUDE_DIR} -DLIBMBE_LIBRARY=${LIBMBE_LIBRARIES} -DLIBSERIALDV_INCLUDE_DIR=${LIBSERIALDV_INCLUDE_DIR} -DLIBSERIALDV_LIBRARY=${LIBSERIALDV_LIBRARY} + BUILD_BYPRODUCTS "${LIBDSDCC_LIBRARIES}" INSTALL_COMMAND "" TEST_COMMAND "" ) @@ -305,10 +336,7 @@ if ((NOT LIBDSDCC_FOUND OR LIBDSDCC_EXTERNAL) AND LIBMBE_FOUND) set(LIBDSDCC_EXTERNAL ON CACHE INTERNAL "") set(LIBDSDCC_INCLUDE_DIR "${EXTERNAL_BUILD_LIBRARIES}/dsdcc/src" CACHE INTERNAL "") if (WIN32) - set(LIBDSDCC_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/dsdcc.lib" CACHE INTERNAL "") install(FILES "${SDRANGEL_BINARY_BIN_DIR}/dsdcc${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") - elseif (LINUX) - set(LIBDSDCC_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libdsdcc${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") elseif (APPLE) set(LIBDSDCC_LIBRARIES "${binary_dir}/libdsdcc${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") install(DIRECTORY "${binary_dir}/" DESTINATION "${INSTALL_LIB_DIR}" @@ -347,134 +375,142 @@ if (LINUX) # apt install liblimesuite-dev (only on ubuntu 18.04). Can be picky on version though so let's build it. # needs pkgconfig and libusb if (NOT LIMESUITE_FOUND OR LIMESUITE_EXTERNAL) - ExternalProject_Add(limesuite - GIT_REPOSITORY https://github.com/myriadrf/LimeSuite.git - GIT_TAG ${LIMESUITE_TAG} - PREFIX "${EXTERNAL_BUILD_LIBRARIES}/limesuite" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} -DLIME_SUITE_EXTVER=release -DENABLE_GUI=OFF -DENABLE_NOVENARF7=OFF -DENABLE_SOAPY_LMS7=OFF -DENABLE_OCTAVE=OFF -DENABLE_SIMD_FLAGS=SSE3 - INSTALL_COMMAND "" - TEST_COMMAND "" - ) - ExternalProject_Get_Property(limesuite source_dir) set(LIMESUITE_FOUND ON CACHE INTERNAL "") set(LIMESUITE_EXTERNAL ON CACHE INTERNAL "") set(LIMESUITE_INCLUDE_DIR "${EXTERNAL_BUILD_LIBRARIES}/limesuite/src/limesuite/src" CACHE INTERNAL "") set(LIMESUITE_LIBRARY "${EXTERNAL_BUILD_LIBRARIES}/lib/libLimeSuite.so" CACHE INTERNAL "") + ExternalProject_Add(limesuite + GIT_REPOSITORY https://github.com/myriadrf/LimeSuite.git + GIT_TAG ${LIMESUITE_TAG} + PREFIX "${EXTERNAL_BUILD_LIBRARIES}/limesuite" + CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DLIME_SUITE_EXTVER=release -DENABLE_GUI=OFF -DENABLE_NOVENARF7=OFF -DENABLE_SOAPY_LMS7=OFF -DENABLE_OCTAVE=OFF -DENABLE_SIMD_FLAGS=SSE3 + BUILD_BYPRODUCTS "${LIMESUITE_LIBRARY}" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) + ExternalProject_Get_Property(limesuite source_dir) makeCopyFile("${source_dir}/src/limeRFE/limeRFE.h" "${source_dir}/src/lime/limeRFE.h" limesuite) endif (NOT LIMESUITE_FOUND OR LIMESUITE_EXTERNAL) # apt install libbladerf-dev # needs pkgconfig and libusb if (NOT LIBBLADERF_FOUND OR LIBBLADERF_EXTERNAL) + set(LIBBLADERF_FOUND ON CACHE INTERNAL "") + set(LIBBLADERF_EXTERNAL ON CACHE INTERNAL "") + set(LIBBLADERF_INCLUDE_DIRS "${EXTERNAL_BUILD_LIBRARIES}/bladerf/src/bladerf/host/libraries/libbladeRF/include" CACHE INTERNAL "") + set(LIBBLADERF_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/bladerf/src/bladerf-build/output/libbladeRF.so.2" CACHE INTERNAL "") ExternalProject_Add(bladerf GIT_REPOSITORY https://github.com/Nuand/bladeRF.git GIT_TAG ${BLADERF_TAG} GIT_SUBMODULES PREFIX "${EXTERNAL_BUILD_LIBRARIES}/bladerf" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} + CMAKE_ARGS ${COMMON_CMAKE_ARGS} SOURCE_SUBDIR host/ + BUILD_BYPRODUCTS "${LIBBLADERF_LIBRARIES}" INSTALL_COMMAND "" TEST_COMMAND "" ) - set(LIBBLADERF_FOUND ON CACHE INTERNAL "") - set(LIBBLADERF_EXTERNAL ON CACHE INTERNAL "") - set(LIBBLADERF_INCLUDE_DIRS "${EXTERNAL_BUILD_LIBRARIES}/bladerf/src/bladerf/host/libraries/libbladeRF/include" CACHE INTERNAL "") - set(LIBBLADERF_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libbladeRF.so" CACHE INTERNAL "") + install(FILES "${LIBBLADERF_LIBRARIES}" DESTINATION "${INSTALL_LIB_DIR}") endif (NOT LIBBLADERF_FOUND OR LIBBLADERF_EXTERNAL) # apt install libiio-dev # needs pkgconfig, libusb, libxml2, lzma, xz, libiconv if (NOT LIBIIO_FOUND OR LIBIIO_EXTERNAL) - ExternalProject_Add(libiio - GIT_REPOSITORY https://github.com/analogdevicesinc/libiio.git - GIT_TAG ${LIBIIO_TAG} - PREFIX "${EXTERNAL_BUILD_LIBRARIES}/libiio" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} -DOSX_PACKAGE=OFF -DWITH_DOC=OFF - INSTALL_COMMAND "" - TEST_COMMAND "" - ) set(LIBIIO_FOUND ON CACHE INTERNAL "") set(LIBIIO_EXTERNAL ON CACHE INTERNAL "") set(LIBIIO_INCLUDE_DIR "${EXTERNAL_BUILD_LIBRARIES}/libiio/src/libiio" CACHE INTERNAL "") set(LIBIIO_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libiio.so" CACHE INTERNAL "") + ExternalProject_Add(libiio + GIT_REPOSITORY https://github.com/analogdevicesinc/libiio.git + GIT_TAG ${LIBIIO_TAG} + PREFIX "${EXTERNAL_BUILD_LIBRARIES}/libiio" + CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DOSX_PACKAGE=OFF -DWITH_DOC=OFF + BUILD_BYPRODUCTS "${LIBIIO_LIBRARIES}" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) endif (NOT LIBIIO_FOUND OR LIBIIO_EXTERNAL) # apt install libairspyhf-dev (only on ubuntu 18.04) # needs libusb and pkgconfig if (NOT LIBAIRSPYHF_FOUND OR LIBAIRSPYHF_EXTERNAL) + set(LIBAIRSPYHF_FOUND ON CACHE INTERNAL "") + set(LIBAIRSPYHF_EXTERNAL ON CACHE INTERNAL "") + set(LIBAIRSPYHF_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libairspyhf.so" CACHE INTERNAL "") ExternalProject_Add(airspyhf GIT_REPOSITORY https://github.com/airspy/airspyhf.git GIT_TAG ${AIRSPYHF_TAG} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/airspyhf" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} + CMAKE_ARGS ${COMMON_CMAKE_ARGS} + BUILD_BYPRODUCTS "${LIBAIRSPYHF_LIBRARIES}" INSTALL_COMMAND "" TEST_COMMAND "" ) ExternalProject_Get_Property(airspyhf source_dir) - set(LIBAIRSPYHF_FOUND ON CACHE INTERNAL "") - set(LIBAIRSPYHF_EXTERNAL ON CACHE INTERNAL "") set(LIBAIRSPYHF_INCLUDE_DIR "${source_dir}/.." CACHE INTERNAL "") - set(LIBAIRSPYHF_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libairspyhf.so" CACHE INTERNAL "") makeLink("${source_dir}/libairspyhf/src" "${source_dir}/../libairspyhf" airspyhf) endif (NOT LIBAIRSPYHF_FOUND OR LIBAIRSPYHF_EXTERNAL) # needs pkgconfig, libusb, autoconf, automake and libtool if (NOT LIBPERSEUS_FOUND OR LIBPERSEUS_EXTERNAL) - ExternalProject_Add(perseus - GIT_REPOSITORY https://github.com/f4exb/libperseus-sdr.git - GIT_TAG ${PERSEUS_TAG} - PREFIX "${EXTERNAL_BUILD_LIBRARIES}/perseus" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} - INSTALL_COMMAND "" - TEST_COMMAND "" - ) set(LIBPERSEUS_FOUND ON CACHE INTERNAL "") set(LIBPERSEUS_EXTERNAL ON CACHE INTERNAL "") set(LIBPERSEUS_INCLUDE_DIR "${EXTERNAL_BUILD_LIBRARIES}/perseus/src/perseus" CACHE INTERNAL "") set(LIBPERSEUS_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libperseus-sdr.so" CACHE INTERNAL "") + ExternalProject_Add(perseus + GIT_REPOSITORY https://github.com/f4exb/libperseus-sdr.git + GIT_TAG ${PERSEUS_TAG} + PREFIX "${EXTERNAL_BUILD_LIBRARIES}/perseus" + CMAKE_ARGS ${COMMON_CMAKE_ARGS} + BUILD_BYPRODUCTS "${LIBPERSEUS_LIBRARIES}" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) endif (NOT LIBPERSEUS_FOUND OR LIBPERSEUS_EXTERNAL) # apt install librtlsdr-dev # needs pkgconfig and libusb if (NOT LIBRTLSDR_FOUND OR LIBRTLSDR_EXTERNAL) - ExternalProject_Add(rtlsdr - GIT_REPOSITORY https://github.com/osmocom/rtl-sdr.git - GIT_TAG ${RTLSDR_TAG} - PREFIX "${EXTERNAL_BUILD_LIBRARIES}/rtlsdr" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} -DDETACH_KERNEL_DRIVER=ON -DINSTALL_UDEV_RULES=${RTLSDR_UDEV} - INSTALL_COMMAND "" - TEST_COMMAND "" - ) set(LIBRTLSDR_FOUND ON CACHE INTERNAL "") set(LIBRTLSDR_EXTERNAL ON CACHE INTERNAL "") set(LIBRTLSDR_INCLUDE_DIR "${EXTERNAL_BUILD_LIBRARIES}/rtlsdr/src/rtlsdr/include" CACHE INTERNAL "") set(LIBRTLSDR_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/librtlsdr.so" CACHE INTERNAL "") + ExternalProject_Add(rtlsdr + GIT_REPOSITORY https://github.com/osmocom/rtl-sdr.git + GIT_TAG ${RTLSDR_TAG} + PREFIX "${EXTERNAL_BUILD_LIBRARIES}/rtlsdr" + CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DDETACH_KERNEL_DRIVER=ON -DINSTALL_UDEV_RULES=${RTLSDR_UDEV} + BUILD_BYPRODUCTS "${LIBRTLSDR_LIBRARIES}" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) endif (NOT LIBRTLSDR_FOUND OR LIBRTLSDR_EXTERNAL) # needs pkgconfig and libusb if (NOT LIBMIRISDR_FOUND OR LIBMIRISDR_EXTERNAL) - ExternalProject_Add(libmirisdr - GIT_REPOSITORY https://github.com/f4exb/libmirisdr-4.git - GIT_TAG ${MIRISDR_TAG} - PREFIX "${EXTERNAL_BUILD_LIBRARIES}/libmirisdr" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} - INSTALL_COMMAND "" - TEST_COMMAND "" - ) set(LIBMIRISDR_FOUND ON CACHE INTERNAL "") set(LIBMIRISDR_EXTERNAL ON CACHE INTERNAL "") set(LIBMIRISDR_INCLUDE_DIR "${EXTERNAL_BUILD_LIBRARIES}/libmirisdr/src/libmirisdr/include" CACHE INTERNAL "") set(LIBMIRISDR_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libmirisdr.so" CACHE INTERNAL "") + ExternalProject_Add(libmirisdr + GIT_REPOSITORY https://github.com/f4exb/libmirisdr-4.git + GIT_TAG ${MIRISDR_TAG} + PREFIX "${EXTERNAL_BUILD_LIBRARIES}/libmirisdr" + CMAKE_ARGS ${COMMON_CMAKE_ARGS} + BUILD_BYPRODUCTS "${LIBMIRISDR_LIBRARIES}" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) endif (NOT LIBMIRISDR_FOUND OR LIBMIRISDR_EXTERNAL) endif (LINUX) if (WIN32 OR APPLE) if (ENABLE_RTLSDR) + set(RTLSDR_LIBUSB_INCLUDE "${LIBUSB_INCLUDE_DIR}") if (WIN32) + set(LIBRTLSDR_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/rtlsdr.lib" CACHE INTERNAL "") set(RTLSDR_LIBUSB_INCLUDE "${LIBUSB_INCLUDE_DIR}/libusb-1.0") - else () - set(RTLSDR_LIBUSB_INCLUDE "${LIBUSB_INCLUDE_DIR}") endif () # needs pkgconfig and libusb ExternalProject_Add(rtlsdr @@ -482,12 +518,13 @@ if (WIN32 OR APPLE) GIT_TAG ${RTLSDR_TAG} DEPENDS ${PTHREADS4W_DEPENDS} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/rtlsdr" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} + CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DINSTALL_UDEV_RULES=${RTLSDR_UDEV} -DLIBUSB_LIBRARIES=${LIBUSB_LIBRARIES} -DLIBUSB_INCLUDE_DIR=${RTLSDR_LIBUSB_INCLUDE} -DTHREADS_PTHREADS_INCLUDE_DIR=${PTHREADS4W_INCLUDE_DIR} -DTHREADS_PTHREADS_WIN32_LIBRARY=${PTHREADS4W_LIBRARIES} + BUILD_BYPRODUCTS "${LIBRTLSDR_LIBRARIES}" INSTALL_COMMAND "" TEST_COMMAND "" ) @@ -496,7 +533,6 @@ if (WIN32 OR APPLE) set(LIBRTLSDR_EXTERNAL ON CACHE INTERNAL "") set(LIBRTLSDR_INCLUDE_DIR "${source_dir}/include" CACHE INTERNAL "") if (WIN32) - set(LIBRTLSDR_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/rtlsdr.lib" CACHE INTERNAL "") install(FILES "${SDRANGEL_BINARY_BIN_DIR}/rtlsdr${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") elseif (APPLE) set(LIBRTLSDR_LIBRARIES "${binary_dir}/src/librtlsdr${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") @@ -508,11 +544,14 @@ if (WIN32 OR APPLE) if (ENABLE_LIMESUITE) # needs pkgconfig, libusb + if (WIN32) + set(LIMESUITE_LIBRARY "${SDRANGEL_BINARY_LIB_DIR}/LimeSuite.lib" CACHE INTERNAL "") + endif () ExternalProject_Add(limesuite GIT_REPOSITORY https://github.com/myriadrf/LimeSuite.git GIT_TAG ${LIMESUITE_TAG} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/limesuite" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} + CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DLIME_SUITE_EXTVER=release -DENABLE_GUI=OFF -DENABLE_NOVENARF7=OFF @@ -522,6 +561,7 @@ if (WIN32 OR APPLE) -DENABLE_EXAMPLES=OFF -DENABLE_SIMD_FLAGS=SSE3 -DFX3_SDK_PATH=${FX3SDK_DIR} + BUILD_BYPRODUCTS "${LIMESUITE_LIBRARY}" INSTALL_COMMAND "" TEST_COMMAND "" ) @@ -530,7 +570,6 @@ if (WIN32 OR APPLE) set(LIMESUITE_EXTERNAL ON CACHE INTERNAL "") set(LIMESUITE_INCLUDE_DIR "${source_dir}/src" CACHE INTERNAL "") if (WIN32) - set(LIMESUITE_LIBRARY "${SDRANGEL_BINARY_LIB_DIR}/LimeSuite.lib" CACHE INTERNAL "") install(FILES "${SDRANGEL_BINARY_BIN_DIR}/LimeSuite${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") makeCopy("${source_dir}/src/limeRFE/limeRFE.h" "${source_dir}/src/lime/limeRFE.h" limesuite) elseif (APPLE) @@ -542,14 +581,18 @@ if (WIN32 OR APPLE) endif (ENABLE_LIMESUITE) if (ENABLE_SOAPYSDR) + if (WIN32) + set(SOAPYSDR_LIBRARY "${SDRANGEL_BINARY_LIB_DIR}/SoapySDR.lib" CACHE INTERNAL "") + endif () ExternalProject_Add(soapysdr GIT_REPOSITORY https://github.com/pothosware/SoapySDR.git GIT_TAG ${SOAPYSDR_TAG} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/soapysdr" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} + CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DENABLE_PYTHON=OFF -DENABLE_PYTHON3=OFF -DENABLE_TESTS=OFF + BUILD_BYPRODUCTS "${SOAPYSDR_LIBRARY}" INSTALL_COMMAND "" TEST_COMMAND "" ) @@ -558,7 +601,6 @@ if (WIN32 OR APPLE) set(SOAPYSDR_EXTERNAL ON CACHE INTERNAL "") set(SOAPYSDR_INCLUDE_DIR "${source_dir}/include" CACHE INTERNAL "") if (WIN32) - set(SOAPYSDR_LIBRARY "${SDRANGEL_BINARY_LIB_DIR}/SoapySDR.lib" CACHE INTERNAL "") install(FILES "${SDRANGEL_BINARY_BIN_DIR}/SoapySDR${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") elseif (APPLE) set(SOAPYSDR_LIBRARY "${binary_dir}/lib/libSoapySDR${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") @@ -569,10 +611,10 @@ if (WIN32 OR APPLE) endif (ENABLE_SOAPYSDR) if (ENABLE_AIRSPY) + set(AIRSPY_LIBUSB_INCLUDE_DIR ${LIBUSB_INCLUDE_DIR}) if (WIN32) + set(LIBAIRSPY_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/airspy.lib" CACHE INTERNAL "") set(AIRSPY_LIBUSB_INCLUDE_DIR ${LIBUSB_INCLUDE_DIR}/libusb-1.0) - else () - set(AIRSPY_LIBUSB_INCLUDE_DIR ${LIBUSB_INCLUDE_DIR}) endif () # needs libusb, pthreads ExternalProject_Add(airspy @@ -580,11 +622,13 @@ if (WIN32 OR APPLE) GIT_TAG ${AIRSPY_TAG} DEPENDS ${PTHREADS4W_DEPENDS} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/airspy" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} + SOURCE_SUBDIR "libairspy" + CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DLIBUSB_LIBRARIES=${LIBUSB_LIBRARIES} -DLIBUSB_INCLUDE_DIR=${AIRSPY_LIBUSB_INCLUDE_DIR} -DTHREADS_PTHREADS_INCLUDE_DIR=${PTHREADS4W_INCLUDE_DIR} -DTHREADS_PTHREADS_WIN32_LIBRARY=${PTHREADS4W_LIBRARIES} + BUILD_BYPRODUCTS "${LIBAIRSPY_LIBRARIES}" INSTALL_COMMAND "" TEST_COMMAND "" ) @@ -594,9 +638,8 @@ if (WIN32 OR APPLE) set(LIBAIRSPY_EXTERNAL ON CACHE INTERNAL "") set(LIBAIRSPY_INCLUDE_DIR "${source_dir}/libairspy/src" CACHE INTERNAL "") if (WIN32) - set(LIBAIRSPY_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/airspy.lib" CACHE INTERNAL "") makeCopyDir("${source_dir}/libairspy/src" "${source_dir}/libairspy/src/libairspy" airspy) - makeCopy("${binary_dir}/airspy-tools/src/airspy${CMAKE_SHARED_LIBRARY_SUFFIX}" "${SDRANGEL_BINARY_BIN_DIR}/airspy${CMAKE_SHARED_LIBRARY_SUFFIX}" airspy) + makeCopy("${binary_dir}/../airspy-tools/src/airspy${CMAKE_SHARED_LIBRARY_SUFFIX}" "${SDRANGEL_BINARY_BIN_DIR}/airspy${CMAKE_SHARED_LIBRARY_SUFFIX}" airspy) install(FILES "${SDRANGEL_BINARY_BIN_DIR}/airspy${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") elseif (APPLE) set(LIBAIRSPY_LIBRARIES "${binary_dir}/libairspy/src/libairspy${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") @@ -608,10 +651,10 @@ if (WIN32 OR APPLE) endif (ENABLE_AIRSPY) if (ENABLE_AIRSPYHF) + set(AIRSPYHF_LIBUSB_INCLUDE_DIR ${LIBUSB_INCLUDE_DIR}) if (WIN32) + set(LIBAIRSPYHF_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/airspyhf.lib" CACHE INTERNAL "") set(AIRSPYHF_LIBUSB_INCLUDE_DIR ${LIBUSB_INCLUDE_DIR}/libusb-1.0) - else () - set(AIRSPYHF_LIBUSB_INCLUDE_DIR ${LIBUSB_INCLUDE_DIR}) endif () # needs pkgconfig, libusb, pthreads ExternalProject_Add(airspyhf @@ -619,11 +662,12 @@ if (WIN32 OR APPLE) GIT_TAG ${AIRSPYHF_TAG} DEPENDS ${PTHREADS4W_DEPENDS} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/airspyhf" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} + CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DLIBUSB_LIBRARIES=${LIBUSB_LIBRARIES} -DLIBUSB_INCLUDE_DIR=${AIRSPYHF_LIBUSB_INCLUDE_DIR} -DTHREADS_PTHREADS_INCLUDE_DIR=${PTHREADS4W_INCLUDE_DIR} -DTHREADS_PTHREADS_WIN32_LIBRARY=${PTHREADS4W_LIBRARIES} + BUILD_BYPRODUCTS "${LIBAIRSPYHF_LIBRARIES}" INSTALL_COMMAND "" TEST_COMMAND "" ) @@ -633,7 +677,6 @@ if (WIN32 OR APPLE) set(LIBAIRSPYHF_EXTERNAL ON CACHE INTERNAL "") set(LIBAIRSPYHF_INCLUDE_DIR "${source_dir}/libairspyhf/src" CACHE INTERNAL "") if (WIN32) - set(LIBAIRSPYHF_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/airspyhf.lib" CACHE INTERNAL "") makeCopyDir("${source_dir}/libairspyhf/src" "${source_dir}/libairspyhf/src/libairspyhf" airspyhf) install(FILES "${SDRANGEL_BINARY_BIN_DIR}/airspyhf${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") elseif (APPLE) @@ -652,6 +695,7 @@ if (WIN32 OR APPLE) # needs pkgconfig, libusb, fftw, pthreads if (WIN32) set(HACKRF_LIBUSB_INCLUDE_DIR ${LIBUSB_INCLUDE_DIR}/libusb-1.0) + set(LIBHACKRF_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/hackrf.lib" CACHE INTERNAL "") else () set(HACKRF_LIBUSB_INCLUDE_DIR ${LIBUSB_INCLUDE_DIR}) endif () @@ -662,13 +706,14 @@ if (WIN32 OR APPLE) DEPENDS ${PTHREADS4W_DEPENDS} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/hackrf" SOURCE_SUBDIR "host/libhackrf" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} + CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DLIBUSB_LIBRARIES=${LIBUSB_LIBRARIES} -DLIBUSB_INCLUDE_DIR=${HACKRF_LIBUSB_INCLUDE_DIR} -DTHREADS_PTHREADS_INCLUDE_DIR=${PTHREADS4W_INCLUDE_DIR} -DTHREADS_PTHREADS_WIN32_LIBRARY=${PTHREADS4W_LIBRARIES} -DFFTW_INCLUDES=${FFTW3F_INCLUDE_DIRS} -DFFTW_LIBRARIES=${FFTW3F_LIBRARIES} + BUILD_BYPRODUCTS "${LIBHACKRF_LIBRARIES}" INSTALL_COMMAND "" TEST_COMMAND "" ) @@ -678,7 +723,6 @@ if (WIN32 OR APPLE) set(LIBHACKRF_EXTERNAL ON CACHE INTERNAL "") set(LIBHACKRF_INCLUDE_DIR "${source_dir}/host/libhackrf" CACHE INTERNAL "") if (WIN32) - set(LIBHACKRF_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/hackrf.lib" CACHE INTERNAL "") # include "libhackrf/hackrf.h" makeCopyDir("${source_dir}/host/libhackrf/src" "${source_dir}/host/libhackrf/libhackrf" hackrf) install(FILES "${SDRANGEL_BINARY_BIN_DIR}/hackrf${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") @@ -725,6 +769,7 @@ if (WIN32 OR APPLE) set(LIBXML2_INCLUDE_DIR "${source_dir}/include" CACHE INTERNAL "") if (WIN32) set(LIBXML2_LIBRARIES "${source_dir}/win32/bin.msvc/libxml2.lib" CACHE INTERNAL "") + set(LIBIIO_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/libiio.lib" CACHE INTERNAL "") makeCopy("${source_dir}/win32/bin.msvc/libxml2${CMAKE_SHARED_LIBRARY_SUFFIX}" "${SDRANGEL_BINARY_BIN_DIR}/libxml2${CMAKE_SHARED_LIBRARY_SUFFIX}" libxml2) install(FILES "${source_dir}/win32/bin.msvc/libxml2${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") elseif (APPLE) @@ -739,7 +784,7 @@ if (WIN32 OR APPLE) GIT_TAG ${LIBIIO_TAG} DEPENDS ${PTHREADS4W_DEPENDS} ${LIBXML2_DEPENDS} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/libiio" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} + CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DLIBUSB_LIBRARIES=${LIBUSB_LIBRARIES} -DLIBUSB_INCLUDE_DIR=${LIBUSB_INCLUDE_DIR} -DTHREADS_PTHREADS_INCLUDE_DIR=${PTHREADS4W_INCLUDE_DIR} @@ -750,6 +795,7 @@ if (WIN32 OR APPLE) -DPYTHON_BINDINGS=OFF -DWITH_MATLAB_BINDINGS_API=OFF -DOSX_PACKAGE=OFF + BUILD_BYPRODUCTS "${LIBIIO_LIBRARIES}" INSTALL_COMMAND "" TEST_COMMAND "" ) @@ -759,7 +805,6 @@ if (WIN32 OR APPLE) set(LIBIIO_EXTERNAL ON CACHE INTERNAL "") set(LIBIIO_INCLUDE_DIR "${source_dir}" CACHE INTERNAL "") if (WIN32) - set(LIBIIO_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/libiio.lib" CACHE INTERNAL "") install(FILES "${SDRANGEL_BINARY_BIN_DIR}/libiio${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") elseif (APPLE) set(LIBIIO_LIBRARIES "${binary_dir}/libiio${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") @@ -774,12 +819,16 @@ if (WIN32 OR APPLE) if (ENABLE_BLADERF) # needs pkgconfig, libusb, pthreads + if (WIN32) + set(LIBBLADERF_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/bladeRF.lib" CACHE INTERNAL "") + endif () ExternalProject_Add(bladerf GIT_REPOSITORY https://github.com/Nuand/bladeRF.git GIT_TAG ${BLADERF_TAG} DEPENDS ${PTHREADS4W_DEPENDS} PREFIX "${EXTERNAL_BUILD_LIBRARIES}/bladerf" - CMAKE_ARGS ${DEFAULT_OUTPUT_DIRECTORIES} + SOURCE_SUBDIR "host" + CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DPKG_CONFIG_EXECUTABLE=${PKG_CONFIG_EXECUTABLE} -DENABLE_BACKEND_USB=ON -DENABLE_BACKEND_LIBUSB=ON @@ -793,6 +842,7 @@ if (WIN32 OR APPLE) -DENABLE_HOST_BUILD=ON -DENABLE_BACKEND_CYAPI=OFF -DTREAT_WARNINGS_AS_ERRORS=OFF + BUILD_BYPRODUCTS "${LIBBLADERF_LIBRARIES}" INSTALL_COMMAND "" TEST_COMMAND "" ) @@ -802,7 +852,6 @@ if (WIN32 OR APPLE) set(LIBBLADERF_EXTERNAL ON CACHE INTERNAL "") set(LIBBLADERF_INCLUDE_DIRS "${source_dir}/host/libraries/libbladeRF/include" CACHE INTERNAL "") if (WIN32) - set(LIBBLADERF_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/bladeRF.lib" CACHE INTERNAL "") install(FILES "${SDRANGEL_BINARY_BIN_DIR}/bladeRF${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}") elseif (APPLE) set(LIBBLADERF_LIBRARIES "${binary_dir}/host/output/libbladeRF${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "") diff --git a/plugins/channelrx/chanalyzer/CMakeLists.txt b/plugins/channelrx/chanalyzer/CMakeLists.txt index 942f94311..58f634239 100644 --- a/plugins/channelrx/chanalyzer/CMakeLists.txt +++ b/plugins/channelrx/chanalyzer/CMakeLists.txt @@ -25,10 +25,6 @@ include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ) -include_directories( - ${Boost_INCLUDE_DIRS} -) - add_library(chanalyzer SHARED ${chanalyzer_SOURCES} ) diff --git a/plugins/channelrx/demodatv/CMakeLists.txt b/plugins/channelrx/demodatv/CMakeLists.txt index 52bb83c9c..3760b4e0c 100644 --- a/plugins/channelrx/demodatv/CMakeLists.txt +++ b/plugins/channelrx/demodatv/CMakeLists.txt @@ -22,7 +22,6 @@ set(atv_HEADERS ) include_directories( - ${Boost_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ) diff --git a/plugins/channelrx/demodbfm/CMakeLists.txt b/plugins/channelrx/demodbfm/CMakeLists.txt index 7e6f22d25..14611fdf4 100644 --- a/plugins/channelrx/demodbfm/CMakeLists.txt +++ b/plugins/channelrx/demodbfm/CMakeLists.txt @@ -30,7 +30,6 @@ set(bfm_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client - ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/channelrx/filesink/CMakeLists.txt b/plugins/channelrx/filesink/CMakeLists.txt index 867275a07..b45f7f6af 100644 --- a/plugins/channelrx/filesink/CMakeLists.txt +++ b/plugins/channelrx/filesink/CMakeLists.txt @@ -22,7 +22,6 @@ set(filesink_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client - ${Boost_INCLUDE_DIR} ) if(NOT SERVER_MODE) diff --git a/plugins/channelrx/localsink/CMakeLists.txt b/plugins/channelrx/localsink/CMakeLists.txt index b5632ae4c..4d6d6f2e0 100644 --- a/plugins/channelrx/localsink/CMakeLists.txt +++ b/plugins/channelrx/localsink/CMakeLists.txt @@ -22,7 +22,6 @@ set(localsink_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client - ${Boost_INCLUDE_DIR} ) if(NOT SERVER_MODE) diff --git a/plugins/channelrx/remotesink/CMakeLists.txt b/plugins/channelrx/remotesink/CMakeLists.txt index 64713e86d..3c2faefb4 100644 --- a/plugins/channelrx/remotesink/CMakeLists.txt +++ b/plugins/channelrx/remotesink/CMakeLists.txt @@ -33,7 +33,6 @@ set(remotesink_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client - ${Boost_INCLUDE_DIRS} ${CM256CC_INCLUDE_DIR} ${CUSTOM_WINDOWS_INCLUDE} ) diff --git a/plugins/channeltx/localsource/CMakeLists.txt b/plugins/channeltx/localsource/CMakeLists.txt index ead523a10..f59b00f21 100644 --- a/plugins/channeltx/localsource/CMakeLists.txt +++ b/plugins/channeltx/localsource/CMakeLists.txt @@ -22,7 +22,6 @@ set(localsource_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client - ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/channeltx/mod802.15.4/CMakeLists.txt b/plugins/channeltx/mod802.15.4/CMakeLists.txt index 11dd722f6..56d2e478e 100644 --- a/plugins/channeltx/mod802.15.4/CMakeLists.txt +++ b/plugins/channeltx/mod802.15.4/CMakeLists.txt @@ -20,7 +20,6 @@ set(mod_ieee_802_15_4_HEADERS ) include_directories( - ${Boost_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ) diff --git a/plugins/channeltx/remotesource/CMakeLists.txt b/plugins/channeltx/remotesource/CMakeLists.txt index 3bf447dc2..73fcf2cc5 100644 --- a/plugins/channeltx/remotesource/CMakeLists.txt +++ b/plugins/channeltx/remotesource/CMakeLists.txt @@ -31,7 +31,6 @@ set(remotesource_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client - ${Boost_INCLUDE_DIRS} ${CM256CC_INCLUDE_DIR} ${CUSTOM_WINDOWS_INCLUDE} ) diff --git a/plugins/samplesink/remoteoutput/CMakeLists.txt b/plugins/samplesink/remoteoutput/CMakeLists.txt index 3bf7c60a9..455ab0f6e 100644 --- a/plugins/samplesink/remoteoutput/CMakeLists.txt +++ b/plugins/samplesink/remoteoutput/CMakeLists.txt @@ -34,7 +34,6 @@ set(remoteoutput_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${CMAKE_SOURCE_DIR}/devices - ${Boost_INCLUDE_DIRS} ${CM256CC_INCLUDE_DIR} ) diff --git a/plugins/samplesink/usrpoutput/CMakeLists.txt b/plugins/samplesink/usrpoutput/CMakeLists.txt index 7e05dbb9a..8bfeece74 100644 --- a/plugins/samplesink/usrpoutput/CMakeLists.txt +++ b/plugins/samplesink/usrpoutput/CMakeLists.txt @@ -1,7 +1,3 @@ -if(WIN32) - link_directories(${BOOST_LIBRARYDIR}) -endif() - project(usrpoutput) set(usrpoutput_SOURCES @@ -24,7 +20,6 @@ include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${CMAKE_SOURCE_DIR}/devices ${UHD_INCLUDE_DIR} - ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/samplesource/kiwisdr/CMakeLists.txt b/plugins/samplesource/kiwisdr/CMakeLists.txt index 8ffdb9fa9..0c03fa1b3 100644 --- a/plugins/samplesource/kiwisdr/CMakeLists.txt +++ b/plugins/samplesource/kiwisdr/CMakeLists.txt @@ -18,7 +18,6 @@ set(kiwisdr_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client - ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/samplesource/remoteinput/CMakeLists.txt b/plugins/samplesource/remoteinput/CMakeLists.txt index eb1b83715..f6e1a519f 100644 --- a/plugins/samplesource/remoteinput/CMakeLists.txt +++ b/plugins/samplesource/remoteinput/CMakeLists.txt @@ -29,7 +29,6 @@ set(remoteinput_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client - ${Boost_INCLUDE_DIRS} ${CM256CC_INCLUDE_DIR} ) diff --git a/plugins/samplesource/usrpinput/CMakeLists.txt b/plugins/samplesource/usrpinput/CMakeLists.txt index a3f495bf1..1fef67c28 100644 --- a/plugins/samplesource/usrpinput/CMakeLists.txt +++ b/plugins/samplesource/usrpinput/CMakeLists.txt @@ -1,7 +1,3 @@ -if(WIN32) - link_directories(${BOOST_LIBRARYDIR}) -endif() - project(usrpinput) set(usrpinput_SOURCES @@ -24,7 +20,6 @@ include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${CMAKE_SOURCE_DIR}/devices ${UHD_INCLUDE_DIR} - ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/sdrbase/CMakeLists.txt b/sdrbase/CMakeLists.txt index 167cc445c..d4fe6dfd7 100644 --- a/sdrbase/CMakeLists.txt +++ b/sdrbase/CMakeLists.txt @@ -360,7 +360,6 @@ include_directories( ${CMAKE_SOURCE_DIR}/logging ${CMAKE_SOURCE_DIR}/qrtplib ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client - ${Boost_INCLUDE_DIRS} ${OPUS_INCLUDE_DIRS} ) @@ -381,6 +380,7 @@ target_link_libraries(sdrbase ${sdrbase_FFTW3F_LIB} ${sdrbase_SERIALDV_LIB} ${sdrbase_LIMERFE_LIB} + Boost::headers Qt5::Core Qt5::Multimedia Qt5::WebSockets diff --git a/sdrbase/ambe/ambeengine.cpp b/sdrbase/ambe/ambeengine.cpp index 03e4eec63..8c56c4ec3 100644 --- a/sdrbase/ambe/ambeengine.cpp +++ b/sdrbase/ambe/ambeengine.cpp @@ -27,7 +27,7 @@ #include #endif -#if !defined(__WINDOWS__) && !defined(__APPLE__) +#if !defined(_WIN32) && !defined(__APPLE__) #include #include #include @@ -51,7 +51,7 @@ AMBEEngine::~AMBEEngine() qDebug("AMBEEngine::~AMBEEngine: %lu controllers", m_controllers.size()); } -#if defined(__WINDOWS__) +#if defined(_WIN32) void AMBEEngine::getComList() { m_comList.clear(); @@ -119,7 +119,7 @@ void AMBEEngine::getComList() } #endif // not Windows nor Apple -#if !defined(__WINDOWS__) && !defined(__APPLE__) +#if !defined(_WIN32) && !defined(__APPLE__) void AMBEEngine::register_comport( std::vector& comList, std::vector& comList8250, diff --git a/sdrbase/ambe/ambeengine.h b/sdrbase/ambe/ambeengine.h index 59c16291f..f083d17b7 100644 --- a/sdrbase/ambe/ambeengine.h +++ b/sdrbase/ambe/ambeengine.h @@ -73,7 +73,7 @@ private: std::string device; }; -#ifndef __WINDOWS__ +#ifndef _WIN32 static std::string get_driver(const std::string& tty); static void register_comport(std::vector& comList, std::vector& comList8250, const std::string& dir); static void probe_serial8250_comports(std::vector& comList, std::vector comList8250); diff --git a/sdrbase/util/serialutil.cpp b/sdrbase/util/serialutil.cpp index c84fddb4c..9a74bd2ba 100644 --- a/sdrbase/util/serialutil.cpp +++ b/sdrbase/util/serialutil.cpp @@ -18,7 +18,7 @@ #include #include -#if defined(__WINDOWS__) +#if defined(_WIN32) #include #include #include @@ -31,7 +31,7 @@ #include "serialutil.h" -#if defined(__WINDOWS__) +#if defined(_WIN32) void SerialUtil::getComPorts(std::vector& comPorts, const std::string& regexStr) { (void) regexStr; diff --git a/sdrgui/CMakeLists.txt b/sdrgui/CMakeLists.txt index 093ac3a91..a949b0448 100644 --- a/sdrgui/CMakeLists.txt +++ b/sdrgui/CMakeLists.txt @@ -231,7 +231,6 @@ include_directories( ${CMAKE_SOURCE_DIR}/httpserver ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${OPENGL_INCLUDE_DIR} - ${Boost_INCLUDE_DIRS} ) add_library(sdrgui SHARED From 379096cbdda74ae77ae8f35f98bf0aaa733a8954 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 4 Nov 2020 08:59:16 +0100 Subject: [PATCH 05/19] Migrate code to Qt 5.14.2 --- plugins/channelrx/demodbfm/bfmdemodgui.cpp | 3 +-- plugins/channelrx/demoddatv/datvdemodgui.cpp | 17 +++++++++-------- .../remotesource/remotesourcegui.cpp | 4 +++- .../channeltx/remotesource/remotesourcegui.h | 4 ++-- plugins/samplesource/sdrplay/sdrplaygui.cpp | 19 ++++++------------- sdrbase/util/syncmessenger.cpp | 6 +++--- sdrgui/dsp/scopevis.cpp | 4 ++-- sdrgui/gui/glscope.cpp | 16 ++++++++-------- sdrgui/gui/glscopegui.cpp | 6 ++---- sdrgui/gui/glspectrum.cpp | 6 +++--- sdrgui/gui/valuedial.cpp | 2 +- sdrgui/gui/valuedialz.cpp | 2 +- 12 files changed, 41 insertions(+), 48 deletions(-) diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.cpp b/plugins/channelrx/demodbfm/bfmdemodgui.cpp index aa317de4e..d699f6389 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodgui.cpp @@ -523,8 +523,7 @@ void BFMDemodGUI::tick() ui->channelPower->setText(QString::number(powDbAvg, 'f', 1)); Real pilotPowDb = CalcDb::dbPower(m_bfmDemod->getPilotLevel()); - QString pilotPowDbStr; - pilotPowDbStr.sprintf("%+02.1f", pilotPowDb); + QString pilotPowDbStr = QString("%1%2").arg(pilotPowDb < 0 ? '-' : '+').arg(pilotPowDb, 3, 'f', 1, QLatin1Char('0')); ui->pilotPower->setText(pilotPowDbStr); if (m_bfmDemod->getAudioSampleRate() < 0) diff --git a/plugins/channelrx/demoddatv/datvdemodgui.cpp b/plugins/channelrx/demoddatv/datvdemodgui.cpp index 7e0ca3c11..e8170bbd1 100644 --- a/plugins/channelrx/demoddatv/datvdemodgui.cpp +++ b/plugins/channelrx/demoddatv/datvdemodgui.cpp @@ -670,19 +670,20 @@ void DATVDemodGUI::on_udpTS_clicked(bool checked) void DATVDemodGUI::on_StreamMetaDataChanged(DataTSMetaData2 *objMetaData) { - QString strMetaData=""; if (objMetaData != nullptr) { + QString strMetaData = ""; + if (objMetaData->OK_TransportStream == true) { - strMetaData.sprintf("PID: %d - Width: %d - Height: %d\r\n%s%s\r\nCodec: %s\r\n", - objMetaData->PID, - objMetaData->Width, - objMetaData->Height, - objMetaData->Program.toStdString().c_str(), - objMetaData->Stream.toStdString().c_str(), - objMetaData->CodecDescription.toStdString().c_str()); + strMetaData = tr("PID: %1 - Width: %2 - Height: %3\r\n%4%5\r\nCodec: %6\r\n") + .arg(objMetaData->PID) + .arg(objMetaData->Width) + .arg(objMetaData->Height) + .arg(objMetaData->Program) + .arg(objMetaData->Stream) + .arg(objMetaData->CodecDescription); } ui->streamInfo->setText(strMetaData); diff --git a/plugins/channeltx/remotesource/remotesourcegui.cpp b/plugins/channeltx/remotesource/remotesourcegui.cpp index df8e8af74..b2d23c49e 100644 --- a/plugins/channeltx/remotesource/remotesourcegui.cpp +++ b/plugins/channeltx/remotesource/remotesourcegui.cpp @@ -15,7 +15,7 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include "remotesourcegui.h" +#include #include "device/deviceapi.h" #include "device/deviceuiset.h" @@ -26,6 +26,8 @@ #include "remotesource.h" #include "ui_remotesourcegui.h" +#include "remotesourcegui.h" + RemoteSourceGUI* RemoteSourceGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx) { RemoteSourceGUI* gui = new RemoteSourceGUI(pluginAPI, deviceUISet, channelTx); diff --git a/plugins/channeltx/remotesource/remotesourcegui.h b/plugins/channeltx/remotesource/remotesourcegui.h index 1a4faf9b1..bcd66a805 100644 --- a/plugins/channeltx/remotesource/remotesourcegui.h +++ b/plugins/channeltx/remotesource/remotesourcegui.h @@ -18,7 +18,7 @@ #ifndef PLUGINS_CHANNELTX_REMOTESRC_REMOTESRCGUI_H_ #define PLUGINS_CHANNELTX_REMOTESRC_REMOTESRCGUI_H_ -#include +#include #include "dsp/channelmarker.h" #include "channel/channelgui.h" @@ -69,7 +69,7 @@ private: uint32_t m_lastSampleCount; uint64_t m_lastTimestampUs; bool m_resetCounts; - QTime m_time; + QElapsedTimer m_time; uint32_t m_tickCount; explicit RemoteSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx, QWidget* parent = 0); diff --git a/plugins/samplesource/sdrplay/sdrplaygui.cpp b/plugins/samplesource/sdrplay/sdrplaygui.cpp index 1cab3c0c1..a214a0b54 100644 --- a/plugins/samplesource/sdrplay/sdrplaygui.cpp +++ b/plugins/samplesource/sdrplay/sdrplaygui.cpp @@ -144,16 +144,14 @@ bool SDRPlayGui::handleMessage(const Message& message) ui->gainMixer->setChecked(msg.getMixerGain() != 0); ui->gainBaseband->setValue(msg.getBasebandGain()); - QString gainText; - gainText.sprintf("%02d", msg.getBasebandGain()); + QString gainText = QStringLiteral("%1").arg(msg.getBasebandGain(), 2, 10, QLatin1Char('0')); ui->gainBasebandText->setText(gainText); } else { ui->gainTuner->setValue(msg.getTunerGain()); - QString gainText; - gainText.sprintf("%03d", msg.getTunerGain()); + QString gainText = QStringLiteral("%1").arg(msg.getTunerGain(), 3, 10, QLatin1Char('0')); ui->gainTunerText->setText(gainText); } @@ -241,8 +239,7 @@ void SDRPlayGui::displaySettings() int gain = m_settings.m_tunerGain; ui->gainTuner->setValue(gain); - QString gainText; - gainText.sprintf("%03d", gain); + QString gainText = QStringLiteral("%1").arg(gain, 3, 10, QLatin1Char('0')); ui->gainTunerText->setText(gainText); m_settings.m_tunerGain = gain; } @@ -258,8 +255,7 @@ void SDRPlayGui::displaySettings() int gain = m_settings.m_basebandGain; ui->gainBaseband->setValue(gain); - QString gainText; - gainText.sprintf("%02d", gain); + QString gainText = QStringLiteral("%1").arg(gain, 2, 10, QLatin1Char('0')); ui->gainBasebandText->setText(gainText); } } @@ -393,9 +389,7 @@ void SDRPlayGui::on_gainTunerOn_toggled(bool checked) void SDRPlayGui::on_gainTuner_valueChanged(int value) { int gain = value; - QString gainText; - gainText.sprintf("%03d", gain); - ui->gainTunerText->setText(gainText); + QString gainText = QStringLiteral("%1").arg(gain, 3, 10, QLatin1Char('0')); m_settings.m_tunerGain = gain; sendSettings(); @@ -429,8 +423,7 @@ void SDRPlayGui::on_gainBaseband_valueChanged(int value) { m_settings.m_basebandGain = value; - QString gainText; - gainText.sprintf("%02d", value); + QString gainText = QStringLiteral("%1").arg(value, 2, 10, QLatin1Char('0')); ui->gainBasebandText->setText(gainText); sendSettings(); diff --git a/sdrbase/util/syncmessenger.cpp b/sdrbase/util/syncmessenger.cpp index 9233bbb3c..97e18ef2f 100644 --- a/sdrbase/util/syncmessenger.cpp +++ b/sdrbase/util/syncmessenger.cpp @@ -34,11 +34,11 @@ int SyncMessenger::sendWait(Message& message, unsigned long msPollTime) { m_message = &message; m_mutex.lock(); - m_complete.store(0); + m_complete.storeRelaxed(0); emit messageSent(); - while (!m_complete.load()) + while (!m_complete.loadRelaxed()) { m_waitCondition.wait(&m_mutex, msPollTime); } @@ -52,7 +52,7 @@ int SyncMessenger::sendWait(Message& message, unsigned long msPollTime) void SyncMessenger::done(int result) { m_result = result; - m_complete.store(1); + m_complete.storeRelaxed(1); m_waitCondition.wakeAll(); } diff --git a/sdrgui/dsp/scopevis.cpp b/sdrgui/dsp/scopevis.cpp index a2ffa1856..9d5faa3e3 100644 --- a/sdrgui/dsp/scopevis.cpp +++ b/sdrgui/dsp/scopevis.cpp @@ -619,13 +619,13 @@ int ScopeVis::processTraces(const SampleVector::const_iterator& cbegin, const Sa // display only at trace end if trace time is less than 1 second if (traceTime < 1.0f) { - if (m_glScope->getProcessingTraceIndex().load() < 0) { + if (m_glScope->getProcessingTraceIndex().loadRelaxed() < 0) { m_glScope->newTraces(m_traces.m_traces, m_traces.currentBufferIndex(), &m_traces.m_projectionTypes); } } // switch to next buffer only if it is not being processed by the scope - if (m_glScope->getProcessingTraceIndex().load() != (((int) m_traces.currentBufferIndex() + 1) % 2)) { + if (m_glScope->getProcessingTraceIndex().loadRelaxed() != (((int) m_traces.currentBufferIndex() + 1) % 2)) { m_traces.switchBuffer(); } diff --git a/sdrgui/gui/glscope.cpp b/sdrgui/gui/glscope.cpp index 3050b1d16..9d0c0d630 100644 --- a/sdrgui/gui/glscope.cpp +++ b/sdrgui/gui/glscope.cpp @@ -135,7 +135,7 @@ void GLScope::newTraces(std::vector *traces, int traceIndex, std::vecto if (m_dataChanged.testAndSetOrdered(0, 1)) { - m_processingTraceIndex.store(traceIndex); + m_processingTraceIndex.storeRelaxed(traceIndex); m_traces = &traces[traceIndex]; m_projectionTypes = projectionTypes; } @@ -834,8 +834,8 @@ void GLScope::paintGL() drawMarkers(); - m_dataChanged.store(0); - m_processingTraceIndex.store(-1); + m_dataChanged.storeRelaxed(0); + m_processingTraceIndex.storeRelaxed(-1); m_mutex.unlock(); } @@ -1113,7 +1113,7 @@ void GLScope::applyConfig() void GLScope::setUniqueDisplays() { QFontMetrics fm(font()); - int M = fm.width("-"); + int M = fm.horizontalAdvance("-"); int scopeHeight = height() - m_topMargin - m_botMargin; int scopeWidth = width() - m_leftMargin - m_rightMargin; @@ -1297,7 +1297,7 @@ void GLScope::setUniqueDisplays() void GLScope::setVerticalDisplays() { QFontMetrics fm(font()); - int M = fm.width("-"); + int M = fm.horizontalAdvance("-"); int scopeHeight = (height() - m_topMargin) / 2 - m_botMargin; int scopeWidth = width() - m_leftMargin - m_rightMargin; @@ -1480,7 +1480,7 @@ void GLScope::setVerticalDisplays() void GLScope::setHorizontalDisplays() { QFontMetrics fm(font()); - int M = fm.width("-"); + int M = fm.horizontalAdvance("-"); int scopeHeight = height() - m_topMargin - m_botMargin; int scopeWidth = (width() - m_rightMargin) / 2 - m_leftMargin; @@ -1662,7 +1662,7 @@ void GLScope::setHorizontalDisplays() void GLScope::setPolarDisplays() { QFontMetrics fm(font()); - int M = fm.width("-"); + int M = fm.horizontalAdvance("-"); int scopeHeight = height() - m_topMargin - m_botMargin; int scopeWidth = (width() - m_rightMargin) / 2 - m_leftMargin; int scopeDim = std::min(scopeWidth, scopeHeight); @@ -2012,7 +2012,7 @@ void GLScope::drawTextOverlay( void GLScope::tick() { - if (m_dataChanged.load()) { + if (m_dataChanged.loadRelaxed()) { update(); } } diff --git a/sdrgui/gui/glscopegui.cpp b/sdrgui/gui/glscopegui.cpp index 3e5d491da..df52e760a 100644 --- a/sdrgui/gui/glscopegui.cpp +++ b/sdrgui/gui/glscopegui.cpp @@ -872,8 +872,7 @@ void GLScopeGUI::on_memoryLoad_clicked(bool checked) void GLScopeGUI::on_mem_valueChanged(int value) { - QString text; - text.sprintf("%02d", value); + QString text = QStringLiteral("%1").arg(value, 2, 10, QLatin1Char('0')); ui->memText->setText(text); disableLiveMode(value > 0); // live / memory mode toggle m_scopeVis->setMemoryIndex(value); @@ -1013,8 +1012,7 @@ void GLScopeGUI::setTraceIndexDisplay() void GLScopeGUI::setTrigCountDisplay() { - QString text; - text.sprintf("%02d", ui->trigCount->value()); + QString text = QStringLiteral("%1").arg(ui->trigCount->value(), 2, 10, QLatin1Char('0')); ui->trigCountText->setText(text); } diff --git a/sdrgui/gui/glspectrum.cpp b/sdrgui/gui/glspectrum.cpp index d539265d0..bb36aabe5 100644 --- a/sdrgui/gui/glspectrum.cpp +++ b/sdrgui/gui/glspectrum.cpp @@ -1251,7 +1251,7 @@ void GLSpectrum::applyChanges() } QFontMetrics fm(font()); - int M = fm.width("-"); + int M = fm.horizontalAdvance("-"); m_topMargin = fm.ascent() * 1.5; m_bottomMargin = fm.ascent() * 1.5; @@ -1261,7 +1261,7 @@ void GLSpectrum::applyChanges() int frequencyScaleTop = 0; int histogramTop = 0; //int m_leftMargin; - m_rightMargin = fm.width("000"); + m_rightMargin = fm.horizontalAdvance("000"); // displays both histogram and waterfall if (m_displayWaterfall && (m_displayHistogram | m_displayMaxHold | m_displayCurrent)) @@ -1800,7 +1800,7 @@ void GLSpectrum::applyChanges() shift = 0; } else { // right half of scale ftext = ftext + " "; - shift = - fm.width(ftext); + shift = - fm.horizontalAdvance(ftext); } painter.drawText(QPointF(m_leftMargin + m_frequencyScale.getPosFromValue(xc) + shift, 2*fm.height() + fm.ascent() / 2 - 1), ftext); } diff --git a/sdrgui/gui/valuedial.cpp b/sdrgui/gui/valuedial.cpp index e5037df0e..3af067f13 100644 --- a/sdrgui/gui/valuedial.cpp +++ b/sdrgui/gui/valuedial.cpp @@ -77,7 +77,7 @@ void ValueDial::setFont(const QFont &font) QWidget::setFont(font); QFontMetrics fm(font); - m_digitWidth = fm.width('0'); + m_digitWidth = fm.horizontalAdvance('0'); m_digitHeight = fm.ascent(); if (m_digitWidth < m_digitHeight) { m_digitWidth = m_digitHeight; diff --git a/sdrgui/gui/valuedialz.cpp b/sdrgui/gui/valuedialz.cpp index 5d9ed8be8..2cc419bf1 100644 --- a/sdrgui/gui/valuedialz.cpp +++ b/sdrgui/gui/valuedialz.cpp @@ -79,7 +79,7 @@ void ValueDialZ::setFont(const QFont& font) QWidget::setFont(font); QFontMetrics fm(font); - m_digitWidth = fm.width('0'); + m_digitWidth = fm.horizontalAdvance('0'); m_digitHeight = fm.ascent(); if(m_digitWidth < m_digitHeight) m_digitWidth = m_digitHeight; From 19ecf12c22add822b7c1f7f48f4687b223bf823d Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 4 Nov 2020 20:05:11 +0100 Subject: [PATCH 06/19] removed asserts --- plugins/samplesink/fileoutput/fileoutputworker.cpp | 2 -- plugins/samplesink/localoutput/localoutputgui.cpp | 1 - .../samplesink/remoteoutput/remoteoutputworker.cpp | 1 - plugins/samplesink/testsink/testsinkworker.cpp | 3 +-- plugins/samplesource/fileinput/fileinputworker.cpp | 2 -- plugins/samplesource/localinput/localinputgui.cpp | 1 - .../samplesource/remoteinput/remoteinputbuffer.cpp | 1 - .../samplesource/remoteinput/remoteinputgui.cpp | 1 - sdrbase/dsp/iirfilter.h | 3 --- sdrbase/dsp/samplesourcefifodb.cpp | 5 ++--- sdrbase/dsp/samplesourcefifodb.h | 1 - sdrbase/util/db.cpp | 14 ++++++-------- sdrbase/util/udpsinkutil.h | 5 ----- 13 files changed, 9 insertions(+), 31 deletions(-) diff --git a/plugins/samplesink/fileoutput/fileoutputworker.cpp b/plugins/samplesink/fileoutput/fileoutputworker.cpp index d31e6589a..99644b0db 100644 --- a/plugins/samplesink/fileoutput/fileoutputworker.cpp +++ b/plugins/samplesink/fileoutput/fileoutputworker.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -39,7 +38,6 @@ FileOutputWorker::FileOutputWorker(std::ofstream *samplesStream, SampleSourceFif m_throttleToggle(false), m_buf(nullptr) { - assert(m_ofstream != nullptr); } FileOutputWorker::~FileOutputWorker() diff --git a/plugins/samplesink/localoutput/localoutputgui.cpp b/plugins/samplesink/localoutput/localoutputgui.cpp index 3b9cd6490..6e9f91234 100644 --- a/plugins/samplesink/localoutput/localoutputgui.cpp +++ b/plugins/samplesink/localoutput/localoutputgui.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/plugins/samplesink/remoteoutput/remoteoutputworker.cpp b/plugins/samplesink/remoteoutput/remoteoutputworker.cpp index a1a88c31b..e295bf7d4 100644 --- a/plugins/samplesink/remoteoutput/remoteoutputworker.cpp +++ b/plugins/samplesink/remoteoutput/remoteoutputworker.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include diff --git a/plugins/samplesink/testsink/testsinkworker.cpp b/plugins/samplesink/testsink/testsinkworker.cpp index 4d59aa0a2..6eb9c11ab 100644 --- a/plugins/samplesink/testsink/testsinkworker.cpp +++ b/plugins/samplesink/testsink/testsinkworker.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -225,4 +224,4 @@ void TestSinkWorker::feedSpectrum(int16_t *buf, unsigned int bufSize) ); m_spectrumSink->feed(m_samplesVector.m_vector.begin(), m_samplesVector.m_vector.begin() + (bufSize/2), false); -} \ No newline at end of file +} diff --git a/plugins/samplesource/fileinput/fileinputworker.cpp b/plugins/samplesource/fileinput/fileinputworker.cpp index 4c2e67523..f1b61f75d 100644 --- a/plugins/samplesource/fileinput/fileinputworker.cpp +++ b/plugins/samplesource/fileinput/fileinputworker.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include "dsp/filerecord.h" @@ -49,7 +48,6 @@ FileInputWorker::FileInputWorker(std::ifstream *samplesStream, m_throttlems(FILESOURCE_THROTTLE_MS), m_throttleToggle(false) { - assert(m_ifstream != nullptr); } FileInputWorker::~FileInputWorker() diff --git a/plugins/samplesource/localinput/localinputgui.cpp b/plugins/samplesource/localinput/localinputgui.cpp index a1f4d1e17..59ebb35b1 100644 --- a/plugins/samplesource/localinput/localinputgui.cpp +++ b/plugins/samplesource/localinput/localinputgui.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/plugins/samplesource/remoteinput/remoteinputbuffer.cpp b/plugins/samplesource/remoteinput/remoteinputbuffer.cpp index 948733fec..6f070e09e 100644 --- a/plugins/samplesource/remoteinput/remoteinputbuffer.cpp +++ b/plugins/samplesource/remoteinput/remoteinputbuffer.cpp @@ -16,7 +16,6 @@ /////////////////////////////////////////////////////////////////////////////////// #include -#include #include #include #include diff --git a/plugins/samplesource/remoteinput/remoteinputgui.cpp b/plugins/samplesource/remoteinput/remoteinputgui.cpp index df1b10cae..dc73951fc 100644 --- a/plugins/samplesource/remoteinput/remoteinputgui.cpp +++ b/plugins/samplesource/remoteinput/remoteinputgui.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/sdrbase/dsp/iirfilter.h b/sdrbase/dsp/iirfilter.h index be05ffefe..c575796d0 100644 --- a/sdrbase/dsp/iirfilter.h +++ b/sdrbase/dsp/iirfilter.h @@ -26,7 +26,6 @@ #include #include -#include template class IIRFilter { @@ -61,8 +60,6 @@ private: template IIRFilter::IIRFilter(const Type *a, const Type *b) { - assert(Order > 1); - m_a = new Type[Order+1]; m_b = new Type[Order+1]; m_x = new Type[Order]; diff --git a/sdrbase/dsp/samplesourcefifodb.cpp b/sdrbase/dsp/samplesourcefifodb.cpp index f702cc7fd..d39e5be63 100644 --- a/sdrbase/dsp/samplesourcefifodb.cpp +++ b/sdrbase/dsp/samplesourcefifodb.cpp @@ -16,7 +16,6 @@ /////////////////////////////////////////////////////////////////////////////////// #include -#include #include "samplesourcefifodb.h" SampleSourceFifoDB::SampleSourceFifoDB(uint32_t size, QObject* parent) : @@ -60,7 +59,7 @@ void SampleSourceFifoDB::init() void SampleSourceFifoDB::readAdvance(SampleVector::iterator& readUntil, unsigned int nbSamples) { // QMutexLocker mutexLocker(&m_mutex); - assert(nbSamples <= m_size/2); + nbSamples = nbSamples > m_size/2 ? m_size/2 : nbSamples; emit dataWrite(nbSamples); m_ir = (m_ir + nbSamples) % m_size; @@ -71,7 +70,7 @@ void SampleSourceFifoDB::readAdvance(SampleVector::iterator& readUntil, unsigned void SampleSourceFifoDB::readAdvance(SampleVector::const_iterator& readUntil, unsigned int nbSamples) { // QMutexLocker mutexLocker(&m_mutex); - assert(nbSamples <= m_size/2); + nbSamples = nbSamples > m_size/2 ? m_size/2 : nbSamples; emit dataWrite(nbSamples); m_ir = (m_ir + nbSamples) % m_size; diff --git a/sdrbase/dsp/samplesourcefifodb.h b/sdrbase/dsp/samplesourcefifodb.h index 7062ae87f..a9b7bbbe2 100644 --- a/sdrbase/dsp/samplesourcefifodb.h +++ b/sdrbase/dsp/samplesourcefifodb.h @@ -21,7 +21,6 @@ #include #include #include -#include #include "export.h" #include "dsp/dsptypes.h" diff --git a/sdrbase/util/db.cpp b/sdrbase/util/db.cpp index 872d4e015..6b18d89ae 100644 --- a/sdrbase/util/db.cpp +++ b/sdrbase/util/db.cpp @@ -17,18 +17,16 @@ #include "util/db.h" #include -#include double CalcDb::dbPower(double magsq, double floor) { - assert(floor > 0.0); - - if (magsq > floor) - { - return 10.0 * log10(magsq); + if (floor <= 0.0) { + return -100.0; } - else - { + + if (magsq > floor) { + return 10.0 * log10(magsq); + } else { return 10.0 * log10(floor); } } diff --git a/sdrbase/util/udpsinkutil.h b/sdrbase/util/udpsinkutil.h index 7abb63995..467b09480 100644 --- a/sdrbase/util/udpsinkutil.h +++ b/sdrbase/util/udpsinkutil.h @@ -24,8 +24,6 @@ #include #include -#include - template class UDPSinkUtil { @@ -37,7 +35,6 @@ public: m_port(9999), m_sampleBufferIndex(0) { - assert(m_udpSamples > 0); m_sampleBuffer = new T[m_udpSamples]; m_socket = new QUdpSocket(parent); } @@ -49,7 +46,6 @@ public: m_port(port), m_sampleBufferIndex(0) { - assert(m_udpSamples > 0); m_sampleBuffer = new T[m_udpSamples]; m_socket = new QUdpSocket(parent); } @@ -61,7 +57,6 @@ public: m_port(port), m_sampleBufferIndex(0) { - assert(m_udpSamples > 0); m_sampleBuffer = new T[m_udpSamples]; m_socket = new QUdpSocket(parent); } From a9d09e30a8d2aa9bf916a6b88472e6d575edd2c1 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 4 Nov 2020 22:52:15 +0100 Subject: [PATCH 07/19] Fixed Qt version checks --- app/main.cpp | 4 ++-- appbench/main.cpp | 2 +- appsrv/main.cpp | 2 +- httpserver/httpconnectionhandler.h | 2 +- logging/logger.cpp | 6 +++--- sdrbase/commands/command.cpp | 8 ++++---- sdrbase/maincore.cpp | 2 +- sdrbase/util/syncmessenger.cpp | 19 +++++++++++++++++-- sdrbase/webapi/webapiadapter.cpp | 2 +- sdrgui/dsp/scopevis.cpp | 13 +++++++++++++ sdrgui/gui/glscope.cpp | 16 ++++++++++++++++ sdrgui/mainwindow.cpp | 2 +- 12 files changed, 61 insertions(+), 17 deletions(-) diff --git a/app/main.cpp b/app/main.cpp index deb75b6d5..32e1a2f70 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -37,7 +37,7 @@ static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *lo QCoreApplication::setApplicationName(APPLICATION_NAME); QCoreApplication::setApplicationVersion(SDRANGEL_VERSION); -#if QT_VERSION >= 0x050600 +#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // DPI support QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); //HiDPI pixmaps #endif @@ -102,7 +102,7 @@ static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *lo MainParser parser; parser.parse(*qApp); -#if QT_VERSION >= 0x050400 +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) qInfo("%s %s Qt %s %db %s %s DSP Rx:%db Tx:%db PID %lld", qPrintable(qApp->applicationName()), qPrintable(qApp->applicationVersion()), diff --git a/appbench/main.cpp b/appbench/main.cpp index 743ccc49e..0c91a875c 100644 --- a/appbench/main.cpp +++ b/appbench/main.cpp @@ -71,7 +71,7 @@ static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *lo ParserBench parser; parser.parse(a); -#if QT_VERSION >= 0x050400 +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) qInfo("%s %s Qt %s %db %s %s DSP Rx:%db Tx:%db PID %lld", qPrintable(QCoreApplication::applicationName()), qPrintable(QCoreApplication::applicationVersion()), diff --git a/appsrv/main.cpp b/appsrv/main.cpp index d74735362..78f4c3a7b 100644 --- a/appsrv/main.cpp +++ b/appsrv/main.cpp @@ -70,7 +70,7 @@ static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *lo MainParser parser; parser.parse(a); -#if QT_VERSION >= 0x050400 +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) qInfo("%s %s Qt %s %db %s %s DSP Rx:%db Tx:%db PID %lld", qPrintable(QCoreApplication::applicationName()), qPrintable(QCoreApplication::applicationVersion()), diff --git a/httpserver/httpconnectionhandler.h b/httpserver/httpconnectionhandler.h index 00cdd943d..5ced8ca76 100644 --- a/httpserver/httpconnectionhandler.h +++ b/httpserver/httpconnectionhandler.h @@ -23,7 +23,7 @@ namespace qtwebapp { /** Alias type definition, for compatibility to different Qt versions */ -#if QT_VERSION >= 0x050000 +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) typedef qintptr tSocketDescriptor; #else typedef int tSocketDescriptor; diff --git a/logging/logger.cpp b/logging/logger.cpp index fca4a307f..a608fad54 100644 --- a/logging/logger.cpp +++ b/logging/logger.cpp @@ -73,7 +73,7 @@ void Logger::msgHandler(const QtMsgType type, const QString &message, const QStr } -#if QT_VERSION >= 0x050000 +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) void Logger::msgHandler5(const QtMsgType type, const QMessageLogContext &context, const QString &message) { (void)(context); // suppress "unused parameter" warning @@ -91,7 +91,7 @@ Logger::~Logger() { if (defaultLogger==this) { -#if QT_VERSION >= 0x050000 +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) qInstallMessageHandler(0); #else qInstallMsgHandler(0); @@ -111,7 +111,7 @@ void Logger::write(const LogMessage* logMessage) void Logger::installMsgHandler() { defaultLogger=this; -#if QT_VERSION >= 0x050000 +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) qInstallMessageHandler(msgHandler5); #else qInstallMsgHandler(msgHandler4); diff --git a/sdrbase/commands/command.cpp b/sdrbase/commands/command.cpp index 9f558267c..a6b83dff8 100644 --- a/sdrbase/commands/command.cpp +++ b/sdrbase/commands/command.cpp @@ -67,7 +67,7 @@ Command::~Command() { if (m_currentProcess) { -#if QT_VERSION < 0x051000 +#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) disconnect(m_currentProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); #else disconnect(m_currentProcess, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); @@ -193,7 +193,7 @@ void Command::run(const QString& apiAddress, int apiPort, int deviceSetIndex) m_isInError = false; m_hasExited = false; -#if QT_VERSION < 0x051000 +#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) connect(m_currentProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); #else connect(m_currentProcess, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); @@ -266,7 +266,7 @@ void Command::processError(QProcess::ProcessError error) { m_log = m_currentProcess->readAllStandardOutput(); -#if QT_VERSION < 0x051000 +#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) disconnect(m_currentProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); #else disconnect(m_currentProcess, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); @@ -288,7 +288,7 @@ void Command::processFinished(int exitCode, QProcess::ExitStatus exitStatus) m_hasExited = true; m_log = m_currentProcess->readAllStandardOutput(); -#if QT_VERSION < 0x051000 +#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) disconnect(m_currentProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); #else disconnect(m_currentProcess, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); diff --git a/sdrbase/maincore.cpp b/sdrbase/maincore.cpp index be6186d79..fed2c4f9a 100644 --- a/sdrbase/maincore.cpp +++ b/sdrbase/maincore.cpp @@ -85,7 +85,7 @@ void MainCore::setLoggingOptions() if (m_settings.getUseLogFile()) { -#if QT_VERSION >= 0x050400 +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) QString appInfoStr(QString("%1 %2 Qt %3 %4b %5 %6 DSP Rx:%7b Tx:%8b PID %9") .arg(QCoreApplication::applicationName()) .arg(QCoreApplication::applicationVersion()) diff --git a/sdrbase/util/syncmessenger.cpp b/sdrbase/util/syncmessenger.cpp index 97e18ef2f..53459a672 100644 --- a/sdrbase/util/syncmessenger.cpp +++ b/sdrbase/util/syncmessenger.cpp @@ -16,6 +16,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include + #include "util/syncmessenger.h" #include "util/message.h" @@ -34,14 +36,23 @@ int SyncMessenger::sendWait(Message& message, unsigned long msPollTime) { m_message = &message; m_mutex.lock(); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) m_complete.storeRelaxed(0); +#else + m_complete.store(0); +#endif emit messageSent(); - while (!m_complete.loadRelaxed()) - { +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + while (!m_complete.loadRelaxed()) { m_waitCondition.wait(&m_mutex, msPollTime); } +#else + while (!m_complete.load()) { + m_waitCondition.wait(&m_mutex, msPollTime); + } +#endif int result = m_result; m_mutex.unlock(); @@ -52,7 +63,11 @@ int SyncMessenger::sendWait(Message& message, unsigned long msPollTime) void SyncMessenger::done(int result) { m_result = result; +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) m_complete.storeRelaxed(1); +#else + m_complete.store(1); +#endif m_waitCondition.wakeAll(); } diff --git a/sdrbase/webapi/webapiadapter.cpp b/sdrbase/webapi/webapiadapter.cpp index 4a7cbc9bb..04f1be848 100644 --- a/sdrbase/webapi/webapiadapter.cpp +++ b/sdrbase/webapi/webapiadapter.cpp @@ -102,7 +102,7 @@ int WebAPIAdapter::instanceSummary( response.setDspRxBits(SDR_RX_SAMP_SZ); response.setDspTxBits(SDR_TX_SAMP_SZ); response.setPid(qApp->applicationPid()); -#if QT_VERSION >= 0x050400 +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) *response.getArchitecture() = QString(QSysInfo::currentCpuArchitecture()); *response.getOs() = QString(QSysInfo::prettyProductName()); #endif diff --git a/sdrgui/dsp/scopevis.cpp b/sdrgui/dsp/scopevis.cpp index 9d5faa3e3..a39e2f66c 100644 --- a/sdrgui/dsp/scopevis.cpp +++ b/sdrgui/dsp/scopevis.cpp @@ -16,6 +16,7 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include #include #include @@ -619,15 +620,27 @@ int ScopeVis::processTraces(const SampleVector::const_iterator& cbegin, const Sa // display only at trace end if trace time is less than 1 second if (traceTime < 1.0f) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) if (m_glScope->getProcessingTraceIndex().loadRelaxed() < 0) { m_glScope->newTraces(m_traces.m_traces, m_traces.currentBufferIndex(), &m_traces.m_projectionTypes); } +#else + if (m_glScope->getProcessingTraceIndex().load() < 0) { + m_glScope->newTraces(m_traces.m_traces, m_traces.currentBufferIndex(), &m_traces.m_projectionTypes); + } +#endif } // switch to next buffer only if it is not being processed by the scope +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) if (m_glScope->getProcessingTraceIndex().loadRelaxed() != (((int) m_traces.currentBufferIndex() + 1) % 2)) { m_traces.switchBuffer(); } +#else + if (m_glScope->getProcessingTraceIndex().load() != (((int) m_traces.currentBufferIndex() + 1) % 2)) { + m_traces.switchBuffer(); + } +#endif return end - begin; // return remainder count } diff --git a/sdrgui/gui/glscope.cpp b/sdrgui/gui/glscope.cpp index 9d0c0d630..9d1aa27e9 100644 --- a/sdrgui/gui/glscope.cpp +++ b/sdrgui/gui/glscope.cpp @@ -16,6 +16,7 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include #include #include #include @@ -135,7 +136,11 @@ void GLScope::newTraces(std::vector *traces, int traceIndex, std::vecto if (m_dataChanged.testAndSetOrdered(0, 1)) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) m_processingTraceIndex.storeRelaxed(traceIndex); +#else + m_processingTraceIndex.store(traceIndex); +#endif m_traces = &traces[traceIndex]; m_projectionTypes = projectionTypes; } @@ -834,8 +839,13 @@ void GLScope::paintGL() drawMarkers(); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) m_dataChanged.storeRelaxed(0); m_processingTraceIndex.storeRelaxed(-1); +#else + m_dataChanged.store(0); + m_processingTraceIndex.store(-1); +#endif m_mutex.unlock(); } @@ -2012,9 +2022,15 @@ void GLScope::drawTextOverlay( void GLScope::tick() { +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) if (m_dataChanged.loadRelaxed()) { update(); } +#else + if (m_dataChanged.load()) { + update(); + } +#endif } void GLScope::connectTimer(const QTimer &timer) diff --git a/sdrgui/mainwindow.cpp b/sdrgui/mainwindow.cpp index 6828c8906..ed0462fc2 100644 --- a/sdrgui/mainwindow.cpp +++ b/sdrgui/mainwindow.cpp @@ -743,7 +743,7 @@ void MainWindow::saveCommandSettings() void MainWindow::createStatusBar() { QString qtVersionStr = QString("Qt %1 ").arg(QT_VERSION_STR); -#if QT_VERSION >= 0x050400 +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) m_showSystemWidget = new QLabel("SDRangel " + qApp->applicationVersion() + " " + qtVersionStr + QSysInfo::currentCpuArchitecture() + " " + QSysInfo::prettyProductName(), this); #else From 1e5ae8ea0f45a8041ab62c610f20363d3615ef80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Tue, 3 Nov 2020 13:52:12 +0100 Subject: [PATCH 08/19] Define _USE_MATH_DEFINES and clean M_PI redefinitions --- CMakeLists.txt | 5 +++++ plugins/channelrx/demodadsb/adsbdemodgui.cpp | 1 - plugins/channelrx/demodbfm/rdsdemod.cpp | 7 +------ plugins/channelrx/demoddatv/leansdr/dvb.h | 7 ++----- plugins/channelrx/demoddatv/leansdr/math.h | 6 +----- plugins/channelrx/demodnfm/nfmdemodsink.cpp | 2 +- plugins/channeltx/modpacket/packetmodbpfdialog.cpp | 1 - plugins/samplesource/testsource/testsourceworker.cpp | 5 ++--- sdrbase/audio/audiocompressorsnd.h | 5 ++--- sdrbase/audio/audiofilter.cpp | 3 +-- sdrbase/dsp/afsquelch.cpp | 4 +--- sdrbase/dsp/ctcssdetector.cpp | 1 - sdrbase/dsp/fftfilt.h | 5 ++--- sdrbase/dsp/fftwindow.h | 6 +----- sdrbase/dsp/firfilter.h | 3 +-- sdrbase/dsp/fmpreemphasis.cpp | 1 - sdrbase/dsp/freqlockcomplex.cpp | 3 +-- sdrbase/dsp/interpolator.cpp | 3 +-- sdrbase/dsp/misc.h | 5 +---- sdrbase/dsp/nco.cpp | 7 ++----- sdrbase/dsp/ncof.cpp | 6 +----- sdrbase/dsp/phasediscri.h | 8 +++----- sdrbase/dsp/phaselock.cpp | 4 +--- sdrbase/dsp/phaselockcomplex.cpp | 3 +-- sdrbase/dsp/projector.cpp | 3 +-- sdrbase/dsp/raisedcosine.h | 3 +-- sdrbase/dsp/recursivefilters.cpp | 5 +---- sdrbase/dsp/wfir.cpp | 6 ++---- sdrbase/util/azel.cpp | 1 - sdrgui/dsp/scopevis.h | 4 +--- sdrgui/gui/fmpreemphasisdialog.cpp | 1 - 31 files changed, 37 insertions(+), 87 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b87aa5052..017ca40c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,11 @@ add_definitions("-DCOPYRIGHT=\"${COPYRIGHT}\"") set(IDENTIFIER "com.${COMPANY}.${APPLICATION_NAME}") add_definitions("-DIDENTIFIER=\"${IDENTIFIER}\"") +add_compile_definitions(_USE_MATH_DEFINES) +if(WIN32) + add_compile_definitions(NOMINMAX) +endif() + find_package(Git) if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git/") execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.cpp b/plugins/channelrx/demodadsb/adsbdemodgui.cpp index f2d38561b..74a2769c9 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodgui.cpp @@ -16,7 +16,6 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#define _USE_MATH_DEFINES #include #include "device/deviceuiset.h" diff --git a/plugins/channelrx/demodbfm/rdsdemod.cpp b/plugins/channelrx/demodbfm/rdsdemod.cpp index 14d989c86..c14a3ed09 100644 --- a/plugins/channelrx/demodbfm/rdsdemod.cpp +++ b/plugins/channelrx/demodbfm/rdsdemod.cpp @@ -19,15 +19,10 @@ #include "../../channelrx/demodbfm/rdsdemod.h" #include -#include +#include #include #include -#undef M_PI -#define M_PI 3.14159265358979323846 -#undef M_PI_2 -#define M_PI_2 1.57079632679489661923 - const Real RDSDemod::m_pllBeta = 50; const Real RDSDemod::m_fsc = 1187.5; diff --git a/plugins/channelrx/demoddatv/leansdr/dvb.h b/plugins/channelrx/demoddatv/leansdr/dvb.h index 66676f536..cedb8463c 100644 --- a/plugins/channelrx/demoddatv/leansdr/dvb.h +++ b/plugins/channelrx/demoddatv/leansdr/dvb.h @@ -17,17 +17,14 @@ #ifndef LEANSDR_DVB_H #define LEANSDR_DVB_H -#include +#include +#include #include "leansdr/convolutional.h" #include "leansdr/rs.h" #include "leansdr/sdr.h" #include "leansdr/viterbi.h" -#ifndef M_PI -# define M_PI 3.14159265358979323846 -#endif - namespace leansdr { diff --git a/plugins/channelrx/demoddatv/leansdr/math.h b/plugins/channelrx/demoddatv/leansdr/math.h index 24fba2406..64bcbaaca 100644 --- a/plugins/channelrx/demoddatv/leansdr/math.h +++ b/plugins/channelrx/demoddatv/leansdr/math.h @@ -17,13 +17,9 @@ #ifndef LEANSDR_MATH_H #define LEANSDR_MATH_H -#include +#include #include -#ifndef M_PI -# define M_PI 3.14159265358979323846 -#endif - namespace leansdr { diff --git a/plugins/channelrx/demodnfm/nfmdemodsink.cpp b/plugins/channelrx/demodnfm/nfmdemodsink.cpp index d51f02f0f..70cd50506 100644 --- a/plugins/channelrx/demodnfm/nfmdemodsink.cpp +++ b/plugins/channelrx/demodnfm/nfmdemodsink.cpp @@ -15,7 +15,7 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include +#include #include #include diff --git a/plugins/channeltx/modpacket/packetmodbpfdialog.cpp b/plugins/channeltx/modpacket/packetmodbpfdialog.cpp index c318d0658..0f7032f9c 100644 --- a/plugins/channeltx/modpacket/packetmodbpfdialog.cpp +++ b/plugins/channeltx/modpacket/packetmodbpfdialog.cpp @@ -15,7 +15,6 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#define _USE_MATH_DEFINES #include #include "packetmodbpfdialog.h" #include "ui_packetmodbpfdialog.h" diff --git a/plugins/samplesource/testsource/testsourceworker.cpp b/plugins/samplesource/testsource/testsourceworker.cpp index 188f7f704..4da7a74e0 100644 --- a/plugins/samplesource/testsource/testsourceworker.cpp +++ b/plugins/samplesource/testsource/testsourceworker.cpp @@ -15,9 +15,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#define _USE_MATH_DEFINES -#include -#include +#include +#include #include #include "testsourceworker.h" diff --git a/sdrbase/audio/audiocompressorsnd.h b/sdrbase/audio/audiocompressorsnd.h index 712152db2..41d6f80fc 100644 --- a/sdrbase/audio/audiocompressorsnd.h +++ b/sdrbase/audio/audiocompressorsnd.h @@ -25,8 +25,7 @@ #ifndef SDRBASE_AUDIO_AUDIOCOMPRESSORSND_H_ #define SDRBASE_AUDIO_AUDIOCOMPRESSORSND_H_ -#define _USE_MATH_DEFINES -#include +#include // maximum number of samples in the delay buffer #define AUDIOCOMPRESSORSND_SF_COMPRESSOR_MAXDELAY 1024 @@ -161,7 +160,7 @@ private: static inline float fixf(float v, float def){ // fix NaN and infinity values that sneak in... not sure why this is needed, but it is - if (isnan(v) || isinf(v)) + if (std::isnan(v) || std::isinf(v)) return def; return v; } diff --git a/sdrbase/audio/audiofilter.cpp b/sdrbase/audio/audiofilter.cpp index d6f01f5bd..9957b0f68 100644 --- a/sdrbase/audio/audiofilter.cpp +++ b/sdrbase/audio/audiofilter.cpp @@ -15,8 +15,7 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#define _USE_MATH_DEFINES -#include +#include #include #include diff --git a/sdrbase/dsp/afsquelch.cpp b/sdrbase/dsp/afsquelch.cpp index faadf3074..1ebaa75a6 100644 --- a/sdrbase/dsp/afsquelch.cpp +++ b/sdrbase/dsp/afsquelch.cpp @@ -15,11 +15,9 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include +#include #include "dsp/afsquelch.h" -#undef M_PI -#define M_PI 3.14159265358979323846 AFSquelch::AFSquelch() : m_nbAvg(128), diff --git a/sdrbase/dsp/ctcssdetector.cpp b/sdrbase/dsp/ctcssdetector.cpp index df073562f..019c5a418 100644 --- a/sdrbase/dsp/ctcssdetector.cpp +++ b/sdrbase/dsp/ctcssdetector.cpp @@ -17,7 +17,6 @@ // along with this program. If not, see . // ////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define _USE_MATH_DEFINES #include #include "dsp/ctcssdetector.h" diff --git a/sdrbase/dsp/fftfilt.h b/sdrbase/dsp/fftfilt.h index 5c3e0222c..fa02d5432 100644 --- a/sdrbase/dsp/fftfilt.h +++ b/sdrbase/dsp/fftfilt.h @@ -6,12 +6,11 @@ #define _FFTFILT_H #include +#include + #include "gfft.h" #include "export.h" -#undef M_PI -#define M_PI 3.14159265358979323846 - //---------------------------------------------------------------------- class SDRBASE_API fftfilt { diff --git a/sdrbase/dsp/fftwindow.h b/sdrbase/dsp/fftwindow.h index 1bcbb6bc1..32fbd7ca7 100644 --- a/sdrbase/dsp/fftwindow.h +++ b/sdrbase/dsp/fftwindow.h @@ -20,14 +20,10 @@ #define INCLUDE_FFTWINDOW_H #include -#define _USE_MATH_DEFINES -#include +#include #include "dsp/dsptypes.h" #include "export.h" -#undef M_PI -#define M_PI 3.14159265358979323846 - class SDRBASE_API FFTWindow { public: enum Function { diff --git a/sdrbase/dsp/firfilter.h b/sdrbase/dsp/firfilter.h index 0ba6334a5..d59cb3823 100644 --- a/sdrbase/dsp/firfilter.h +++ b/sdrbase/dsp/firfilter.h @@ -18,8 +18,7 @@ #pragma once -#define _USE_MATH_DEFINES -#include +#include #include "dsp/dsptypes.h" #include "export.h" diff --git a/sdrbase/dsp/fmpreemphasis.cpp b/sdrbase/dsp/fmpreemphasis.cpp index 6e33ef431..0df31d38e 100644 --- a/sdrbase/dsp/fmpreemphasis.cpp +++ b/sdrbase/dsp/fmpreemphasis.cpp @@ -16,7 +16,6 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#define _USE_MATH_DEFINES #include #include #include "dsp/fmpreemphasis.h" diff --git a/sdrbase/dsp/freqlockcomplex.cpp b/sdrbase/dsp/freqlockcomplex.cpp index 59ce97e09..79a4e4018 100644 --- a/sdrbase/dsp/freqlockcomplex.cpp +++ b/sdrbase/dsp/freqlockcomplex.cpp @@ -22,8 +22,7 @@ /////////////////////////////////////////////////////////////////////////////////// #include "freqlockcomplex.h" -#define _USE_MATH_DEFINES -#include +#include FreqLockComplex::FreqLockComplex() : m_a0(0.998), diff --git a/sdrbase/dsp/interpolator.cpp b/sdrbase/dsp/interpolator.cpp index 467ed0a48..9ab79d84d 100644 --- a/sdrbase/dsp/interpolator.cpp +++ b/sdrbase/dsp/interpolator.cpp @@ -1,5 +1,4 @@ -#define _USE_MATH_DEFINES -#include +#include #include #include "dsp/interpolator.h" diff --git a/sdrbase/dsp/misc.h b/sdrbase/dsp/misc.h index eb0e411cf..f0c73f1f0 100644 --- a/sdrbase/dsp/misc.h +++ b/sdrbase/dsp/misc.h @@ -24,10 +24,7 @@ #ifndef _MISC_H #define _MISC_H -#include - -#undef M_PI -#define M_PI 3.14159265358979323846 +#include inline float sinc(float x) { diff --git a/sdrbase/dsp/nco.cpp b/sdrbase/dsp/nco.cpp index 57d072327..6eda52fdb 100644 --- a/sdrbase/dsp/nco.cpp +++ b/sdrbase/dsp/nco.cpp @@ -17,13 +17,10 @@ /////////////////////////////////////////////////////////////////////////////////// #include -#include -#define _USE_MATH_DEFINES -#include +#include +#include #include "dsp/nco.h" -#undef M_PI -#define M_PI 3.14159265358979323846 Real NCO::m_table[NCO::TableSize]; bool NCO::m_tableInitialized = false; diff --git a/sdrbase/dsp/ncof.cpp b/sdrbase/dsp/ncof.cpp index 48011671c..4becab475 100644 --- a/sdrbase/dsp/ncof.cpp +++ b/sdrbase/dsp/ncof.cpp @@ -17,13 +17,9 @@ #include #include -#define _USE_MATH_DEFINES -#include +#include #include "dsp/ncof.h" -#undef M_PI -#define M_PI 3.14159265358979323846 - Real NCOF::m_table[NCOF::TableSize+1]; bool NCOF::m_tableInitialized = false; float NCOF::m_tableSizeLimit = (float) NCOF::TableSize; diff --git a/sdrbase/dsp/phasediscri.h b/sdrbase/dsp/phasediscri.h index e479c40e4..cb3059936 100644 --- a/sdrbase/dsp/phasediscri.h +++ b/sdrbase/dsp/phasediscri.h @@ -19,11 +19,9 @@ #ifndef INCLUDE_DSP_PHASEDISCRI_H_ #define INCLUDE_DSP_PHASEDISCRI_H_ +#include #include "dsp/dsptypes.h" -#undef M_PI -#define M_PI 3.14159265358979323846 - class PhaseDiscriminators { public: @@ -167,8 +165,8 @@ private: } - #define PI_FLOAT 3.14159265f - #define PIBY2_FLOAT 1.5707963f + #define PI_FLOAT float(M_PI) + #define PIBY2_FLOAT float(M_PI_2) // |error| < 0.005 float atan2_approximation2( float y, float x ) { diff --git a/sdrbase/dsp/phaselock.cpp b/sdrbase/dsp/phaselock.cpp index 503f85bca..035a2de17 100644 --- a/sdrbase/dsp/phaselock.cpp +++ b/sdrbase/dsp/phaselock.cpp @@ -16,11 +16,9 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include +#include #include "dsp/phaselock.h" -#undef M_PI -#define M_PI 3.14159265358979323846 // Construct phase-locked loop. PhaseLock::PhaseLock(Real freq, Real bandwidth, Real minsignal) diff --git a/sdrbase/dsp/phaselockcomplex.cpp b/sdrbase/dsp/phaselockcomplex.cpp index a5fdfe8ab..523469059 100644 --- a/sdrbase/dsp/phaselockcomplex.cpp +++ b/sdrbase/dsp/phaselockcomplex.cpp @@ -22,8 +22,7 @@ /////////////////////////////////////////////////////////////////////////////////// #include -#define _USE_MATH_DEFINES -#include +#include #include "phaselockcomplex.h" PhaseLockComplex::PhaseLockComplex() : diff --git a/sdrbase/dsp/projector.cpp b/sdrbase/dsp/projector.cpp index afe98ad5a..1add3dcf0 100644 --- a/sdrbase/dsp/projector.cpp +++ b/sdrbase/dsp/projector.cpp @@ -16,8 +16,7 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#define _USE_MATH_DEFINES -#include +#include #include "projector.h" Projector::Projector(ProjectionType projectionType) : diff --git a/sdrbase/dsp/raisedcosine.h b/sdrbase/dsp/raisedcosine.h index 98a82bee2..5e9e51c18 100644 --- a/sdrbase/dsp/raisedcosine.h +++ b/sdrbase/dsp/raisedcosine.h @@ -19,8 +19,7 @@ #ifndef INCLUDE_RAISEDCOSINE_H #define INCLUDE_RAISEDCOSINE_H -#define _USE_MATH_DEFINES -#include +#include #include "dsp/dsptypes.h" // Raised-cosine low-pass filter for pulse shaping, without intersymbol interference (ISI) diff --git a/sdrbase/dsp/recursivefilters.cpp b/sdrbase/dsp/recursivefilters.cpp index f246e3ed2..d5f468943 100644 --- a/sdrbase/dsp/recursivefilters.cpp +++ b/sdrbase/dsp/recursivefilters.cpp @@ -15,12 +15,9 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include +#include #include "recursivefilters.h" -#undef M_PI -#define M_PI 3.14159265358979323846 - SecondOrderRecursiveFilter::SecondOrderRecursiveFilter(float samplingFrequency, float centerFrequency, float r) : m_r(r), m_frequencyRatio(centerFrequency/samplingFrequency), diff --git a/sdrbase/dsp/wfir.cpp b/sdrbase/dsp/wfir.cpp index e6df32cd2..642bbe989 100644 --- a/sdrbase/dsp/wfir.cpp +++ b/sdrbase/dsp/wfir.cpp @@ -4,15 +4,13 @@ http://www.iowahills.com */ -#include +#include #include #include #include "wfir.h" -#undef M_PI -#define M_PI 3.14159265358979323846 -#define M_2PI 6.28318530717958647692 +#define M_2PI (2*M_PI) // This first calculates the impulse response for a rectangular window. // It then applies the windowing function of choice to the impulse response. diff --git a/sdrbase/util/azel.cpp b/sdrbase/util/azel.cpp index 4bb7494bb..7a9aeeb8b 100644 --- a/sdrbase/util/azel.cpp +++ b/sdrbase/util/azel.cpp @@ -17,7 +17,6 @@ #include "azel.h" -#define _USE_MATH_DEFINES #include // Calculate cartesian distance between two points diff --git a/sdrgui/dsp/scopevis.h b/sdrgui/dsp/scopevis.h index 3e01a3bf3..b8b5df5f6 100644 --- a/sdrgui/dsp/scopevis.h +++ b/sdrgui/dsp/scopevis.h @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include @@ -37,8 +37,6 @@ #include "util/message.h" #include "util/doublebuffer.h" -#undef M_PI -#define M_PI 3.14159265358979323846 class GLScope; diff --git a/sdrgui/gui/fmpreemphasisdialog.cpp b/sdrgui/gui/fmpreemphasisdialog.cpp index 54ddd80b6..37d1ef7a0 100644 --- a/sdrgui/gui/fmpreemphasisdialog.cpp +++ b/sdrgui/gui/fmpreemphasisdialog.cpp @@ -15,7 +15,6 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#define _USE_MATH_DEFINES #include #include "fmpreemphasisdialog.h" #include "ui_fmpreemphasisdialog.h" From 00ba5115f3a0b4d792ef1e7f397cfe5c51b7214f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Tue, 3 Nov 2020 14:40:14 +0100 Subject: [PATCH 09/19] NFMDemodSink: Proper audio scaling to 16-bit --- plugins/channelrx/demodnfm/nfmdemodsink.cpp | 14 ++++----- plugins/channelrx/demodnfm/nfmdemodsink.h | 33 --------------------- sdrbase/dsp/firfilter.cpp | 13 ++++++++ sdrbase/dsp/firfilter.h | 20 +------------ sdrbase/dsp/misc.h | 3 +- 5 files changed, 22 insertions(+), 61 deletions(-) diff --git a/plugins/channelrx/demodnfm/nfmdemodsink.cpp b/plugins/channelrx/demodnfm/nfmdemodsink.cpp index 70cd50506..6dcef3b6f 100644 --- a/plugins/channelrx/demodnfm/nfmdemodsink.cpp +++ b/plugins/channelrx/demodnfm/nfmdemodsink.cpp @@ -27,6 +27,7 @@ #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "dsp/devicesamplemimo.h" +#include "dsp/misc.h" #include "device/deviceapi.h" #include "nfmdemodreport.h" @@ -58,6 +59,7 @@ NFMDemodSink::NFMDemodSink() : { m_agcLevel = 1.0; m_audioBuffer.resize(1<<16); + m_phaseDiscri.setFMScaling(1.0f); applySettings(m_settings, true); applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true); @@ -174,9 +176,11 @@ void NFMDemodSink::processOneSample(Complex &ci) if (!m_settings.m_audioMute && (m_settings.m_ctcssOn && m_ctcssIndexSelected == ctcssIndex || m_ctcssIndexSelected == 0)) { Real audioSample = m_squelchDelayLine.readBack(m_squelchGate); + Q_ASSERT(audioSample >= -1.0f && audioSample <= 1.0f); audioSample = m_settings.m_highPass ? m_bandpass.filter(audioSample) : m_lowpass.filter(audioSample); - audioSample *= m_settings.m_volume * m_filterTaps; - sample = std::lrint(audioSample); + + audioSample *= m_settings.m_volume * std::numeric_limits::max(); + sample = clamp(std::rint(audioSample), std::numeric_limits::lowest(), std::numeric_limits::max()); } } @@ -258,11 +262,6 @@ void NFMDemodSink::applySettings(const NFMDemodSettings& settings, bool force) m_interpolatorDistance = (Real) m_channelSampleRate / (Real) m_audioSampleRate; } - if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force) - { - m_phaseDiscri.setFMScaling((8.0f*m_audioSampleRate) / static_cast(settings.m_fmDeviation)); // integrate 4x factor - } - if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || force) { m_bandpass.create(m_filterTaps, m_audioSampleRate, 300.0, settings.m_afBandwidth); @@ -324,7 +323,6 @@ void NFMDemodSink::applyAudioSampleRate(unsigned int sampleRate) m_afSquelch.setCoefficients(sampleRate/2000, 600, sampleRate, 200, 0, afSqTones); // 0.5ms test period, 300ms average span, audio SR, 100ms attack, no decay } - m_phaseDiscri.setFMScaling((8.0f*sampleRate) / static_cast(m_settings.m_fmDeviation)); // integrate 4x factor m_audioFifo.setSize(sampleRate); m_squelchDelayLine.resize(sampleRate/2); m_interpolatorDistanceRemain = 0; diff --git a/plugins/channelrx/demodnfm/nfmdemodsink.h b/plugins/channelrx/demodnfm/nfmdemodsink.h index 74c8dc469..bca38c93c 100644 --- a/plugins/channelrx/demodnfm/nfmdemodsink.h +++ b/plugins/channelrx/demodnfm/nfmdemodsink.h @@ -139,39 +139,6 @@ private: void processOneSample(Complex &ci); MessageQueue *getMessageQueueToGUI() { return m_messageQueueToGUI; } - - inline float arctan2(Real y, Real x) - { - Real coeff_1 = M_PI / 4; - Real coeff_2 = 3 * coeff_1; - Real abs_y = fabs(y) + 1e-10; // kludge to prevent 0/0 condition - Real angle; - if( x>= 0) { - Real r = (x - abs_y) / (x + abs_y); - angle = coeff_1 - coeff_1 * r; - } else { - Real r = (x + abs_y) / (abs_y - x); - angle = coeff_2 - coeff_1 * r; - } - if(y < 0) { - return(-angle); - } else { - return(angle); - } - } - - inline Real angleDist(Real a, Real b) - { - Real dist = b - a; - - while(dist <= M_PI) - dist += 2 * M_PI; - while(dist >= M_PI) - dist -= 2 * M_PI; - - return dist; - } - }; #endif // INCLUDE_NFMDEMODSINK_H diff --git a/sdrbase/dsp/firfilter.cpp b/sdrbase/dsp/firfilter.cpp index ef3092583..dd287c348 100644 --- a/sdrbase/dsp/firfilter.cpp +++ b/sdrbase/dsp/firfilter.cpp @@ -52,6 +52,19 @@ void generateLowPassFilter(int nTaps, double sampleRate, double cutoff, std::vec int n = i - (nTaps - 1) / 2; taps[i] *= 0.42 + 0.5 * cos((2.0 * M_PI * n) / nTaps) + 0.08 * cos((4.0 * M_PI * n) / nTaps); } + + Real sum = 0; + size_t i; + + for (i = 0; i < taps.size() - 1; ++i) { + sum += taps[i] * 2.0; + } + + sum += taps[i]; + + for (i = 0; i < taps.size(); ++i) { + taps[i] /= sum; + } } } diff --git a/sdrbase/dsp/firfilter.h b/sdrbase/dsp/firfilter.h index d59cb3823..282e52505 100644 --- a/sdrbase/dsp/firfilter.h +++ b/sdrbase/dsp/firfilter.h @@ -20,6 +20,7 @@ #include #include "dsp/dsptypes.h" +#include "dsp/misc.h" #include "export.h" namespace FirFilterGenerators @@ -74,22 +75,6 @@ protected: } } - void normalize(Real sum_fix = 0.0) - { - Real sum = 0; - size_t i; - - for (i = 0; i < m_taps.size() - 1; ++i) { - sum += m_taps[i] * 2.0; - } - - sum += m_taps[i] + sum_fix; - - for (i = 0; i < m_taps.size(); ++i) { - m_taps[i] /= sum; - } - } - protected: std::vector m_taps; std::vector m_samples; @@ -104,7 +89,6 @@ public: { this->init(nTaps); FirFilterGenerators::generateLowPassFilter(nTaps, sampleRate, cutoff, this->m_taps); - this->normalize(); } }; @@ -129,7 +113,6 @@ struct Bandpass : public FirFilter } this->m_taps[this->m_taps.size() - 1] += 1; - this->normalize(-1.0); } }; @@ -146,6 +129,5 @@ struct Highpass : public FirFilter } this->m_taps[this->m_taps.size() - 1] += 1; - this->normalize(-1.0); } }; diff --git a/sdrbase/dsp/misc.h b/sdrbase/dsp/misc.h index f0c73f1f0..a4b41b65b 100644 --- a/sdrbase/dsp/misc.h +++ b/sdrbase/dsp/misc.h @@ -36,7 +36,8 @@ inline float cosc(float x) return (fabs(x) < 1e-10) ? 0.0 : ((1.0 - cos(M_PI * x)) / (M_PI * x)); } -inline float clamp(float x, float min, float max) +template +inline T clamp(T x, T min, T max) { return (x < min) ? min : ((x > max) ? max : x); } From 38755e35f1915a59ecc41eb9fde4033b5318d7cc Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 5 Nov 2020 00:00:34 +0100 Subject: [PATCH 10/19] NFM demod: restored expected FM deviation --- plugins/channelrx/demodnfm/nfmdemodsink.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/channelrx/demodnfm/nfmdemodsink.cpp b/plugins/channelrx/demodnfm/nfmdemodsink.cpp index 6dcef3b6f..5d455545c 100644 --- a/plugins/channelrx/demodnfm/nfmdemodsink.cpp +++ b/plugins/channelrx/demodnfm/nfmdemodsink.cpp @@ -176,7 +176,6 @@ void NFMDemodSink::processOneSample(Complex &ci) if (!m_settings.m_audioMute && (m_settings.m_ctcssOn && m_ctcssIndexSelected == ctcssIndex || m_ctcssIndexSelected == 0)) { Real audioSample = m_squelchDelayLine.readBack(m_squelchGate); - Q_ASSERT(audioSample >= -1.0f && audioSample <= 1.0f); audioSample = m_settings.m_highPass ? m_bandpass.filter(audioSample) : m_lowpass.filter(audioSample); audioSample *= m_settings.m_volume * std::numeric_limits::max(); @@ -262,6 +261,11 @@ void NFMDemodSink::applySettings(const NFMDemodSettings& settings, bool force) m_interpolatorDistance = (Real) m_channelSampleRate / (Real) m_audioSampleRate; } + if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force) + { + m_phaseDiscri.setFMScaling(m_audioSampleRate / static_cast(settings.m_fmDeviation)); // integrate 4x factor + } + if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || force) { m_bandpass.create(m_filterTaps, m_audioSampleRate, 300.0, settings.m_afBandwidth); @@ -323,6 +327,7 @@ void NFMDemodSink::applyAudioSampleRate(unsigned int sampleRate) m_afSquelch.setCoefficients(sampleRate/2000, 600, sampleRate, 200, 0, afSqTones); // 0.5ms test period, 300ms average span, audio SR, 100ms attack, no decay } + m_phaseDiscri.setFMScaling(sampleRate / static_cast(m_settings.m_fmDeviation)); m_audioFifo.setSize(sampleRate); m_squelchDelayLine.resize(sampleRate/2); m_interpolatorDistanceRemain = 0; From 7ad8c046f257bcac2866b9ebfec502befdfc79eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Tue, 3 Nov 2020 16:36:05 +0100 Subject: [PATCH 11/19] NFMDemodSink: Fix ctcssOn logic --- plugins/channelrx/demodnfm/nfmdemodsink.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/channelrx/demodnfm/nfmdemodsink.cpp b/plugins/channelrx/demodnfm/nfmdemodsink.cpp index 5d455545c..8738420c6 100644 --- a/plugins/channelrx/demodnfm/nfmdemodsink.cpp +++ b/plugins/channelrx/demodnfm/nfmdemodsink.cpp @@ -173,7 +173,7 @@ void NFMDemodSink::processOneSample(Complex &ci) } } - if (!m_settings.m_audioMute && (m_settings.m_ctcssOn && m_ctcssIndexSelected == ctcssIndex || m_ctcssIndexSelected == 0)) + if (!m_settings.m_audioMute && (!m_settings.m_ctcssOn || m_ctcssIndexSelected == ctcssIndex || m_ctcssIndexSelected == 0)) { Real audioSample = m_squelchDelayLine.readBack(m_squelchGate); audioSample = m_settings.m_highPass ? m_bandpass.filter(audioSample) : m_lowpass.filter(audioSample); From d727abe79ecdc7edf0caef7793d5268d7327ffdb Mon Sep 17 00:00:00 2001 From: AsciiWolf Date: Thu, 5 Nov 2020 14:20:50 +0100 Subject: [PATCH 12/19] Workaround Flatpak issues on Wayland --- flatpak/org.sdrangel.SDRangel.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flatpak/org.sdrangel.SDRangel.json b/flatpak/org.sdrangel.SDRangel.json index 523b7c3bb..a7f6bbc1f 100644 --- a/flatpak/org.sdrangel.SDRangel.json +++ b/flatpak/org.sdrangel.SDRangel.json @@ -14,7 +14,8 @@ "--share=ipc", "--socket=pulseaudio", "--socket=x11", - "--socket=wayland" + "--socket=wayland", + "--env=QT_QPA_PLATFORM=xcb" ], "modules": [ { From f2bd3e4b845a33a0a4591e9c23c2a14fd910fab6 Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 5 Nov 2020 08:31:38 +0100 Subject: [PATCH 13/19] Downgrade cmake version requirements --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 017ca40c9..46b31ef84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.16.0) +cmake_minimum_required(VERSION 3.10.0) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") From 41f0fec4f68c03853311f0d6b512281e7592171d Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 5 Nov 2020 11:11:43 +0100 Subject: [PATCH 14/19] sdrbase cmake: restored Boost_INCLUDE_DIRS --- devices/plutosdr/CMakeLists.txt | 1 + devices/usrp/CMakeLists.txt | 5 +++++ plugins/channelrx/chanalyzer/CMakeLists.txt | 3 ++- plugins/channelrx/demodatv/CMakeLists.txt | 1 + plugins/channelrx/demodbfm/CMakeLists.txt | 1 + plugins/channelrx/filesink/CMakeLists.txt | 1 + plugins/channelrx/localsink/CMakeLists.txt | 1 + plugins/channelrx/remotesink/CMakeLists.txt | 1 + plugins/channeltx/localsource/CMakeLists.txt | 1 + plugins/channeltx/mod802.15.4/CMakeLists.txt | 1 + plugins/channeltx/remotesource/CMakeLists.txt | 1 + plugins/samplesink/remoteoutput/CMakeLists.txt | 1 + plugins/samplesink/usrpoutput/CMakeLists.txt | 1 + plugins/samplesource/kiwisdr/CMakeLists.txt | 3 ++- plugins/samplesource/remoteinput/CMakeLists.txt | 1 + plugins/samplesource/usrpinput/CMakeLists.txt | 1 + sdrbase/CMakeLists.txt | 2 +- sdrgui/CMakeLists.txt | 3 ++- 18 files changed, 25 insertions(+), 4 deletions(-) diff --git a/devices/plutosdr/CMakeLists.txt b/devices/plutosdr/CMakeLists.txt index 4a58a5b33..db56a61d0 100644 --- a/devices/plutosdr/CMakeLists.txt +++ b/devices/plutosdr/CMakeLists.txt @@ -19,6 +19,7 @@ set(plutosdrdevice_HEADERS include_directories( ${LIBIIO_INCLUDE_DIR} ${ICONV_INCLUDE_DIR} + ${Boost_INCLUDE_DIRS} ) add_library(plutosdrdevice SHARED diff --git a/devices/usrp/CMakeLists.txt b/devices/usrp/CMakeLists.txt index ce6fd890f..ec26fc273 100644 --- a/devices/usrp/CMakeLists.txt +++ b/devices/usrp/CMakeLists.txt @@ -15,6 +15,7 @@ set(usrpdevice_HEADERS include_directories( ${UHD_INCLUDE_DIR} + ${Boost_INCLUDE_DIRS} ) add_library(usrpdevice SHARED @@ -24,6 +25,10 @@ add_library(usrpdevice SHARED set_target_properties(usrpdevice PROPERTIES DEFINE_SYMBOL "devices_EXPORTS") +if (NOT WIN32) + link_directories(${Boost_LIBRARY_DIRS}) +endif() + target_link_libraries(usrpdevice ${UHD_LIBRARIES} Boost::disable_autolinking diff --git a/plugins/channelrx/chanalyzer/CMakeLists.txt b/plugins/channelrx/chanalyzer/CMakeLists.txt index 58f634239..ea6f44267 100644 --- a/plugins/channelrx/chanalyzer/CMakeLists.txt +++ b/plugins/channelrx/chanalyzer/CMakeLists.txt @@ -22,7 +22,8 @@ set(chanalyzer_HEADERS ) include_directories( - ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${Boost_INCLUDE_DIRS} ) add_library(chanalyzer SHARED diff --git a/plugins/channelrx/demodatv/CMakeLists.txt b/plugins/channelrx/demodatv/CMakeLists.txt index 3760b4e0c..570c6180a 100644 --- a/plugins/channelrx/demodatv/CMakeLists.txt +++ b/plugins/channelrx/demodatv/CMakeLists.txt @@ -23,6 +23,7 @@ set(atv_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${Boost_INCLUDE_DIRS} ) add_library(demodatv SHARED diff --git a/plugins/channelrx/demodbfm/CMakeLists.txt b/plugins/channelrx/demodbfm/CMakeLists.txt index 14611fdf4..7e6f22d25 100644 --- a/plugins/channelrx/demodbfm/CMakeLists.txt +++ b/plugins/channelrx/demodbfm/CMakeLists.txt @@ -30,6 +30,7 @@ set(bfm_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/channelrx/filesink/CMakeLists.txt b/plugins/channelrx/filesink/CMakeLists.txt index b45f7f6af..6f230ca76 100644 --- a/plugins/channelrx/filesink/CMakeLists.txt +++ b/plugins/channelrx/filesink/CMakeLists.txt @@ -22,6 +22,7 @@ set(filesink_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/channelrx/localsink/CMakeLists.txt b/plugins/channelrx/localsink/CMakeLists.txt index 4d6d6f2e0..f03b740aa 100644 --- a/plugins/channelrx/localsink/CMakeLists.txt +++ b/plugins/channelrx/localsink/CMakeLists.txt @@ -22,6 +22,7 @@ set(localsink_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/channelrx/remotesink/CMakeLists.txt b/plugins/channelrx/remotesink/CMakeLists.txt index 3c2faefb4..fe6c61b3f 100644 --- a/plugins/channelrx/remotesink/CMakeLists.txt +++ b/plugins/channelrx/remotesink/CMakeLists.txt @@ -35,6 +35,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${CM256CC_INCLUDE_DIR} ${CUSTOM_WINDOWS_INCLUDE} + ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/channeltx/localsource/CMakeLists.txt b/plugins/channeltx/localsource/CMakeLists.txt index f59b00f21..ead523a10 100644 --- a/plugins/channeltx/localsource/CMakeLists.txt +++ b/plugins/channeltx/localsource/CMakeLists.txt @@ -22,6 +22,7 @@ set(localsource_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/channeltx/mod802.15.4/CMakeLists.txt b/plugins/channeltx/mod802.15.4/CMakeLists.txt index 56d2e478e..072a6adb2 100644 --- a/plugins/channeltx/mod802.15.4/CMakeLists.txt +++ b/plugins/channeltx/mod802.15.4/CMakeLists.txt @@ -21,6 +21,7 @@ set(mod_ieee_802_15_4_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/channeltx/remotesource/CMakeLists.txt b/plugins/channeltx/remotesource/CMakeLists.txt index 73fcf2cc5..ec483a4e7 100644 --- a/plugins/channeltx/remotesource/CMakeLists.txt +++ b/plugins/channeltx/remotesource/CMakeLists.txt @@ -33,6 +33,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${CM256CC_INCLUDE_DIR} ${CUSTOM_WINDOWS_INCLUDE} + ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/samplesink/remoteoutput/CMakeLists.txt b/plugins/samplesink/remoteoutput/CMakeLists.txt index 455ab0f6e..e731370f2 100644 --- a/plugins/samplesink/remoteoutput/CMakeLists.txt +++ b/plugins/samplesink/remoteoutput/CMakeLists.txt @@ -35,6 +35,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${CMAKE_SOURCE_DIR}/devices ${CM256CC_INCLUDE_DIR} + ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/samplesink/usrpoutput/CMakeLists.txt b/plugins/samplesink/usrpoutput/CMakeLists.txt index 8bfeece74..3fc09108f 100644 --- a/plugins/samplesink/usrpoutput/CMakeLists.txt +++ b/plugins/samplesink/usrpoutput/CMakeLists.txt @@ -20,6 +20,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${CMAKE_SOURCE_DIR}/devices ${UHD_INCLUDE_DIR} + ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/samplesource/kiwisdr/CMakeLists.txt b/plugins/samplesource/kiwisdr/CMakeLists.txt index 0c03fa1b3..272344470 100644 --- a/plugins/samplesource/kiwisdr/CMakeLists.txt +++ b/plugins/samplesource/kiwisdr/CMakeLists.txt @@ -18,6 +18,7 @@ set(kiwisdr_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) @@ -54,4 +55,4 @@ target_link_libraries(${TARGET_NAME} ${TARGET_LIB_GUI} ) -install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) \ No newline at end of file +install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) diff --git a/plugins/samplesource/remoteinput/CMakeLists.txt b/plugins/samplesource/remoteinput/CMakeLists.txt index f6e1a519f..3041e77b5 100644 --- a/plugins/samplesource/remoteinput/CMakeLists.txt +++ b/plugins/samplesource/remoteinput/CMakeLists.txt @@ -30,6 +30,7 @@ set(remoteinput_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${CM256CC_INCLUDE_DIR} + ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/samplesource/usrpinput/CMakeLists.txt b/plugins/samplesource/usrpinput/CMakeLists.txt index 1fef67c28..948232fb8 100644 --- a/plugins/samplesource/usrpinput/CMakeLists.txt +++ b/plugins/samplesource/usrpinput/CMakeLists.txt @@ -20,6 +20,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${CMAKE_SOURCE_DIR}/devices ${UHD_INCLUDE_DIR} + ${Boost_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/sdrbase/CMakeLists.txt b/sdrbase/CMakeLists.txt index d4fe6dfd7..167cc445c 100644 --- a/sdrbase/CMakeLists.txt +++ b/sdrbase/CMakeLists.txt @@ -360,6 +360,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/logging ${CMAKE_SOURCE_DIR}/qrtplib ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${Boost_INCLUDE_DIRS} ${OPUS_INCLUDE_DIRS} ) @@ -380,7 +381,6 @@ target_link_libraries(sdrbase ${sdrbase_FFTW3F_LIB} ${sdrbase_SERIALDV_LIB} ${sdrbase_LIMERFE_LIB} - Boost::headers Qt5::Core Qt5::Multimedia Qt5::WebSockets diff --git a/sdrgui/CMakeLists.txt b/sdrgui/CMakeLists.txt index a949b0448..0284b7008 100644 --- a/sdrgui/CMakeLists.txt +++ b/sdrgui/CMakeLists.txt @@ -231,7 +231,8 @@ include_directories( ${CMAKE_SOURCE_DIR}/httpserver ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${OPENGL_INCLUDE_DIR} - ) + ${Boost_INCLUDE_DIRS} +) add_library(sdrgui SHARED ${sdrgui_SOURCES} From 3377fb084bfb412ae3be9eec8f0b2be40f1e92bc Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 5 Nov 2020 13:41:12 +0100 Subject: [PATCH 15/19] NFM demod: damper discriminator output amplitude by 2 to limit audio loudness --- plugins/channelrx/demodnfm/nfmdemodsink.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/channelrx/demodnfm/nfmdemodsink.cpp b/plugins/channelrx/demodnfm/nfmdemodsink.cpp index 8738420c6..8b39e1d7a 100644 --- a/plugins/channelrx/demodnfm/nfmdemodsink.cpp +++ b/plugins/channelrx/demodnfm/nfmdemodsink.cpp @@ -59,7 +59,7 @@ NFMDemodSink::NFMDemodSink() : { m_agcLevel = 1.0; m_audioBuffer.resize(1<<16); - m_phaseDiscri.setFMScaling(1.0f); + m_phaseDiscri.setFMScaling(0.5f); applySettings(m_settings, true); applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true); @@ -263,7 +263,7 @@ void NFMDemodSink::applySettings(const NFMDemodSettings& settings, bool force) if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force) { - m_phaseDiscri.setFMScaling(m_audioSampleRate / static_cast(settings.m_fmDeviation)); // integrate 4x factor + m_phaseDiscri.setFMScaling((0.5f *m_audioSampleRate) / static_cast(settings.m_fmDeviation)); // integrate 4x factor } if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || force) @@ -327,7 +327,7 @@ void NFMDemodSink::applyAudioSampleRate(unsigned int sampleRate) m_afSquelch.setCoefficients(sampleRate/2000, 600, sampleRate, 200, 0, afSqTones); // 0.5ms test period, 300ms average span, audio SR, 100ms attack, no decay } - m_phaseDiscri.setFMScaling(sampleRate / static_cast(m_settings.m_fmDeviation)); + m_phaseDiscri.setFMScaling((0.5f * sampleRate) / static_cast(m_settings.m_fmDeviation)); m_audioFifo.setSize(sampleRate); m_squelchDelayLine.resize(sampleRate/2); m_interpolatorDistanceRemain = 0; From fecbd54a354ecb26fd246f27d19ced469fbf901b Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 5 Nov 2020 13:55:05 +0100 Subject: [PATCH 16/19] Linux package build: do not build server flavor --- .appveyor.yml | 3 ++- debian/rules | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index b798601d2..103342f18 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -27,7 +27,8 @@ environment: CMAKE_CUSTOM_OPTIONS: "-DCMAKE_BUILD_TYPE=Release \ -DFORCE_SSE41=ON \ -DDEBUG_OUTPUT=ON \ - -DENABLE_EXTERNAL_LIBRARIES=ON" + -DENABLE_EXTERNAL_LIBRARIES=ON \ + -DBUILD_SERVER=OFF" for: - matrix: diff --git a/debian/rules b/debian/rules index c131bc0e1..3d4bf9ddb 100755 --- a/debian/rules +++ b/debian/rules @@ -4,7 +4,7 @@ # FORCE_SSE41 will be not accepted upstream override_dh_auto_configure: - dh_auto_configure -- -DFORCE_SSE41=ON -DENABLE_EXTERNAL_LIBRARIES=ON -DDEBUG_OUTPUT=ON + dh_auto_configure -- -DFORCE_SSE41=ON -DENABLE_EXTERNAL_LIBRARIES=ON -DDEBUG_OUTPUT=ON -DBUILD_SERVER=OFF override_dh_auto_test: echo "Skipping test step" From f1cf57bacd08b0f9c95cdac932be021cde0d4e50 Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 5 Nov 2020 23:21:04 +0100 Subject: [PATCH 17/19] NFM: review frequency deviation and NFM demod volume control --- doc/img/NFMdemod_plugin.png | Bin 22734 -> 24143 bytes doc/img/NFMdemod_plugin.xcf | Bin 90678 -> 89161 bytes plugins/channelrx/demodnfm/nfmdemodgui.cpp | 8 +++--- plugins/channelrx/demodnfm/nfmdemodgui.ui | 13 ++++++---- .../channelrx/demodnfm/nfmdemodsettings.cpp | 10 +++++--- plugins/channelrx/demodnfm/readme.md | 13 ++++++++-- plugins/channeltx/modnfm/nfmmodgui.ui | 24 +++++++++--------- plugins/channeltx/modnfm/nfmmodsource.cpp | 5 ++-- plugins/channeltx/modnfm/readme.md | 2 +- 9 files changed, 44 insertions(+), 31 deletions(-) diff --git a/doc/img/NFMdemod_plugin.png b/doc/img/NFMdemod_plugin.png index 56aeab4581d4c755e1723f476b8e8ae1a1bdd928..5c3147e44e5e869062aa1fbf650007b9687d7ffa 100644 GIT binary patch literal 24143 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
kd(PJ*&zA; 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 z>;?7%hkzr%JHQFxG;kKE1?quD;9cMva2;p`J^volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); - m_settings.m_volume = value / 10.0; + ui->volumeText->setText(QString("%1").arg(value)); + m_settings.m_volume = value / 100.0; applySettings(); } @@ -368,8 +368,8 @@ void NFMDemodGUI::displaySettings() ui->afBWText->setText(QString("%1 k").arg(m_settings.m_afBandwidth / 1000.0)); ui->afBW->setValue(m_settings.m_afBandwidth / 1000.0); - ui->volumeText->setText(QString("%1").arg(m_settings.m_volume, 0, 'f', 1)); - ui->volume->setValue(m_settings.m_volume * 10.0); + ui->volumeText->setText(QString("%1").arg(m_settings.m_volume*100.0, 0, 'f', 0)); + ui->volume->setValue(m_settings.m_volume * 100.0); ui->squelchGateText->setText(QString("%1").arg(m_settings.m_squelchGate * 10.0f, 0, 'f', 0)); ui->squelchGate->setValue(m_settings.m_squelchGate); diff --git a/plugins/channelrx/demodnfm/nfmdemodgui.ui b/plugins/channelrx/demodnfm/nfmdemodgui.ui index d7cb4820c..8d3eb29f8 100644 --- a/plugins/channelrx/demodnfm/nfmdemodgui.ui +++ b/plugins/channelrx/demodnfm/nfmdemodgui.ui @@ -336,16 +336,19 @@ - Sound volume + Sound volume (%) - 40 + 200 + + + 1 1 - 10 + 100 @@ -364,10 +367,10 @@ - Sound volume + Sound volume (%) - 1.0 + 100 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter diff --git a/plugins/channelrx/demodnfm/nfmdemodsettings.cpp b/plugins/channelrx/demodnfm/nfmdemodsettings.cpp index 55fb412c2..de5c3479a 100644 --- a/plugins/channelrx/demodnfm/nfmdemodsettings.cpp +++ b/plugins/channelrx/demodnfm/nfmdemodsettings.cpp @@ -23,13 +23,15 @@ #include "nfmdemodsettings.h" +// fixed |Carson (3k) |Carson (6k) +// | 11F3 16F3 | const int NFMDemodSettings::m_rfBW[] = { - 5000, 6250, 8330, 10000, 12500, 15000, 20000, 25000, 40000 + 5000, 6250, 8330, 11000, 16000, 20000, 25000, 40000 }; -const int NFMDemodSettings::m_fmDev[] = { // corresponding single side FM deviations at 0.4 * BW - 2000, 2500, 3330, 4000, 5000, 6000, 8000, 10000, 16000 +const int NFMDemodSettings::m_fmDev[] = { + 2500, 2500, 3330, 5000, 10000, 14000, 19000, 28000 }; -const int NFMDemodSettings::m_nbRfBW = 9; +const int NFMDemodSettings::m_nbRfBW = 8; NFMDemodSettings::NFMDemodSettings() : m_channelMarker(0) diff --git a/plugins/channelrx/demodnfm/readme.md b/plugins/channelrx/demodnfm/readme.md index 92f0b8021..f16fa47c8 100644 --- a/plugins/channelrx/demodnfm/readme.md +++ b/plugins/channelrx/demodnfm/readme.md @@ -24,7 +24,16 @@ Average total power in dB relative to a +/- 1.0 amplitude signal received in the

4: RF bandwidth

-This is the bandwidth in kHz of the channel signal before demodulation. It can be set in steps as 5, 6.25, 8.33, 10, 12.5, 15, 20, 25 and 40 kHz. The expected one side frequency deviation is 0.4 times the bandwidth. +This is the bandwidth in kHz of the channel signal before demodulation. It can take these values with the corresponding nominal frequency deviation: + + - **5** kHz: ± 1.25 kHz + - **6.25** kHz: ± 1.25 kHz + - **8.33** kHz: ± 1.67 kHz + - **11** kHz: ± 2.5 kHz (11F3) + - **16** kHz: ± 5 kHz (16F3) + - **20** kHz: ± 7 kHz + - **25** kHz: ± 9.5 kHz + - **40** kHz: ± 14 kHz ☞ The demodulation is done at the channel sample rate which is guaranteed not to be lower than the requested audio sample rate but can possibly be equal to it. This means that for correct operation in any case you must ensure that the sample rate of the audio device is not lower than the Nyquist rate required to process this channel bandwidth. @@ -36,7 +45,7 @@ This is the bandwidth of the audio signal in kHz (i.e. after demodulation). It c

6: Volume

-This is the volume of the audio signal from 0.0 (mute) to 4.0 (maximum). It can be varied continuously in 0.1 steps using the dial button. +This is the volume of the audio signal from 0% (mute) to 200% (maximum) of volume at nominal frequency deviation. It can be varied continuously 1% steps using the dial button.

7: Delta/Level squelch

diff --git a/plugins/channeltx/modnfm/nfmmodgui.ui b/plugins/channeltx/modnfm/nfmmodgui.ui index e154043a8..ea064368f 100644 --- a/plugins/channeltx/modnfm/nfmmodgui.ui +++ b/plugins/channeltx/modnfm/nfmmodgui.ui @@ -299,7 +299,7 @@ Modulation percentage
- 250 + 300 1 @@ -827,29 +827,29 @@
gui/rollupwidget.h
1 + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
LevelMeterVU QWidget
gui/levelmeter.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
CWKeyerGUI QWidget
gui/cwkeyergui.h
1
- - ValueDialZ - QWidget -
gui/valuedialz.h
- 1 -
diff --git a/plugins/channeltx/modnfm/nfmmodsource.cpp b/plugins/channeltx/modnfm/nfmmodsource.cpp index bc0d5e0c1..6ed08b9dd 100644 --- a/plugins/channeltx/modnfm/nfmmodsource.cpp +++ b/plugins/channeltx/modnfm/nfmmodsource.cpp @@ -134,11 +134,10 @@ void NFMModSource::modulateSample() calculateLevel(t); m_audioBufferFill++; - // 0.625 = 1/1.25 (heuristic) if (m_settings.m_ctcssOn) { - m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * (0.85f * m_bandpass.filter(t) + 0.15f * 0.625f * m_ctcssNco.next()) * (M_PI / 0.625f); + m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * (0.85f * m_bandpass.filter(t) + 0.15f * 0.625f * m_ctcssNco.next()) * 1.33f; } else { - m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * m_bandpass.filter(t) * (M_PI / 0.625f); + m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * m_bandpass.filter(t) * 1.33f; } // limit phasor range to ]-pi,pi] diff --git a/plugins/channeltx/modnfm/readme.md b/plugins/channeltx/modnfm/readme.md index 22139d828..f03bacb39 100644 --- a/plugins/channeltx/modnfm/readme.md +++ b/plugins/channeltx/modnfm/readme.md @@ -30,7 +30,7 @@ This is the bandwidth in khz of the modulating signal filtered before modulation

7: Frequency deviation

-Adjusts the frequency deviation in 0.1 kHz steps from 0 to 25 kHz +Adjusts the frequency deviation in 0.1 kHz steps from 0 to 30 kHz. This is the full deviation.

8: Volume

From fec07c0b083b1837628566a293ba2edf314c8ef3 Mon Sep 17 00:00:00 2001 From: f4exb Date: Fri, 6 Nov 2020 06:13:56 +0100 Subject: [PATCH 18/19] Switched back external/windows to f4exb --- .gitmodules | 2 +- external/windows | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 77e5c5a7f..e3dbe3009 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "external/windows"] path = external/windows - url = https://github.com/kasper93/sdrangel-windows-libraries.git + url = https://github.com/f4exb/sdrangel-windows-libraries.git diff --git a/external/windows b/external/windows index fd7d2b7a2..a47e94ace 160000 --- a/external/windows +++ b/external/windows @@ -1 +1 @@ -Subproject commit fd7d2b7a202631642ced85cf4268ec46987a4d60 +Subproject commit a47e94ace126e9562fdc58d27fce95412e10d932 From 556ddaaff6f55033dab8f7e7bc27f83803bd9439 Mon Sep 17 00:00:00 2001 From: f4exb Date: Fri, 6 Nov 2020 07:04:46 +0100 Subject: [PATCH 19/19] Updated versions and changelogs --- CHANGELOG | 12 ++++++++++++ CMakeLists.txt | 2 +- debian/changelog | 12 ++++++++++++ plugins/channelrx/demodnfm/nfmplugin.cpp | 2 +- plugins/channeltx/modnfm/nfmmodplugin.cpp | 2 +- plugins/samplesource/kiwisdr/kiwisdrplugin.cpp | 2 +- 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a044c7895..e1a8e560b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,15 @@ +sdrangel (4.21.2-1) unstable; urgency=medium + + * Windows package: upgrade to VS 2019 and Qt 5.15.1. PR #683 + * Package builds: migrate to Ninja. PR #683 + * Define _USE_MATH_DEFINES and clean M_PI redefinitions. PR #682 + * NFM Demod: Refactored audio scaling. PR #682 + fix + * NFM Demod: Fix CTCSS check logic: PR #682 + * NFM: review frequency deviation + * KiwiSDR: fixed issue in local network. Fixes #435 + + -- Edouard Griffiths, F4EXB Fri, 06 Nov 2020 05:21:24 +0100 + sdrangel (4.21.1-1) unstable; urgency=medium * ADS-B demod: optimization of sync word correlation. Implements #675 diff --git a/CMakeLists.txt b/CMakeLists.txt index 46b31ef84..2a42928f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) # configure version set(sdrangel_VERSION_MAJOR "4") set(sdrangel_VERSION_MINOR "21") -set(sdrangel_VERSION_PATCH "1") +set(sdrangel_VERSION_PATCH "2") set(sdrangel_VERSION_SUFFIX "") # SDRAngel cmake options diff --git a/debian/changelog b/debian/changelog index c7eda0ca0..3f3c03b01 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,15 @@ +sdrangel (4.21.2-1) unstable; urgency=medium + + * Windows package: upgrade to VS 2019 and Qt 5.15.1. PR #683 + * Package builds: migrate to Ninja. PR #683 + * Define _USE_MATH_DEFINES and clean M_PI redefinitions. PR #682 + * NFM Demod: Refactored audio scaling. PR #682 + fix + * NFM Demod: Fix CTCSS check logic: PR #682 + * NFM: review frequency deviation + * KiwiSDR: fixed issue in local network. Fixes #435 + + -- Edouard Griffiths, F4EXB Fri, 06 Nov 2020 05:21:24 +0100 + sdrangel (4.21.1-1) unstable; urgency=medium * ADS-B demod: optimization of sync word correlation. Implements #675 diff --git a/plugins/channelrx/demodnfm/nfmplugin.cpp b/plugins/channelrx/demodnfm/nfmplugin.cpp index d0827fb11..c130c1b0a 100644 --- a/plugins/channelrx/demodnfm/nfmplugin.cpp +++ b/plugins/channelrx/demodnfm/nfmplugin.cpp @@ -12,7 +12,7 @@ const PluginDescriptor NFMPlugin::m_pluginDescriptor = { NFMDemod::m_channelId, QString("NFM Demodulator"), - QString("4.21.1"), + QString("4.21.2"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/channeltx/modnfm/nfmmodplugin.cpp b/plugins/channeltx/modnfm/nfmmodplugin.cpp index 2a5065c4b..96e9f824f 100644 --- a/plugins/channeltx/modnfm/nfmmodplugin.cpp +++ b/plugins/channeltx/modnfm/nfmmodplugin.cpp @@ -28,7 +28,7 @@ const PluginDescriptor NFMModPlugin::m_pluginDescriptor = { NFMMod::m_channelId, QString("NFM Modulator"), - QString("4.21.1"), + QString("4.21.2"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesource/kiwisdr/kiwisdrplugin.cpp b/plugins/samplesource/kiwisdr/kiwisdrplugin.cpp index 6da771d85..fb93b2b78 100644 --- a/plugins/samplesource/kiwisdr/kiwisdrplugin.cpp +++ b/plugins/samplesource/kiwisdr/kiwisdrplugin.cpp @@ -32,7 +32,7 @@ const PluginDescriptor KiwiSDRPlugin::m_pluginDescriptor = { QString("KiwiSDR"), QString("KiwiSDR input"), - QString("4.19.0"), + QString("4.21.2"), QString("(c) Vort (c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true,