mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-17 13:51:47 -05:00
commit
f174569a67
@ -79,9 +79,9 @@ for:
|
|||||||
qttools5-dev qttools5-dev-tools qtmultimedia5-dev libqt5multimedia5-plugins libqt5websockets5-dev \
|
qttools5-dev qttools5-dev-tools qtmultimedia5-dev libqt5multimedia5-plugins libqt5websockets5-dev \
|
||||||
libqt5quick5 \
|
libqt5quick5 \
|
||||||
qml-module-qtlocation qml-module-qtpositioning qml-module-qtquick-window2 qml-module-qtquick-dialogs \
|
qml-module-qtlocation qml-module-qtpositioning qml-module-qtquick-window2 qml-module-qtquick-dialogs \
|
||||||
qml-module-qtquick-controls qml-module-qtquick-layouts \
|
qml-module-qtquick-controls qml-module-qtquick-controls2 qml-module-qtquick-layouts \
|
||||||
libqt5serialport5-dev qtdeclarative5-dev qtpositioning5-dev qtlocation5-dev \
|
libqt5serialport5-dev qtdeclarative5-dev qtpositioning5-dev qtlocation5-dev \
|
||||||
libqt5charts5-dev libqt5texttospeech5-dev \
|
libqt5charts5-dev libqt5texttospeech5-dev libfaad-dev zlib1g-dev \
|
||||||
libusb-1.0-0-dev libboost-all-dev libasound2-dev libopencv-dev libopencv-imgcodecs-dev \
|
libusb-1.0-0-dev libboost-all-dev libasound2-dev libopencv-dev libopencv-imgcodecs-dev \
|
||||||
libxml2-dev bison flex ffmpeg libpostproc-dev libavcodec-dev libavformat-dev \
|
libxml2-dev bison flex ffmpeg libpostproc-dev libavcodec-dev libavformat-dev \
|
||||||
libopus-dev libcodec2-dev libairspy-dev libhackrf-dev \
|
libopus-dev libcodec2-dev libairspy-dev libhackrf-dev \
|
||||||
|
@ -230,6 +230,11 @@ elseif (WIN32)
|
|||||||
set(UHD_LIBRARIES "${EXTERNAL_LIBRARY_FOLDER}/uhd/lib/uhd.lib" CACHE INTERNAL "")
|
set(UHD_LIBRARIES "${EXTERNAL_LIBRARY_FOLDER}/uhd/lib/uhd.lib" CACHE INTERNAL "")
|
||||||
set(UHD_DLL_DIR "${EXTERNAL_LIBRARY_FOLDER}/uhd/bin" CACHE INTERNAL "")
|
set(UHD_DLL_DIR "${EXTERNAL_LIBRARY_FOLDER}/uhd/bin" CACHE INTERNAL "")
|
||||||
|
|
||||||
|
set(DAB_FOUND ON CACHE INTERNAL "")
|
||||||
|
set(DAB_INCLUDE_DIR "${EXTERNAL_LIBRARY_FOLDER}/dab" CACHE INTERNAL "")
|
||||||
|
set(DAB_LIBRARIES "${EXTERNAL_LIBRARY_FOLDER}/dab/dab_lib.lib" CACHE INTERNAL "")
|
||||||
|
set(DAB_DLL_DIR "${EXTERNAL_LIBRARY_FOLDER}/dab" CACHE INTERNAL "")
|
||||||
|
|
||||||
set(OPENSSL_FOUND ON CACHE INTERNAL "")
|
set(OPENSSL_FOUND ON CACHE INTERNAL "")
|
||||||
set(OPENSSL_DLL_DIR "${EXTERNAL_LIBRARY_FOLDER}/openssl" CACHE INTERNAL "")
|
set(OPENSSL_DLL_DIR "${EXTERNAL_LIBRARY_FOLDER}/openssl" CACHE INTERNAL "")
|
||||||
|
|
||||||
@ -255,6 +260,14 @@ elseif (WIN32)
|
|||||||
set(SDRPLAY_LIBRARIES "${EXTERNAL_LIBRARY_FOLDER}/sdrplay/x64/sdrplay_api.lib" CACHE INTERNAL "")
|
set(SDRPLAY_LIBRARIES "${EXTERNAL_LIBRARY_FOLDER}/sdrplay/x64/sdrplay_api.lib" CACHE INTERNAL "")
|
||||||
set(SDRPLAY_DLL_DIR "${EXTERNAL_LIBRARY_FOLDER}/sdrplay/x64/" CACHE INTERNAL "")
|
set(SDRPLAY_DLL_DIR "${EXTERNAL_LIBRARY_FOLDER}/sdrplay/x64/" CACHE INTERNAL "")
|
||||||
|
|
||||||
|
set(FAAD_FOUND ON CACHE INTERNAL "")
|
||||||
|
set(FAAD_INCLUDE_DIR "${EXTERNAL_LIBRARY_FOLDER}/faad2/include" CACHE INTERNAL "")
|
||||||
|
set(FAAD_LIBRARY "${EXTERNAL_LIBRARY_FOLDER}/faad2/lib/libfaad.lib" CACHE INTERNAL "")
|
||||||
|
|
||||||
|
set(ZLIB_FOUND ON CACHE INTERNAL "")
|
||||||
|
set(ZLIB_INCLUDE_DIRS "${EXTERNAL_LIBRARY_FOLDER}/zlib/include" CACHE INTERNAL "")
|
||||||
|
set(ZLIB_LIBRARIES "${EXTERNAL_LIBRARY_FOLDER}/zlib/lib/zlibstaticd.lib" CACHE INTERNAL "")
|
||||||
|
|
||||||
# used on fixup_bundle phase
|
# used on fixup_bundle phase
|
||||||
set(WINDOWS_FIXUP_BUNDLE_LIB_DIRS
|
set(WINDOWS_FIXUP_BUNDLE_LIB_DIRS
|
||||||
"${EXTERNAL_LIBRARY_FOLDER}/fftw-3"
|
"${EXTERNAL_LIBRARY_FOLDER}/fftw-3"
|
||||||
@ -330,6 +343,8 @@ find_package(FFTW3F REQUIRED)
|
|||||||
find_package(LibUSB REQUIRED) # used by so many packages
|
find_package(LibUSB REQUIRED) # used by so many packages
|
||||||
find_package(OpenCV OPTIONAL_COMPONENTS core highgui imgproc imgcodecs videoio) # channeltx/modatv
|
find_package(OpenCV OPTIONAL_COMPONENTS core highgui imgproc imgcodecs videoio) # channeltx/modatv
|
||||||
find_package(LibSigMF) # SigMF recording files support
|
find_package(LibSigMF) # SigMF recording files support
|
||||||
|
find_package(ZLIB) # For DAB
|
||||||
|
find_package(FAAD) # For DAB
|
||||||
|
|
||||||
if (LIBSIGMF_FOUND AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
if (LIBSIGMF_FOUND AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
add_definitions(-DHAS_LIBSIGMF)
|
add_definitions(-DHAS_LIBSIGMF)
|
||||||
|
31
cmake/Modules/FindFAAD.cmake
Normal file
31
cmake/Modules/FindFAAD.cmake
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
IF(NOT FAAD_FOUND)
|
||||||
|
INCLUDE(FindPkgConfig)
|
||||||
|
PKG_CHECK_MODULES(PC_FAAD faad2)
|
||||||
|
|
||||||
|
FIND_PATH(
|
||||||
|
FAAD_INCLUDE_DIR
|
||||||
|
NAMES faad.h
|
||||||
|
HINTS ${FAAD_DIR}/include
|
||||||
|
${PC_FAAD_INCLUDE_DIRS}
|
||||||
|
PATHS /usr/local/include
|
||||||
|
/usr/include
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(
|
||||||
|
FAAD_LIBRARY
|
||||||
|
NAMES faad
|
||||||
|
HINTS ${FAAD_DIR}/lib
|
||||||
|
${PC_FAAD_LIBRARY_DIRS}
|
||||||
|
PATHS /usr/local/lib
|
||||||
|
/usr/lib
|
||||||
|
/usr/lib64
|
||||||
|
)
|
||||||
|
|
||||||
|
message(STATUS "FAAD LIBRARY " ${FAAD_LIBRARY})
|
||||||
|
message(STATUS "FAAD INCLUDE DIRS " ${FAAD_INCLUDE_DIR})
|
||||||
|
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(FAAD DEFAULT_MSG FAAD_LIBRARY FAAD_INCLUDE_DIR)
|
||||||
|
MARK_AS_ADVANCED(FAAD_LIBRARY FAAD_INCLUDE_DIR)
|
||||||
|
|
||||||
|
ENDIF(NOT FAAD_FOUND)
|
13
debian/control
vendored
13
debian/control
vendored
@ -20,6 +20,7 @@ Build-Depends: debhelper (>= 9),
|
|||||||
qml-module-qtquick-window2,
|
qml-module-qtquick-window2,
|
||||||
qml-module-qtquick-dialogs,
|
qml-module-qtquick-dialogs,
|
||||||
qml-module-qtquick-controls,
|
qml-module-qtquick-controls,
|
||||||
|
qml-module-qtquick-controls2,
|
||||||
qml-module-qtquick-layouts,
|
qml-module-qtquick-layouts,
|
||||||
libqt5serialport5-dev,
|
libqt5serialport5-dev,
|
||||||
libqt5charts5-dev,
|
libqt5charts5-dev,
|
||||||
@ -36,12 +37,14 @@ Build-Depends: debhelper (>= 9),
|
|||||||
bison,
|
bison,
|
||||||
flex,
|
flex,
|
||||||
ffmpeg,
|
ffmpeg,
|
||||||
|
libfaad-dev,
|
||||||
libavcodec-dev,
|
libavcodec-dev,
|
||||||
libavformat-dev,
|
libavformat-dev,
|
||||||
libopus-dev,
|
libopus-dev,
|
||||||
libairspy-dev,
|
libairspy-dev,
|
||||||
libhackrf-dev,
|
libhackrf-dev,
|
||||||
libuhd-dev
|
libuhd-dev,
|
||||||
|
zlib1g-dev
|
||||||
# TODO:
|
# TODO:
|
||||||
# - more dependencies based on version; newer has more devices
|
# - more dependencies based on version; newer has more devices
|
||||||
# - manage dependencies not present upstream
|
# - manage dependencies not present upstream
|
||||||
@ -51,16 +54,16 @@ Architecture: any
|
|||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libasound2, libgl1-mesa-glx, libqt5multimedia5-plugins, pulseaudio, ffmpeg
|
Depends: ${shlibs:Depends}, ${misc:Depends}, libasound2, libgl1-mesa-glx, libqt5multimedia5-plugins, pulseaudio, ffmpeg
|
||||||
Description: SDR/Analyzer/Generator front-end for various hardware
|
Description: SDR/Analyzer/Generator front-end for various hardware
|
||||||
SDR/Analyzer/Generator front-end for Airspy, BladeRF, HackRF,
|
SDR/Analyzer/Generator front-end for Airspy, BladeRF, HackRF,
|
||||||
RTL-SDR, FunCube, LimeSDR, PlutoSDR, USRP.
|
RTL-SDR, FunCube, LimeSDR, PlutoSDR, RSP, USRP.
|
||||||
Also File source and sink for I/Q samples, network I/Q sources with
|
Also File source and sink for I/Q samples, network I/Q sources with
|
||||||
remote instance.
|
remote instance.
|
||||||
Based on Qt5 framework and OpenGL for the spectrum and scope rendering.
|
Based on Qt5 framework and OpenGL for the spectrum and scope rendering.
|
||||||
Builds on Linux, Windows and Mac O/S
|
Builds on Linux, Windows and Mac O/S
|
||||||
Reception modes supported:
|
Reception modes supported:
|
||||||
Analog: AM, ATV, NFM, WFM, SSB, broadcast FM
|
Analog: AM, ATV, NFM, WFM, SSB, broadcast FM, APT
|
||||||
Digital: D-Star, Yaesu SF, DMR, dPMR, LoRa, ADS-B, Packet (AX.25/APRS)
|
Digital: D-Star, Yaesu SF, DMR, dPMR, FreeDV, DAB, DVB-S, LoRa, ADS-B, Packet (AX.25/APRS)
|
||||||
Analyzer: Generic channel
|
Analyzer: Generic channel
|
||||||
Transmission modes supported:
|
Transmission modes supported:
|
||||||
Analog: AM, ATV, NFM, SSB, WFM
|
Analog: AM, ATV, NFM, SSB, WFM
|
||||||
Digital: Packet (AX.25), 802.15.4
|
Digital: DVB-S, Packet (AX.25), 802.15.4
|
||||||
Homepage: https://github.com/f4exb/sdrangel
|
Homepage: https://github.com/f4exb/sdrangel
|
||||||
|
BIN
doc/img/DABDemod_plugin.png
Normal file
BIN
doc/img/DABDemod_plugin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
45
external/CMakeLists.txt
vendored
45
external/CMakeLists.txt
vendored
@ -443,6 +443,51 @@ if (WIN32)
|
|||||||
install(FILES "${source_dir}/pthreadVC2${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}")
|
install(FILES "${source_dir}/pthreadVC2${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}")
|
||||||
endif (WIN32)
|
endif (WIN32)
|
||||||
|
|
||||||
|
# For DAB demodulator
|
||||||
|
if (ZLIB_FOUND AND FAAD_FOUND)
|
||||||
|
if (WIN32)
|
||||||
|
set(DAB_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/dab_lib.lib" CACHE INTERNAL "")
|
||||||
|
elseif (LINUX)
|
||||||
|
set(DAB_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib/libdab_lib${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "")
|
||||||
|
endif()
|
||||||
|
if (WIN32)
|
||||||
|
set(PTHREADS_OPT_FOR_DAB "-DPTHREADS=${PTHREADS4W_LIBRARIES}" CACHE INTERNAL "")
|
||||||
|
else()
|
||||||
|
set(PTHREADS_OPT_FOR_DAB "" CACHE INTERNAL "")
|
||||||
|
endif()
|
||||||
|
ExternalProject_Add(dab
|
||||||
|
GIT_REPOSITORY https://github.com/srcejon/dab-cmdline.git
|
||||||
|
GIT_TAG msvc
|
||||||
|
PREFIX "${EXTERNAL_BUILD_LIBRARIES}/dab"
|
||||||
|
SOURCE_SUBDIR "library"
|
||||||
|
CMAKE_ARGS ${COMMON_CMAKE_ARGS}
|
||||||
|
-DFFTW3F_INCLUDE_DIRS=${FFTW3F_INCLUDE_DIRS}
|
||||||
|
-DFFTW3F_LIBRARIES=${FFTW3F_LIBRARIES}
|
||||||
|
-DFAAD_INCLUDE_DIR=${FAAD_INCLUDE_DIR}
|
||||||
|
-DFAAD_LIBRARY=${FAAD_LIBRARY}
|
||||||
|
-DZLIB_INCLUDE_DIR=${ZLIB_INCLUDE_DIRS}
|
||||||
|
-DZLIB_LIBRARY=${ZLIB_LIBRARIES}
|
||||||
|
${PTHREADS_OPT_FOR_DAB}
|
||||||
|
BUILD_BYPRODUCTS "${DAB_LIBRARIES}"
|
||||||
|
INSTALL_COMMAND ""
|
||||||
|
TEST_COMMAND ""
|
||||||
|
)
|
||||||
|
ExternalProject_Get_Property(dab source_dir binary_dir)
|
||||||
|
set(DAB_FOUND ON CACHE INTERNAL "")
|
||||||
|
set(DAB_EXTERNAL ON CACHE INTERNAL "")
|
||||||
|
set(DAB_INCLUDE_DIR "${EXTERNAL_BUILD_LIBRARIES}/dab/src/dab" CACHE INTERNAL "")
|
||||||
|
if (WIN32)
|
||||||
|
install(FILES "${SDRANGEL_BINARY_BIN_DIR}/dab_lib${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}")
|
||||||
|
elseif (APPLE)
|
||||||
|
set(DAB_LIBRARIES "${binary_dir}/libapt${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "")
|
||||||
|
install(DIRECTORY "${binary_dir}/" DESTINATION "${INSTALL_LIB_DIR}"
|
||||||
|
FILES_MATCHING PATTERN "libdab_lib*${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||||
|
set(MACOS_EXTERNAL_LIBS_FIXUP "${MACOS_EXTERNAL_LIBS_FIXUP};${binary_dir}/")
|
||||||
|
endif ()
|
||||||
|
else()
|
||||||
|
message(STATUS "Can't build DAB library as missing zlib or faad")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Device interface libraries. Use external libraries build for these. Only Linux for now.
|
# Device interface libraries. Use external libraries build for these. Only Linux for now.
|
||||||
if (LINUX)
|
if (LINUX)
|
||||||
# apt install liblimesuite-dev (only on ubuntu 18.04). Can be picky on version though so let's build it.
|
# apt install liblimesuite-dev (only on ubuntu 18.04). Can be picky on version though so let's build it.
|
||||||
|
@ -18,6 +18,10 @@ add_subdirectory(demodchirpchat)
|
|||||||
add_subdirectory(demodvorsc)
|
add_subdirectory(demodvorsc)
|
||||||
add_subdirectory(demodpacket)
|
add_subdirectory(demodpacket)
|
||||||
|
|
||||||
|
if(DAB_FOUND AND ZLIB_FOUND AND FAAD_FOUND)
|
||||||
|
add_subdirectory(demoddab)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(APT_FOUND)
|
if(APT_FOUND)
|
||||||
add_subdirectory(demodapt)
|
add_subdirectory(demodapt)
|
||||||
endif()
|
endif()
|
||||||
|
64
plugins/channelrx/demoddab/CMakeLists.txt
Normal file
64
plugins/channelrx/demoddab/CMakeLists.txt
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
project(demoddab)
|
||||||
|
|
||||||
|
add_definitions(-DDABLIN_AAC_FAAD2)
|
||||||
|
|
||||||
|
set(demoddab_SOURCES
|
||||||
|
dabdemod.cpp
|
||||||
|
dabdemodsettings.cpp
|
||||||
|
dabdemodbaseband.cpp
|
||||||
|
dabdemodsink.cpp
|
||||||
|
dabdemodplugin.cpp
|
||||||
|
dabdemodwebapiadapter.cpp
|
||||||
|
dabdemoddevice.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(demoddab_HEADERS
|
||||||
|
dabdemod.h
|
||||||
|
dabdemodsettings.h
|
||||||
|
dabdemodbaseband.h
|
||||||
|
dabdemodsink.h
|
||||||
|
dabdemodplugin.h
|
||||||
|
dabdemodwebapiadapter.h
|
||||||
|
dabdemoddevice.h
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||||
|
${DAB_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT SERVER_MODE)
|
||||||
|
set(demoddab_SOURCES
|
||||||
|
${demoddab_SOURCES}
|
||||||
|
dabdemodgui.cpp
|
||||||
|
dabdemodgui.ui
|
||||||
|
)
|
||||||
|
set(demoddab_HEADERS
|
||||||
|
${demoddab_HEADERS}
|
||||||
|
dabdemodgui.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(TARGET_NAME demoddab)
|
||||||
|
set(TARGET_LIB "Qt5::Widgets")
|
||||||
|
set(TARGET_LIB_GUI "sdrgui")
|
||||||
|
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
|
||||||
|
else()
|
||||||
|
set(TARGET_NAME demoddabsrv)
|
||||||
|
set(TARGET_LIB "")
|
||||||
|
set(TARGET_LIB_GUI "")
|
||||||
|
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(${TARGET_NAME} SHARED
|
||||||
|
${demoddab_SOURCES}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${TARGET_NAME}
|
||||||
|
Qt5::Core
|
||||||
|
${TARGET_LIB}
|
||||||
|
sdrbase
|
||||||
|
${TARGET_LIB_GUI}
|
||||||
|
${DAB_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})
|
541
plugins/channelrx/demoddab/dabdemod.cpp
Normal file
541
plugins/channelrx/demoddab/dabdemod.cpp
Normal file
@ -0,0 +1,541 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2015-2018 Edouard Griffiths, F4EXB. //
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "dabdemod.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <complex.h>
|
||||||
|
|
||||||
|
#include "SWGChannelSettings.h"
|
||||||
|
#include "SWGDABDemodSettings.h"
|
||||||
|
#include "SWGChannelReport.h"
|
||||||
|
#include "SWGMapItem.h"
|
||||||
|
|
||||||
|
#include "dsp/dspengine.h"
|
||||||
|
#include "dsp/dspcommands.h"
|
||||||
|
#include "device/deviceapi.h"
|
||||||
|
#include "feature/feature.h"
|
||||||
|
#include "util/db.h"
|
||||||
|
#include "maincore.h"
|
||||||
|
|
||||||
|
MESSAGE_CLASS_DEFINITION(DABDemod::MsgConfigureDABDemod, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABEnsembleName, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABProgramName, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABProgramData, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABSystemData, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABProgramQuality, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABFIBQuality, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABSampleRate, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABData, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABReset, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABResetService, Message)
|
||||||
|
|
||||||
|
const char * const DABDemod::m_channelIdURI = "sdrangel.channel.dabdemod";
|
||||||
|
const char * const DABDemod::m_channelId = "DABDemod";
|
||||||
|
|
||||||
|
DABDemod::DABDemod(DeviceAPI *deviceAPI) :
|
||||||
|
ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
|
||||||
|
m_deviceAPI(deviceAPI),
|
||||||
|
m_basebandSampleRate(0)
|
||||||
|
{
|
||||||
|
setObjectName(m_channelId);
|
||||||
|
|
||||||
|
m_basebandSink = new DABDemodBaseband(this);
|
||||||
|
m_basebandSink->setMessageQueueToChannel(getInputMessageQueue());
|
||||||
|
m_basebandSink->setChannel(this);
|
||||||
|
m_basebandSink->moveToThread(&m_thread);
|
||||||
|
|
||||||
|
applySettings(m_settings, true);
|
||||||
|
|
||||||
|
m_deviceAPI->addChannelSink(this);
|
||||||
|
m_deviceAPI->addChannelSinkAPI(this);
|
||||||
|
|
||||||
|
m_networkManager = new QNetworkAccessManager();
|
||||||
|
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
DABDemod::~DABDemod()
|
||||||
|
{
|
||||||
|
qDebug("DABDemod::~DABDemod");
|
||||||
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
|
delete m_networkManager;
|
||||||
|
m_deviceAPI->removeChannelSinkAPI(this);
|
||||||
|
m_deviceAPI->removeChannelSink(this);
|
||||||
|
|
||||||
|
if (m_basebandSink->isRunning()) {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete m_basebandSink;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DABDemod::getNumberOfDeviceStreams() const
|
||||||
|
{
|
||||||
|
return m_deviceAPI->getNbSourceStreams();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst)
|
||||||
|
{
|
||||||
|
(void) firstOfBurst;
|
||||||
|
m_basebandSink->feed(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemod::start()
|
||||||
|
{
|
||||||
|
qDebug("DABDemod::start");
|
||||||
|
|
||||||
|
m_basebandSink->reset();
|
||||||
|
m_basebandSink->startWork();
|
||||||
|
m_thread.start();
|
||||||
|
|
||||||
|
DSPSignalNotification *dspMsg = new DSPSignalNotification(m_basebandSampleRate, m_centerFrequency);
|
||||||
|
m_basebandSink->getInputMessageQueue()->push(dspMsg);
|
||||||
|
|
||||||
|
DABDemodBaseband::MsgConfigureDABDemodBaseband *msg = DABDemodBaseband::MsgConfigureDABDemodBaseband::create(m_settings, true);
|
||||||
|
m_basebandSink->getInputMessageQueue()->push(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemod::stop()
|
||||||
|
{
|
||||||
|
qDebug("DABDemod::stop");
|
||||||
|
m_basebandSink->stopWork();
|
||||||
|
m_thread.quit();
|
||||||
|
m_thread.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DABDemod::handleMessage(const Message& cmd)
|
||||||
|
{
|
||||||
|
if (MsgConfigureDABDemod::match(cmd))
|
||||||
|
{
|
||||||
|
MsgConfigureDABDemod& cfg = (MsgConfigureDABDemod&) cmd;
|
||||||
|
qDebug() << "DABDemod::handleMessage: MsgConfigureDABDemod";
|
||||||
|
applySettings(cfg.getSettings(), cfg.getForce());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (DSPSignalNotification::match(cmd))
|
||||||
|
{
|
||||||
|
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
|
||||||
|
m_basebandSampleRate = notif.getSampleRate();
|
||||||
|
m_centerFrequency = notif.getCenterFrequency();
|
||||||
|
// Forward to the sink
|
||||||
|
DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy
|
||||||
|
qDebug() << "DABDemod::handleMessage: DSPSignalNotification";
|
||||||
|
m_basebandSink->getInputMessageQueue()->push(rep);
|
||||||
|
// Forward to GUI if any
|
||||||
|
if (m_guiMessageQueue)
|
||||||
|
{
|
||||||
|
rep = new DSPSignalNotification(notif);
|
||||||
|
m_guiMessageQueue->push(rep);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (MsgDABSystemData::match(cmd))
|
||||||
|
{
|
||||||
|
MsgDABSystemData& report = (MsgDABSystemData&)cmd;
|
||||||
|
if (getMessageQueueToGUI())
|
||||||
|
{
|
||||||
|
getMessageQueueToGUI()->push(new MsgDABSystemData(report));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (MsgDABProgramQuality::match(cmd))
|
||||||
|
{
|
||||||
|
MsgDABProgramQuality& report = (MsgDABProgramQuality&)cmd;
|
||||||
|
if (getMessageQueueToGUI())
|
||||||
|
{
|
||||||
|
getMessageQueueToGUI()->push(new MsgDABProgramQuality(report));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (MsgDABFIBQuality::match(cmd))
|
||||||
|
{
|
||||||
|
MsgDABFIBQuality& report = (MsgDABFIBQuality&)cmd;
|
||||||
|
if (getMessageQueueToGUI())
|
||||||
|
{
|
||||||
|
getMessageQueueToGUI()->push(new MsgDABFIBQuality(report));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (MsgDABSampleRate::match(cmd))
|
||||||
|
{
|
||||||
|
MsgDABSampleRate& report = (MsgDABSampleRate&)cmd;
|
||||||
|
if (getMessageQueueToGUI())
|
||||||
|
{
|
||||||
|
getMessageQueueToGUI()->push(new MsgDABSampleRate(report));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (MsgDABEnsembleName::match(cmd))
|
||||||
|
{
|
||||||
|
MsgDABEnsembleName& report = (MsgDABEnsembleName&)cmd;
|
||||||
|
if (getMessageQueueToGUI())
|
||||||
|
{
|
||||||
|
getMessageQueueToGUI()->push(new MsgDABEnsembleName(report));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (MsgDABProgramName::match(cmd))
|
||||||
|
{
|
||||||
|
MsgDABProgramName& report = (MsgDABProgramName&)cmd;
|
||||||
|
if (getMessageQueueToGUI())
|
||||||
|
{
|
||||||
|
getMessageQueueToGUI()->push(new MsgDABProgramName(report));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (MsgDABProgramData::match(cmd))
|
||||||
|
{
|
||||||
|
MsgDABProgramData& report = (MsgDABProgramData&)cmd;
|
||||||
|
if (getMessageQueueToGUI())
|
||||||
|
{
|
||||||
|
getMessageQueueToGUI()->push(new MsgDABProgramData(report));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (MsgDABData::match(cmd))
|
||||||
|
{
|
||||||
|
MsgDABData& report = (MsgDABData&)cmd;
|
||||||
|
if (getMessageQueueToGUI())
|
||||||
|
{
|
||||||
|
getMessageQueueToGUI()->push(new MsgDABData(report));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (MsgDABReset::match(cmd))
|
||||||
|
{
|
||||||
|
MsgDABReset& report = (MsgDABReset&)cmd;
|
||||||
|
m_basebandSink->getInputMessageQueue()->push(new MsgDABReset(report));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (MsgDABResetService::match(cmd))
|
||||||
|
{
|
||||||
|
MsgDABResetService& report = (MsgDABResetService&)cmd;
|
||||||
|
m_basebandSink->getInputMessageQueue()->push(new MsgDABResetService(report));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemod::applySettings(const DABDemodSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
qDebug() << "DABDemod::applySettings:"
|
||||||
|
<< " m_streamIndex: " << settings.m_streamIndex
|
||||||
|
<< " m_useReverseAPI: " << settings.m_useReverseAPI
|
||||||
|
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
|
||||||
|
<< " m_reverseAPIPort: " << settings.m_reverseAPIPort
|
||||||
|
<< " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex
|
||||||
|
<< " m_reverseAPIChannelIndex: " << settings.m_reverseAPIChannelIndex
|
||||||
|
<< " force: " << force;
|
||||||
|
|
||||||
|
QList<QString> reverseAPIKeys;
|
||||||
|
|
||||||
|
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
|
||||||
|
reverseAPIKeys.append("inputFrequencyOffset");
|
||||||
|
}
|
||||||
|
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) {
|
||||||
|
reverseAPIKeys.append("rfBandwidth");
|
||||||
|
}
|
||||||
|
if ((settings.m_program != m_settings.m_program) || force) {
|
||||||
|
reverseAPIKeys.append("program");
|
||||||
|
}
|
||||||
|
if ((settings.m_volume != m_settings.m_volume) || force) {
|
||||||
|
reverseAPIKeys.append("volume");
|
||||||
|
}
|
||||||
|
if ((settings.m_audioMute != m_settings.m_audioMute) || force) {
|
||||||
|
reverseAPIKeys.append("audioMute");
|
||||||
|
}
|
||||||
|
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force) {
|
||||||
|
reverseAPIKeys.append("audioDeviceName");
|
||||||
|
}
|
||||||
|
if (m_settings.m_streamIndex != settings.m_streamIndex)
|
||||||
|
{
|
||||||
|
if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only
|
||||||
|
{
|
||||||
|
m_deviceAPI->removeChannelSinkAPI(this);
|
||||||
|
m_deviceAPI->removeChannelSink(this, m_settings.m_streamIndex);
|
||||||
|
m_deviceAPI->addChannelSink(this, settings.m_streamIndex);
|
||||||
|
m_deviceAPI->addChannelSinkAPI(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
reverseAPIKeys.append("streamIndex");
|
||||||
|
}
|
||||||
|
|
||||||
|
DABDemodBaseband::MsgConfigureDABDemodBaseband *msg = DABDemodBaseband::MsgConfigureDABDemodBaseband::create(settings, force);
|
||||||
|
m_basebandSink->getInputMessageQueue()->push(msg);
|
||||||
|
|
||||||
|
if (settings.m_useReverseAPI)
|
||||||
|
{
|
||||||
|
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
|
||||||
|
(m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) ||
|
||||||
|
(m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) ||
|
||||||
|
(m_settings.m_reverseAPIDeviceIndex != settings.m_reverseAPIDeviceIndex) ||
|
||||||
|
(m_settings.m_reverseAPIChannelIndex != settings.m_reverseAPIChannelIndex);
|
||||||
|
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray DABDemod::serialize() const
|
||||||
|
{
|
||||||
|
return m_settings.serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DABDemod::deserialize(const QByteArray& data)
|
||||||
|
{
|
||||||
|
if (m_settings.deserialize(data))
|
||||||
|
{
|
||||||
|
MsgConfigureDABDemod *msg = MsgConfigureDABDemod::create(m_settings, true);
|
||||||
|
m_inputMessageQueue.push(msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_settings.resetToDefaults();
|
||||||
|
MsgConfigureDABDemod *msg = MsgConfigureDABDemod::create(m_settings, true);
|
||||||
|
m_inputMessageQueue.push(msg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int DABDemod::webapiSettingsGet(
|
||||||
|
SWGSDRangel::SWGChannelSettings& response,
|
||||||
|
QString& errorMessage)
|
||||||
|
{
|
||||||
|
(void) errorMessage;
|
||||||
|
response.setDabDemodSettings(new SWGSDRangel::SWGDABDemodSettings());
|
||||||
|
response.getDabDemodSettings()->init();
|
||||||
|
webapiFormatChannelSettings(response, m_settings);
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DABDemod::webapiSettingsPutPatch(
|
||||||
|
bool force,
|
||||||
|
const QStringList& channelSettingsKeys,
|
||||||
|
SWGSDRangel::SWGChannelSettings& response,
|
||||||
|
QString& errorMessage)
|
||||||
|
{
|
||||||
|
(void) errorMessage;
|
||||||
|
DABDemodSettings settings = m_settings;
|
||||||
|
webapiUpdateChannelSettings(settings, channelSettingsKeys, response);
|
||||||
|
|
||||||
|
MsgConfigureDABDemod *msg = MsgConfigureDABDemod::create(settings, force);
|
||||||
|
m_inputMessageQueue.push(msg);
|
||||||
|
|
||||||
|
qDebug("DABDemod::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
|
||||||
|
if (m_guiMessageQueue) // forward to GUI if any
|
||||||
|
{
|
||||||
|
MsgConfigureDABDemod *msgToGUI = MsgConfigureDABDemod::create(settings, force);
|
||||||
|
m_guiMessageQueue->push(msgToGUI);
|
||||||
|
}
|
||||||
|
|
||||||
|
webapiFormatChannelSettings(response, settings);
|
||||||
|
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemod::webapiUpdateChannelSettings(
|
||||||
|
DABDemodSettings& settings,
|
||||||
|
const QStringList& channelSettingsKeys,
|
||||||
|
SWGSDRangel::SWGChannelSettings& response)
|
||||||
|
{
|
||||||
|
if (channelSettingsKeys.contains("inputFrequencyOffset")) {
|
||||||
|
settings.m_inputFrequencyOffset = response.getDabDemodSettings()->getInputFrequencyOffset();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rfBandwidth")) {
|
||||||
|
settings.m_rfBandwidth = response.getDabDemodSettings()->getRfBandwidth();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("program")) {
|
||||||
|
settings.m_program = *response.getDabDemodSettings()->getProgram();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("m_volume")) {
|
||||||
|
settings.m_volume = response.getDabDemodSettings()->getVolume();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioMute")) {
|
||||||
|
settings.m_audioMute = response.getDabDemodSettings()->getAudioMute();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioDeviceName")) {
|
||||||
|
settings.m_audioDeviceName = *response.getDabDemodSettings()->getAudioDeviceName();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rgbColor")) {
|
||||||
|
settings.m_rgbColor = response.getDabDemodSettings()->getRgbColor();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("title")) {
|
||||||
|
settings.m_title = *response.getDabDemodSettings()->getTitle();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("streamIndex")) {
|
||||||
|
settings.m_streamIndex = response.getDabDemodSettings()->getStreamIndex();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("useReverseAPI")) {
|
||||||
|
settings.m_useReverseAPI = response.getDabDemodSettings()->getUseReverseApi() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIAddress")) {
|
||||||
|
settings.m_reverseAPIAddress = *response.getDabDemodSettings()->getReverseApiAddress();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIPort")) {
|
||||||
|
settings.m_reverseAPIPort = response.getDabDemodSettings()->getReverseApiPort();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
|
||||||
|
settings.m_reverseAPIDeviceIndex = response.getDabDemodSettings()->getReverseApiDeviceIndex();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
|
||||||
|
settings.m_reverseAPIChannelIndex = response.getDabDemodSettings()->getReverseApiChannelIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const DABDemodSettings& settings)
|
||||||
|
{
|
||||||
|
response.getDabDemodSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||||
|
response.getDabDemodSettings()->setRfBandwidth(settings.m_rfBandwidth);
|
||||||
|
response.getDabDemodSettings()->setProgram(new QString(settings.m_program));
|
||||||
|
response.getDabDemodSettings()->setVolume(settings.m_volume);
|
||||||
|
response.getDabDemodSettings()->setAudioMute(settings.m_audioMute);
|
||||||
|
response.getDabDemodSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
||||||
|
|
||||||
|
response.getDabDemodSettings()->setRgbColor(settings.m_rgbColor);
|
||||||
|
if (response.getDabDemodSettings()->getTitle()) {
|
||||||
|
*response.getDabDemodSettings()->getTitle() = settings.m_title;
|
||||||
|
} else {
|
||||||
|
response.getDabDemodSettings()->setTitle(new QString(settings.m_title));
|
||||||
|
}
|
||||||
|
|
||||||
|
response.getDabDemodSettings()->setStreamIndex(settings.m_streamIndex);
|
||||||
|
response.getDabDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
|
||||||
|
|
||||||
|
if (response.getDabDemodSettings()->getReverseApiAddress()) {
|
||||||
|
*response.getDabDemodSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
|
||||||
|
} else {
|
||||||
|
response.getDabDemodSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
response.getDabDemodSettings()->setReverseApiPort(settings.m_reverseAPIPort);
|
||||||
|
response.getDabDemodSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
|
||||||
|
response.getDabDemodSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const DABDemodSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
|
||||||
|
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
|
||||||
|
|
||||||
|
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
|
||||||
|
.arg(settings.m_reverseAPIAddress)
|
||||||
|
.arg(settings.m_reverseAPIPort)
|
||||||
|
.arg(settings.m_reverseAPIDeviceIndex)
|
||||||
|
.arg(settings.m_reverseAPIChannelIndex);
|
||||||
|
m_networkRequest.setUrl(QUrl(channelSettingsURL));
|
||||||
|
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
|
||||||
|
QBuffer *buffer = new QBuffer();
|
||||||
|
buffer->open((QBuffer::ReadWrite));
|
||||||
|
buffer->write(swgChannelSettings->asJson().toUtf8());
|
||||||
|
buffer->seek(0);
|
||||||
|
|
||||||
|
// Always use PATCH to avoid passing reverse API settings
|
||||||
|
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||||
|
buffer->setParent(reply);
|
||||||
|
|
||||||
|
delete swgChannelSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemod::webapiFormatChannelSettings(
|
||||||
|
QList<QString>& channelSettingsKeys,
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
|
||||||
|
const DABDemodSettings& settings,
|
||||||
|
bool force
|
||||||
|
)
|
||||||
|
{
|
||||||
|
swgChannelSettings->setDirection(0); // Single sink (Rx)
|
||||||
|
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
|
||||||
|
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
|
||||||
|
swgChannelSettings->setChannelType(new QString("DABDemod"));
|
||||||
|
swgChannelSettings->setDabDemodSettings(new SWGSDRangel::SWGDABDemodSettings());
|
||||||
|
SWGSDRangel::SWGDABDemodSettings *swgDABDemodSettings = swgChannelSettings->getDabDemodSettings();
|
||||||
|
|
||||||
|
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||||
|
|
||||||
|
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
|
||||||
|
swgDABDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rfBandwidth") || force) {
|
||||||
|
swgDABDemodSettings->setRfBandwidth(settings.m_rfBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("program") || force) {
|
||||||
|
swgDABDemodSettings->setProgram(new QString(settings.m_program));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("volume") || force) {
|
||||||
|
swgDABDemodSettings->setVolume(settings.m_volume);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioMute") || force) {
|
||||||
|
swgDABDemodSettings->setAudioMute(settings.m_audioMute);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioDeviceName") || force) {
|
||||||
|
swgDABDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||||
|
swgDABDemodSettings->setRgbColor(settings.m_rgbColor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("title") || force) {
|
||||||
|
swgDABDemodSettings->setTitle(new QString(settings.m_title));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("streamIndex") || force) {
|
||||||
|
swgDABDemodSettings->setStreamIndex(settings.m_streamIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemod::networkManagerFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
QNetworkReply::NetworkError replyError = reply->error();
|
||||||
|
|
||||||
|
if (replyError)
|
||||||
|
{
|
||||||
|
qWarning() << "DABDemod::networkManagerFinished:"
|
||||||
|
<< " error(" << (int) replyError
|
||||||
|
<< "): " << replyError
|
||||||
|
<< ": " << reply->errorString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QString answer = reply->readAll();
|
||||||
|
answer.chop(1); // remove last \n
|
||||||
|
qDebug("DABDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
reply->deleteLater();
|
||||||
|
}
|
375
plugins/channelrx/demoddab/dabdemod.h
Normal file
375
plugins/channelrx/demoddab/dabdemod.h
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2015-2018 Edouard Griffiths, F4EXB. //
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef INCLUDE_DABDEMOD_H
|
||||||
|
#define INCLUDE_DABDEMOD_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
#include "dsp/basebandsamplesink.h"
|
||||||
|
#include "channel/channelapi.h"
|
||||||
|
#include "util/message.h"
|
||||||
|
|
||||||
|
#include "dabdemodbaseband.h"
|
||||||
|
#include "dabdemodsettings.h"
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QNetworkReply;
|
||||||
|
class QThread;
|
||||||
|
class DeviceAPI;
|
||||||
|
|
||||||
|
class DABDemod : public BasebandSampleSink, public ChannelAPI {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
class MsgConfigureDABDemod : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
const DABDemodSettings& getSettings() const { return m_settings; }
|
||||||
|
bool getForce() const { return m_force; }
|
||||||
|
|
||||||
|
static MsgConfigureDABDemod* create(const DABDemodSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
return new MsgConfigureDABDemod(settings, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
DABDemodSettings m_settings;
|
||||||
|
bool m_force;
|
||||||
|
|
||||||
|
MsgConfigureDABDemod(const DABDemodSettings& settings, bool force) :
|
||||||
|
Message(),
|
||||||
|
m_settings(settings),
|
||||||
|
m_force(force)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgDABEnsembleName : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
const QString getName() const { return m_name; }
|
||||||
|
int getId() const { return m_id; }
|
||||||
|
|
||||||
|
static MsgDABEnsembleName* create(const QString& name, int id)
|
||||||
|
{
|
||||||
|
return new MsgDABEnsembleName(name, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_name;
|
||||||
|
int m_id;
|
||||||
|
|
||||||
|
MsgDABEnsembleName(const QString& name, int id) :
|
||||||
|
Message(),
|
||||||
|
m_name(name),
|
||||||
|
m_id(id)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgDABProgramName : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
const QString getName() const { return m_name; }
|
||||||
|
int getId() const { return m_id; }
|
||||||
|
|
||||||
|
static MsgDABProgramName* create(const QString& name, int id)
|
||||||
|
{
|
||||||
|
return new MsgDABProgramName(name, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_name;
|
||||||
|
int m_id;
|
||||||
|
|
||||||
|
MsgDABProgramName(const QString& name, int id) :
|
||||||
|
Message(),
|
||||||
|
m_name(name),
|
||||||
|
m_id(id)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgDABProgramData: public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
int getBitrate() const { return m_bitrate; }
|
||||||
|
const QString getAudio() const { return m_audio; }
|
||||||
|
const QString getLanguage() const { return m_language; }
|
||||||
|
const QString getProgramType() const { return m_programType; }
|
||||||
|
|
||||||
|
|
||||||
|
static MsgDABProgramData* create(int bitrate, const QString& audio, const QString& language, const QString& programType)
|
||||||
|
{
|
||||||
|
return new MsgDABProgramData(bitrate, audio, language, programType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_bitrate;
|
||||||
|
QString m_audio;
|
||||||
|
QString m_language;
|
||||||
|
QString m_programType;
|
||||||
|
|
||||||
|
MsgDABProgramData(int bitrate, const QString& audio, const QString& language, const QString& programType) :
|
||||||
|
Message(),
|
||||||
|
m_bitrate(bitrate),
|
||||||
|
m_audio(audio),
|
||||||
|
m_language(language),
|
||||||
|
m_programType(programType)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgDABSystemData : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool getSync() const { return m_sync; }
|
||||||
|
int16_t getSNR() const { return m_snr; }
|
||||||
|
int32_t getFrequencyOffset() const { return m_frequencyOffset; }
|
||||||
|
|
||||||
|
static MsgDABSystemData* create(bool sync, int16_t snr, int32_t frequencyOffset)
|
||||||
|
{
|
||||||
|
return new MsgDABSystemData(sync, snr, frequencyOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_sync;
|
||||||
|
int16_t m_snr;
|
||||||
|
int32_t m_frequencyOffset;
|
||||||
|
|
||||||
|
MsgDABSystemData(bool sync, int16_t snr, int32_t frequencyOffset) :
|
||||||
|
Message(),
|
||||||
|
m_sync(sync),
|
||||||
|
m_snr(snr),
|
||||||
|
m_frequencyOffset(frequencyOffset)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgDABProgramQuality : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
int getFrames() const { return m_frames; }
|
||||||
|
int getRS() const { return m_rs; }
|
||||||
|
int getAAC() const { return m_aac; }
|
||||||
|
|
||||||
|
static MsgDABProgramQuality* create(int frames, int rs, int aac)
|
||||||
|
{
|
||||||
|
return new MsgDABProgramQuality(frames, rs, aac);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_frames;
|
||||||
|
int m_rs;
|
||||||
|
int m_aac;
|
||||||
|
|
||||||
|
MsgDABProgramQuality(int frames, int rs, int aac) :
|
||||||
|
Message(),
|
||||||
|
m_frames(frames),
|
||||||
|
m_rs(rs),
|
||||||
|
m_aac(aac)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgDABFIBQuality : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
int getPercent() const { return m_percent; }
|
||||||
|
|
||||||
|
static MsgDABFIBQuality* create(int percent)
|
||||||
|
{
|
||||||
|
return new MsgDABFIBQuality(percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_percent;
|
||||||
|
|
||||||
|
MsgDABFIBQuality(int percent) :
|
||||||
|
Message(),
|
||||||
|
m_percent(percent)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgDABSampleRate : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
int getSampleRate() const { return m_sampleRate; }
|
||||||
|
|
||||||
|
static MsgDABSampleRate* create(int sampleRate)
|
||||||
|
{
|
||||||
|
return new MsgDABSampleRate(sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_sampleRate;
|
||||||
|
|
||||||
|
MsgDABSampleRate(int sampleRate) :
|
||||||
|
Message(),
|
||||||
|
m_sampleRate(sampleRate)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgDABData : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
const QString getData() const { return m_data; }
|
||||||
|
|
||||||
|
static MsgDABData* create(const QString& data)
|
||||||
|
{
|
||||||
|
return new MsgDABData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_data;
|
||||||
|
|
||||||
|
MsgDABData(const QString& data) :
|
||||||
|
Message(),
|
||||||
|
m_data(data)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgDABReset : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static MsgDABReset* create()
|
||||||
|
{
|
||||||
|
return new MsgDABReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
MsgDABReset() :
|
||||||
|
Message()
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgDABResetService : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static MsgDABResetService* create()
|
||||||
|
{
|
||||||
|
return new MsgDABResetService();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
MsgDABResetService() :
|
||||||
|
Message()
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DABDemod(DeviceAPI *deviceAPI);
|
||||||
|
virtual ~DABDemod();
|
||||||
|
virtual void destroy() { delete this; }
|
||||||
|
|
||||||
|
using BasebandSampleSink::feed;
|
||||||
|
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
|
||||||
|
virtual void start();
|
||||||
|
virtual void stop();
|
||||||
|
virtual bool handleMessage(const Message& cmd);
|
||||||
|
|
||||||
|
virtual void getIdentifier(QString& id) { id = objectName(); }
|
||||||
|
virtual const QString& getURI() const { return getName(); }
|
||||||
|
virtual void getTitle(QString& title) { title = m_settings.m_title; }
|
||||||
|
virtual qint64 getCenterFrequency() const { return 0; }
|
||||||
|
|
||||||
|
virtual QByteArray serialize() const;
|
||||||
|
virtual bool deserialize(const QByteArray& data);
|
||||||
|
|
||||||
|
virtual int getNbSinkStreams() const { return 1; }
|
||||||
|
virtual int getNbSourceStreams() const { return 0; }
|
||||||
|
|
||||||
|
virtual qint64 getStreamCenterFrequency(int streamIndex, bool sinkElseSource) const
|
||||||
|
{
|
||||||
|
(void) streamIndex;
|
||||||
|
(void) sinkElseSource;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int webapiSettingsGet(
|
||||||
|
SWGSDRangel::SWGChannelSettings& response,
|
||||||
|
QString& errorMessage);
|
||||||
|
|
||||||
|
virtual int webapiSettingsPutPatch(
|
||||||
|
bool force,
|
||||||
|
const QStringList& channelSettingsKeys,
|
||||||
|
SWGSDRangel::SWGChannelSettings& response,
|
||||||
|
QString& errorMessage);
|
||||||
|
|
||||||
|
static void webapiFormatChannelSettings(
|
||||||
|
SWGSDRangel::SWGChannelSettings& response,
|
||||||
|
const DABDemodSettings& settings);
|
||||||
|
|
||||||
|
static void webapiUpdateChannelSettings(
|
||||||
|
DABDemodSettings& settings,
|
||||||
|
const QStringList& channelSettingsKeys,
|
||||||
|
SWGSDRangel::SWGChannelSettings& response);
|
||||||
|
|
||||||
|
double getMagSq() const { return m_basebandSink->getMagSq(); }
|
||||||
|
|
||||||
|
void getMagSqLevels(double& avg, double& peak, int& nbSamples) {
|
||||||
|
m_basebandSink->getMagSqLevels(avg, peak, nbSamples);
|
||||||
|
}
|
||||||
|
/* void setMessageQueueToGUI(MessageQueue* queue) override {
|
||||||
|
ChannelAPI::setMessageQueueToGUI(queue);
|
||||||
|
m_basebandSink->setMessageQueueToGUI(queue);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
uint32_t getNumberOfDeviceStreams() const;
|
||||||
|
|
||||||
|
static const char * const m_channelIdURI;
|
||||||
|
static const char * const m_channelId;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeviceAPI *m_deviceAPI;
|
||||||
|
QThread m_thread;
|
||||||
|
DABDemodBaseband* m_basebandSink;
|
||||||
|
DABDemodSettings m_settings;
|
||||||
|
int m_basebandSampleRate; //!< stored from device message used when starting baseband sink
|
||||||
|
qint64 m_centerFrequency;
|
||||||
|
|
||||||
|
QNetworkAccessManager *m_networkManager;
|
||||||
|
QNetworkRequest m_networkRequest;
|
||||||
|
|
||||||
|
void applySettings(const DABDemodSettings& settings, bool force = false);
|
||||||
|
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const DABDemodSettings& settings, bool force);
|
||||||
|
void webapiFormatChannelSettings(
|
||||||
|
QList<QString>& channelSettingsKeys,
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
|
||||||
|
const DABDemodSettings& settings,
|
||||||
|
bool force
|
||||||
|
);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void networkManagerFinished(QNetworkReply *reply);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_DABDEMOD_H
|
203
plugins/channelrx/demoddab/dabdemodbaseband.cpp
Normal file
203
plugins/channelrx/demoddab/dabdemodbaseband.cpp
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "dsp/dspengine.h"
|
||||||
|
#include "dsp/dspcommands.h"
|
||||||
|
#include "dsp/downchannelizer.h"
|
||||||
|
|
||||||
|
#include "dabdemodbaseband.h"
|
||||||
|
#include "dabdemod.h"
|
||||||
|
|
||||||
|
MESSAGE_CLASS_DEFINITION(DABDemodBaseband::MsgConfigureDABDemodBaseband, Message)
|
||||||
|
|
||||||
|
DABDemodBaseband::DABDemodBaseband(DABDemod *packetDemod) :
|
||||||
|
m_sink(packetDemod),
|
||||||
|
m_running(false),
|
||||||
|
m_mutex(QMutex::Recursive)
|
||||||
|
{
|
||||||
|
qDebug("DABDemodBaseband::DABDemodBaseband");
|
||||||
|
|
||||||
|
m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(1000000));
|
||||||
|
m_channelizer = new DownChannelizer(&m_sink);
|
||||||
|
|
||||||
|
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(m_sink.getAudioFifo(), getInputMessageQueue());
|
||||||
|
m_sink.applyAudioSampleRate(DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate());
|
||||||
|
}
|
||||||
|
|
||||||
|
DABDemodBaseband::~DABDemodBaseband()
|
||||||
|
{
|
||||||
|
m_inputMessageQueue.clear();
|
||||||
|
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(m_sink.getAudioFifo());
|
||||||
|
delete m_channelizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodBaseband::reset()
|
||||||
|
{
|
||||||
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
m_inputMessageQueue.clear();
|
||||||
|
m_sampleFifo.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodBaseband::startWork()
|
||||||
|
{
|
||||||
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
QObject::connect(
|
||||||
|
&m_sampleFifo,
|
||||||
|
&SampleSinkFifo::dataReady,
|
||||||
|
this,
|
||||||
|
&DABDemodBaseband::handleData,
|
||||||
|
Qt::QueuedConnection
|
||||||
|
);
|
||||||
|
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
||||||
|
m_running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodBaseband::stopWork()
|
||||||
|
{
|
||||||
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
||||||
|
QObject::disconnect(
|
||||||
|
&m_sampleFifo,
|
||||||
|
&SampleSinkFifo::dataReady,
|
||||||
|
this,
|
||||||
|
&DABDemodBaseband::handleData
|
||||||
|
);
|
||||||
|
m_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodBaseband::setChannel(ChannelAPI *channel)
|
||||||
|
{
|
||||||
|
m_sink.setChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
|
||||||
|
{
|
||||||
|
m_sampleFifo.write(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodBaseband::handleData()
|
||||||
|
{
|
||||||
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
|
||||||
|
while ((m_sampleFifo.fill() > 0) && (m_inputMessageQueue.size() == 0))
|
||||||
|
{
|
||||||
|
SampleVector::iterator part1begin;
|
||||||
|
SampleVector::iterator part1end;
|
||||||
|
SampleVector::iterator part2begin;
|
||||||
|
SampleVector::iterator part2end;
|
||||||
|
|
||||||
|
std::size_t count = m_sampleFifo.readBegin(m_sampleFifo.fill(), &part1begin, &part1end, &part2begin, &part2end);
|
||||||
|
|
||||||
|
// first part of FIFO data
|
||||||
|
if (part1begin != part1end) {
|
||||||
|
m_channelizer->feed(part1begin, part1end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// second part of FIFO data (used when block wraps around)
|
||||||
|
if(part2begin != part2end) {
|
||||||
|
m_channelizer->feed(part2begin, part2end);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sampleFifo.readCommit((unsigned int) count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodBaseband::handleInputMessages()
|
||||||
|
{
|
||||||
|
Message* message;
|
||||||
|
|
||||||
|
while ((message = m_inputMessageQueue.pop()) != nullptr)
|
||||||
|
{
|
||||||
|
if (handleMessage(*message)) {
|
||||||
|
delete message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DABDemodBaseband::handleMessage(const Message& cmd)
|
||||||
|
{
|
||||||
|
if (MsgConfigureDABDemodBaseband::match(cmd))
|
||||||
|
{
|
||||||
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
MsgConfigureDABDemodBaseband& cfg = (MsgConfigureDABDemodBaseband&) cmd;
|
||||||
|
qDebug() << "DABDemodBaseband::handleMessage: MsgConfigureDABDemodBaseband";
|
||||||
|
|
||||||
|
applySettings(cfg.getSettings(), cfg.getForce());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (DSPSignalNotification::match(cmd))
|
||||||
|
{
|
||||||
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
|
||||||
|
qDebug() << "DABDemodBaseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate();
|
||||||
|
setBasebandSampleRate(notif.getSampleRate());
|
||||||
|
m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(notif.getSampleRate()));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (DABDemod::MsgDABReset::match(cmd))
|
||||||
|
{
|
||||||
|
m_sink.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (DABDemod::MsgDABResetService::match(cmd))
|
||||||
|
{
|
||||||
|
m_sink.resetService();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodBaseband::applySettings(const DABDemodSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force)
|
||||||
|
{
|
||||||
|
m_channelizer->setChannelization(DABDEMOD_CHANNEL_SAMPLE_RATE, settings.m_inputFrequencyOffset);
|
||||||
|
m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
|
||||||
|
{
|
||||||
|
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
||||||
|
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName);
|
||||||
|
audioDeviceManager->removeAudioSink(m_sink.getAudioFifo());
|
||||||
|
audioDeviceManager->addAudioSink(m_sink.getAudioFifo(), getInputMessageQueue(), audioDeviceIndex);
|
||||||
|
int audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex);
|
||||||
|
|
||||||
|
if (m_sink.getAudioSampleRate() != audioSampleRate)
|
||||||
|
{
|
||||||
|
m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
|
||||||
|
m_sink.applyAudioSampleRate(audioSampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_sink.applySettings(settings, force);
|
||||||
|
|
||||||
|
m_settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodBaseband::setBasebandSampleRate(int sampleRate)
|
||||||
|
{
|
||||||
|
m_channelizer->setBasebandSampleRate(sampleRate);
|
||||||
|
m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
|
||||||
|
}
|
95
plugins/channelrx/demoddab/dabdemodbaseband.h
Normal file
95
plugins/channelrx/demoddab/dabdemodbaseband.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef INCLUDE_DABDEMODBASEBAND_H
|
||||||
|
#define INCLUDE_DABDEMODBASEBAND_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QMutex>
|
||||||
|
|
||||||
|
#include "dsp/samplesinkfifo.h"
|
||||||
|
#include "util/message.h"
|
||||||
|
#include "util/messagequeue.h"
|
||||||
|
|
||||||
|
#include "dabdemodsink.h"
|
||||||
|
|
||||||
|
class DownChannelizer;
|
||||||
|
class ChannelAPI;
|
||||||
|
class DABDemod;
|
||||||
|
|
||||||
|
class DABDemodBaseband : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
class MsgConfigureDABDemodBaseband : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
const DABDemodSettings& getSettings() const { return m_settings; }
|
||||||
|
bool getForce() const { return m_force; }
|
||||||
|
|
||||||
|
static MsgConfigureDABDemodBaseband* create(const DABDemodSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
return new MsgConfigureDABDemodBaseband(settings, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
DABDemodSettings m_settings;
|
||||||
|
bool m_force;
|
||||||
|
|
||||||
|
MsgConfigureDABDemodBaseband(const DABDemodSettings& settings, bool force) :
|
||||||
|
Message(),
|
||||||
|
m_settings(settings),
|
||||||
|
m_force(force)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
DABDemodBaseband(DABDemod *packetDemod);
|
||||||
|
~DABDemodBaseband();
|
||||||
|
void reset();
|
||||||
|
void startWork();
|
||||||
|
void stopWork();
|
||||||
|
void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
|
||||||
|
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
|
||||||
|
void getMagSqLevels(double& avg, double& peak, int& nbSamples) {
|
||||||
|
m_sink.getMagSqLevels(avg, peak, nbSamples);
|
||||||
|
}
|
||||||
|
void setMessageQueueToChannel(MessageQueue *messageQueue) { m_sink.setMessageQueueToChannel(messageQueue); }
|
||||||
|
void setBasebandSampleRate(int sampleRate);
|
||||||
|
void setChannel(ChannelAPI *channel);
|
||||||
|
double getMagSq() const { return m_sink.getMagSq(); }
|
||||||
|
bool isRunning() const { return m_running; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SampleSinkFifo m_sampleFifo;
|
||||||
|
DownChannelizer *m_channelizer;
|
||||||
|
DABDemodSink m_sink;
|
||||||
|
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
|
||||||
|
DABDemodSettings m_settings;
|
||||||
|
bool m_running;
|
||||||
|
QMutex m_mutex;
|
||||||
|
|
||||||
|
bool handleMessage(const Message& cmd);
|
||||||
|
void applySettings(const DABDemodSettings& settings, bool force = false);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleInputMessages();
|
||||||
|
void handleData(); //!< Handle data when samples have to be processed
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_DABDEMODBASEBAND_H
|
120
plugins/channelrx/demoddab/dabdemoddevice.cpp
Normal file
120
plugins/channelrx/demoddab/dabdemoddevice.cpp
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2010, 2011, 2012 Jan van Katwijk (J.vanKatwijk@gmail.com)
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "dabdemoddevice.h"
|
||||||
|
|
||||||
|
// Implementation of default device, as not included in library
|
||||||
|
|
||||||
|
deviceHandler::deviceHandler(void)
|
||||||
|
{
|
||||||
|
lastFrequency = 100000;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceHandler::~deviceHandler(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool deviceHandler::restartReader(int32_t)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deviceHandler::stopReader(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void deviceHandler::run(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t deviceHandler::getSamples(std::complex<float> *v, int32_t amount)
|
||||||
|
{
|
||||||
|
(void)v;
|
||||||
|
(void)amount;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t deviceHandler::Samples(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t deviceHandler::defaultFrequency(void)
|
||||||
|
{
|
||||||
|
return 220000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deviceHandler::resetBuffer(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void deviceHandler::setGain(int32_t x)
|
||||||
|
{
|
||||||
|
(void)x;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool deviceHandler::has_autogain(void)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deviceHandler::set_autogain(bool b)
|
||||||
|
{
|
||||||
|
(void)b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deviceHandler::set_ifgainReduction(int x)
|
||||||
|
{
|
||||||
|
(void)x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deviceHandler::set_lnaState(int x)
|
||||||
|
{
|
||||||
|
(void)x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Device with source data from SDRangel
|
||||||
|
// Other methods not needed for DAB library
|
||||||
|
|
||||||
|
DABDemodDevice::DABDemodDevice() :
|
||||||
|
m_iqBuffer (4 * 1024 * 1024)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodDevice::putSample(std::complex<float> s)
|
||||||
|
{
|
||||||
|
std::complex<float> localBuf[1];
|
||||||
|
localBuf[0] = s;
|
||||||
|
if (m_iqBuffer.GetRingBufferWriteAvailable() > 0)
|
||||||
|
m_iqBuffer.putDataIntoBuffer(localBuf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t DABDemodDevice::getSamples(std::complex<float> *buf, int32_t size)
|
||||||
|
{
|
||||||
|
return m_iqBuffer.getDataFromBuffer(buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t DABDemodDevice::Samples(void)
|
||||||
|
{
|
||||||
|
return m_iqBuffer.GetRingBufferReadAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodDevice::resetBuffer(void)
|
||||||
|
{
|
||||||
|
m_iqBuffer.FlushRingBuffer();
|
||||||
|
}
|
38
plugins/channelrx/demoddab/dabdemoddevice.h
Normal file
38
plugins/channelrx/demoddab/dabdemoddevice.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef INCLUDE_DABDEMODDEVICE_H
|
||||||
|
#define INCLUDE_DABDEMODDEVICE_H
|
||||||
|
|
||||||
|
#include <dab-api.h>
|
||||||
|
|
||||||
|
class DABDemodDevice : public deviceHandler {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DABDemodDevice();
|
||||||
|
void putSample(std::complex<float> s);
|
||||||
|
int32_t getSamples(std::complex<float> *buf, int32_t size) override;
|
||||||
|
int32_t Samples(void) override;
|
||||||
|
void resetBuffer(void) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RingBuffer<std::complex<float>> m_iqBuffer;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_DABDEMODDEVICE_H
|
651
plugins/channelrx/demoddab/dabdemodgui.cpp
Normal file
651
plugins/channelrx/demoddab/dabdemodgui.cpp
Normal file
@ -0,0 +1,651 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QRegExp>
|
||||||
|
|
||||||
|
#include "dabdemodgui.h"
|
||||||
|
|
||||||
|
#include "device/deviceuiset.h"
|
||||||
|
#include "dsp/dspengine.h"
|
||||||
|
#include "dsp/dspcommands.h"
|
||||||
|
#include "ui_dabdemodgui.h"
|
||||||
|
#include "plugin/pluginapi.h"
|
||||||
|
#include "util/simpleserializer.h"
|
||||||
|
#include "util/db.h"
|
||||||
|
#include "gui/audioselectdialog.h"
|
||||||
|
#include "gui/basicchannelsettingsdialog.h"
|
||||||
|
#include "gui/devicestreamselectiondialog.h"
|
||||||
|
#include "dsp/dspengine.h"
|
||||||
|
#include "gui/crightclickenabler.h"
|
||||||
|
#include "channel/channelwebapiutils.h"
|
||||||
|
#include "maincore.h"
|
||||||
|
|
||||||
|
#include "dabdemod.h"
|
||||||
|
#include "dabdemodsink.h"
|
||||||
|
|
||||||
|
// Table column indexes
|
||||||
|
#define PROGRAMS_COL_NAME 0
|
||||||
|
#define PROGRAMS_COL_ID 1
|
||||||
|
#define PROGRAMS_COL_FREQUENCY 2
|
||||||
|
|
||||||
|
void DABDemodGUI::resizeTable()
|
||||||
|
{
|
||||||
|
// Fill table with a row of dummy data that will size the columns nicely
|
||||||
|
// Trailing spaces are for sort arrow
|
||||||
|
int row = ui->programs->rowCount();
|
||||||
|
ui->programs->setRowCount(row + 1);
|
||||||
|
ui->programs->setItem(row, PROGRAMS_COL_NAME, new QTableWidgetItem("Some Random Radio Station"));
|
||||||
|
ui->programs->setItem(row, PROGRAMS_COL_ID, new QTableWidgetItem("123456"));
|
||||||
|
ui->programs->setItem(row, PROGRAMS_COL_FREQUENCY, new QTableWidgetItem("200.000"));
|
||||||
|
ui->programs->resizeColumnsToContents();
|
||||||
|
ui->programs->removeRow(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Columns in table reordered
|
||||||
|
void DABDemodGUI::programs_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex)
|
||||||
|
{
|
||||||
|
(void) oldVisualIndex;
|
||||||
|
|
||||||
|
m_settings.m_columnIndexes[logicalIndex] = newVisualIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Column in table resized (when hidden size is 0)
|
||||||
|
void DABDemodGUI::programs_sectionResized(int logicalIndex, int oldSize, int newSize)
|
||||||
|
{
|
||||||
|
(void) oldSize;
|
||||||
|
|
||||||
|
m_settings.m_columnSizes[logicalIndex] = newSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right click in table header - show column select menu
|
||||||
|
void DABDemodGUI::columnSelectMenu(QPoint pos)
|
||||||
|
{
|
||||||
|
menu->popup(ui->programs->horizontalHeader()->viewport()->mapToGlobal(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide/show column when menu selected
|
||||||
|
void DABDemodGUI::columnSelectMenuChecked(bool checked)
|
||||||
|
{
|
||||||
|
(void) checked;
|
||||||
|
|
||||||
|
QAction* action = qobject_cast<QAction*>(sender());
|
||||||
|
if (action != nullptr)
|
||||||
|
{
|
||||||
|
int idx = action->data().toInt(nullptr);
|
||||||
|
ui->programs->setColumnHidden(idx, !action->isChecked());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create column select menu item
|
||||||
|
QAction *DABDemodGUI::createCheckableItem(QString &text, int idx, bool checked)
|
||||||
|
{
|
||||||
|
QAction *action = new QAction(text, this);
|
||||||
|
action->setCheckable(true);
|
||||||
|
action->setChecked(checked);
|
||||||
|
action->setData(QVariant(idx));
|
||||||
|
connect(action, SIGNAL(triggered()), this, SLOT(columnSelectMenuChecked()));
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
DABDemodGUI* DABDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel)
|
||||||
|
{
|
||||||
|
DABDemodGUI* gui = new DABDemodGUI(pluginAPI, deviceUISet, rxChannel);
|
||||||
|
return gui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::destroy()
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::resetToDefaults()
|
||||||
|
{
|
||||||
|
m_settings.resetToDefaults();
|
||||||
|
displaySettings();
|
||||||
|
applySettings(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray DABDemodGUI::serialize() const
|
||||||
|
{
|
||||||
|
return m_settings.serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DABDemodGUI::deserialize(const QByteArray& data)
|
||||||
|
{
|
||||||
|
if(m_settings.deserialize(data)) {
|
||||||
|
displaySettings();
|
||||||
|
applySettings(true);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
resetToDefaults();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add row to table
|
||||||
|
void DABDemodGUI::addProgramName(const DABDemod::MsgDABProgramName& program)
|
||||||
|
{
|
||||||
|
ui->programs->setSortingEnabled(false);
|
||||||
|
int row = ui->programs->rowCount();
|
||||||
|
ui->programs->setRowCount(row + 1);
|
||||||
|
|
||||||
|
QTableWidgetItem *nameItem = new QTableWidgetItem();
|
||||||
|
QTableWidgetItem *idItem = new QTableWidgetItem();
|
||||||
|
QTableWidgetItem *frequencyItem = new QTableWidgetItem();
|
||||||
|
ui->programs->setItem(row, PROGRAMS_COL_NAME, nameItem);
|
||||||
|
ui->programs->setItem(row, PROGRAMS_COL_ID, idItem);
|
||||||
|
ui->programs->setItem(row, PROGRAMS_COL_FREQUENCY, frequencyItem);
|
||||||
|
nameItem->setText(program.getName());
|
||||||
|
idItem->setText(QString::number(program.getId()));
|
||||||
|
double frequencyInHz;
|
||||||
|
if (ChannelWebAPIUtils::getCenterFrequency(m_dabDemod->getDeviceSetIndex(), frequencyInHz))
|
||||||
|
{
|
||||||
|
double frequencyInMHz = (frequencyInHz+m_settings.m_inputFrequencyOffset)/1e6;
|
||||||
|
frequencyItem->setText(QString::number(frequencyInMHz, 'f', 3));
|
||||||
|
frequencyItem->setData(Qt::UserRole, frequencyInHz+m_settings.m_inputFrequencyOffset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
frequencyItem->setData(Qt::UserRole, 0.0);
|
||||||
|
ui->programs->setSortingEnabled(true);
|
||||||
|
filterRow(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tune to the selected program
|
||||||
|
void DABDemodGUI::on_programs_cellDoubleClicked(int row, int column)
|
||||||
|
{
|
||||||
|
(void) column;
|
||||||
|
|
||||||
|
m_settings.m_program = ui->programs->item(row, PROGRAMS_COL_NAME)->text();
|
||||||
|
|
||||||
|
double frequencyInHz = ui->programs->item(row, PROGRAMS_COL_FREQUENCY)->data(Qt::UserRole).toDouble();
|
||||||
|
ChannelWebAPIUtils::setCenterFrequency(m_dabDemod->getDeviceSetIndex(), frequencyInHz-m_settings.m_inputFrequencyOffset);
|
||||||
|
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DABDemodGUI::handleMessage(const Message& message)
|
||||||
|
{
|
||||||
|
if (DABDemod::MsgConfigureDABDemod::match(message))
|
||||||
|
{
|
||||||
|
qDebug("DABDemodGUI::handleMessage: DABDemod::MsgConfigureDABDemod");
|
||||||
|
const DABDemod::MsgConfigureDABDemod& cfg = (DABDemod::MsgConfigureDABDemod&) message;
|
||||||
|
m_settings = cfg.getSettings();
|
||||||
|
blockApplySettings(true);
|
||||||
|
displaySettings();
|
||||||
|
blockApplySettings(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (DSPSignalNotification::match(message))
|
||||||
|
{
|
||||||
|
DSPSignalNotification& notif = (DSPSignalNotification&) message;
|
||||||
|
m_basebandSampleRate = notif.getSampleRate();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (DABDemod::MsgDABEnsembleName::match(message))
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABEnsembleName& report = (DABDemod::MsgDABEnsembleName&) message;
|
||||||
|
ui->ensemble->setText(report.getName());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (DABDemod::MsgDABProgramName::match(message))
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABProgramName& report = (DABDemod::MsgDABProgramName&) message;
|
||||||
|
addProgramName(report);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (DABDemod::MsgDABProgramData::match(message))
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABProgramData& report = (DABDemod::MsgDABProgramData&) message;
|
||||||
|
ui->program->setText(m_settings.m_program);
|
||||||
|
ui->bitrate->setText(QString("%1kbps").arg(report.getBitrate()));
|
||||||
|
ui->audio->setText(report.getAudio());
|
||||||
|
ui->language->setText(report.getLanguage());
|
||||||
|
ui->programType->setText(report.getProgramType());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (DABDemod::MsgDABSystemData::match(message))
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABSystemData& report = (DABDemod::MsgDABSystemData&) message;
|
||||||
|
if (report.getSync())
|
||||||
|
ui->sync->setText("Yes");
|
||||||
|
else
|
||||||
|
ui->sync->setText("No");
|
||||||
|
ui->snr->setText(QString("%1").arg(report.getSNR()));
|
||||||
|
ui->freqOffset->setText(QString("%1").arg(report.getFrequencyOffset()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (DABDemod::MsgDABProgramQuality::match(message))
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABProgramQuality& report = (DABDemod::MsgDABProgramQuality&) message;
|
||||||
|
ui->frames->setText(QString("%1%").arg(report.getFrames()));
|
||||||
|
ui->rs->setText(QString("%1%").arg(report.getRS()));
|
||||||
|
ui->aac->setText(QString("%1%").arg(report.getAAC()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (DABDemod::MsgDABFIBQuality::match(message))
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABFIBQuality& report = (DABDemod::MsgDABFIBQuality&) message;
|
||||||
|
ui->fib->setText(QString("%1%").arg(report.getPercent()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (DABDemod::MsgDABSampleRate::match(message))
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABSampleRate& report = (DABDemod::MsgDABSampleRate&) message;
|
||||||
|
qDebug() << "Ssample rate: " << report.getSampleRate();
|
||||||
|
ui->sampleRate->setText(QString("%1k").arg(report.getSampleRate()/1000.0, 0, 'f', 0));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (DABDemod::MsgDABData::match(message))
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABData& report = (DABDemod::MsgDABData&) message;
|
||||||
|
ui->data->setText(report.getData());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::handleInputMessages()
|
||||||
|
{
|
||||||
|
Message* message;
|
||||||
|
|
||||||
|
while ((message = getInputMessageQueue()->pop()) != 0)
|
||||||
|
{
|
||||||
|
if (handleMessage(*message))
|
||||||
|
{
|
||||||
|
delete message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::channelMarkerChangedByCursor()
|
||||||
|
{
|
||||||
|
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
|
||||||
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::channelMarkerHighlightedByCursor()
|
||||||
|
{
|
||||||
|
setHighlighted(m_channelMarker.getHighlighted());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::on_deltaFrequency_changed(qint64 value)
|
||||||
|
{
|
||||||
|
m_channelMarker.setCenterFrequency(value);
|
||||||
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::on_audioMute_toggled(bool checked)
|
||||||
|
{
|
||||||
|
m_settings.m_audioMute = checked;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::on_volume_valueChanged(int value)
|
||||||
|
{
|
||||||
|
ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
|
||||||
|
m_settings.m_volume = value / 10.0;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::on_rfBW_valueChanged(int value)
|
||||||
|
{
|
||||||
|
float bw = value * 100.0f;
|
||||||
|
ui->rfBWText->setText(QString("%1k").arg(value / 10.0, 0, 'f', 1));
|
||||||
|
m_channelMarker.setBandwidth(bw);
|
||||||
|
m_settings.m_rfBandwidth = bw;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::on_filter_editingFinished()
|
||||||
|
{
|
||||||
|
m_settings.m_filter = ui->filter->text();
|
||||||
|
filter();
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::on_clearTable_clicked()
|
||||||
|
{
|
||||||
|
ui->programs->setRowCount(0);
|
||||||
|
// Reset the DAB library, so it re-outputs program names
|
||||||
|
DABDemod::MsgDABReset* message = DABDemod::MsgDABReset::create();
|
||||||
|
m_dabDemod->getInputMessageQueue()->push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::filterRow(int row)
|
||||||
|
{
|
||||||
|
bool hidden = false;
|
||||||
|
if (m_settings.m_filter != "")
|
||||||
|
{
|
||||||
|
QRegExp re(m_settings.m_filter);
|
||||||
|
QTableWidgetItem *fromItem = ui->programs->item(row, PROGRAMS_COL_NAME);
|
||||||
|
if (re.indexIn(fromItem->text()) == -1)
|
||||||
|
hidden = true;
|
||||||
|
}
|
||||||
|
ui->programs->setRowHidden(row, hidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::filter()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ui->programs->rowCount(); i++)
|
||||||
|
{
|
||||||
|
filterRow(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
||||||
|
{
|
||||||
|
(void) widget;
|
||||||
|
(void) rollDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::onMenuDialogCalled(const QPoint &p)
|
||||||
|
{
|
||||||
|
if (m_contextMenuType == ContextMenuChannelSettings)
|
||||||
|
{
|
||||||
|
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
|
||||||
|
dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
|
||||||
|
dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
|
||||||
|
dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
|
||||||
|
dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex);
|
||||||
|
dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex);
|
||||||
|
dialog.move(p);
|
||||||
|
dialog.exec();
|
||||||
|
|
||||||
|
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
||||||
|
m_settings.m_title = m_channelMarker.getTitle();
|
||||||
|
m_settings.m_useReverseAPI = dialog.useReverseAPI();
|
||||||
|
m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
|
||||||
|
m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
|
||||||
|
m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex();
|
||||||
|
m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex();
|
||||||
|
|
||||||
|
setWindowTitle(m_settings.m_title);
|
||||||
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
|
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine))
|
||||||
|
{
|
||||||
|
DeviceStreamSelectionDialog dialog(this);
|
||||||
|
dialog.setNumberOfStreams(m_dabDemod->getNumberOfDeviceStreams());
|
||||||
|
dialog.setStreamIndex(m_settings.m_streamIndex);
|
||||||
|
dialog.move(p);
|
||||||
|
dialog.exec();
|
||||||
|
|
||||||
|
m_settings.m_streamIndex = dialog.getSelectedStreamIndex();
|
||||||
|
m_channelMarker.clearStreamIndexes();
|
||||||
|
m_channelMarker.addStreamIndex(m_settings.m_streamIndex);
|
||||||
|
displayStreamIndex();
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
resetContextMenuType();
|
||||||
|
}
|
||||||
|
|
||||||
|
DABDemodGUI::DABDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent) :
|
||||||
|
ChannelGUI(parent),
|
||||||
|
ui(new Ui::DABDemodGUI),
|
||||||
|
m_pluginAPI(pluginAPI),
|
||||||
|
m_deviceUISet(deviceUISet),
|
||||||
|
m_channelMarker(this),
|
||||||
|
m_doApplySettings(true),
|
||||||
|
m_tickCount(0),
|
||||||
|
m_channelFreq(0.0)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
|
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
|
||||||
|
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
|
||||||
|
|
||||||
|
m_dabDemod = reinterpret_cast<DABDemod*>(rxChannel);
|
||||||
|
m_dabDemod->setMessageQueueToGUI(getInputMessageQueue());
|
||||||
|
|
||||||
|
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
||||||
|
connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect()));
|
||||||
|
|
||||||
|
connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
|
||||||
|
|
||||||
|
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
||||||
|
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||||
|
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
|
||||||
|
ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue);
|
||||||
|
|
||||||
|
m_channelMarker.blockSignals(true);
|
||||||
|
m_channelMarker.setColor(Qt::yellow);
|
||||||
|
m_channelMarker.setBandwidth(m_settings.m_rfBandwidth);
|
||||||
|
m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
|
||||||
|
m_channelMarker.setTitle("Packet Demodulator");
|
||||||
|
m_channelMarker.blockSignals(false);
|
||||||
|
m_channelMarker.setVisible(true); // activate signal on the last setting only
|
||||||
|
|
||||||
|
setTitleColor(m_channelMarker.getColor());
|
||||||
|
m_settings.setChannelMarker(&m_channelMarker);
|
||||||
|
|
||||||
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
||||||
|
m_deviceUISet->addRollupWidget(this);
|
||||||
|
|
||||||
|
connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor()));
|
||||||
|
connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
|
||||||
|
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
||||||
|
|
||||||
|
// Resize the table using dummy data
|
||||||
|
resizeTable();
|
||||||
|
// Allow user to reorder columns
|
||||||
|
ui->programs->horizontalHeader()->setSectionsMovable(true);
|
||||||
|
// Allow user to sort table by clicking on headers
|
||||||
|
ui->programs->setSortingEnabled(true);
|
||||||
|
// Add context menu to allow hiding/showing of columns
|
||||||
|
menu = new QMenu(ui->programs);
|
||||||
|
for (int i = 0; i < ui->programs->horizontalHeader()->count(); i++)
|
||||||
|
{
|
||||||
|
QString text = ui->programs->horizontalHeaderItem(i)->text();
|
||||||
|
menu->addAction(createCheckableItem(text, i, true));
|
||||||
|
}
|
||||||
|
ui->programs->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
connect(ui->programs->horizontalHeader(), SIGNAL(customContextMenuRequested(QPoint)), SLOT(columnSelectMenu(QPoint)));
|
||||||
|
// Get signals when columns change
|
||||||
|
connect(ui->programs->horizontalHeader(), SIGNAL(sectionMoved(int, int, int)), SLOT(programs_sectionMoved(int, int, int)));
|
||||||
|
connect(ui->programs->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), SLOT(programs_sectionResized(int, int, int)));
|
||||||
|
|
||||||
|
displaySettings();
|
||||||
|
applySettings(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
DABDemodGUI::~DABDemodGUI()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::blockApplySettings(bool block)
|
||||||
|
{
|
||||||
|
m_doApplySettings = !block;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::applySettings(bool force)
|
||||||
|
{
|
||||||
|
if (m_doApplySettings)
|
||||||
|
{
|
||||||
|
DABDemod::MsgConfigureDABDemod* message = DABDemod::MsgConfigureDABDemod::create( m_settings, force);
|
||||||
|
m_dabDemod->getInputMessageQueue()->push(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::displaySettings()
|
||||||
|
{
|
||||||
|
m_channelMarker.blockSignals(true);
|
||||||
|
m_channelMarker.setBandwidth(m_settings.m_rfBandwidth);
|
||||||
|
m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
|
||||||
|
m_channelMarker.setTitle(m_settings.m_title);
|
||||||
|
m_channelMarker.blockSignals(false);
|
||||||
|
m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only
|
||||||
|
|
||||||
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
|
setWindowTitle(m_channelMarker.getTitle());
|
||||||
|
|
||||||
|
blockApplySettings(true);
|
||||||
|
|
||||||
|
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
|
||||||
|
ui->audioMute->setChecked(m_settings.m_audioMute);
|
||||||
|
|
||||||
|
ui->volume->setValue(m_settings.m_volume * 10.0);
|
||||||
|
ui->volumeText->setText(QString("%1").arg(m_settings.m_volume, 0, 'f', 1));
|
||||||
|
|
||||||
|
ui->rfBWText->setText(QString("%1k").arg(m_settings.m_rfBandwidth / 1000.0, 0, 'f', 1));
|
||||||
|
ui->rfBW->setValue(m_settings.m_rfBandwidth / 100.0);
|
||||||
|
|
||||||
|
displayStreamIndex();
|
||||||
|
|
||||||
|
ui->filter->setText(m_settings.m_filter);
|
||||||
|
|
||||||
|
// Order and size columns
|
||||||
|
QHeaderView *header = ui->programs->horizontalHeader();
|
||||||
|
for (int i = 0; i < DABDEMOD_COLUMNS; i++)
|
||||||
|
{
|
||||||
|
bool hidden = m_settings.m_columnSizes[i] == 0;
|
||||||
|
header->setSectionHidden(i, hidden);
|
||||||
|
menu->actions().at(i)->setChecked(!hidden);
|
||||||
|
if (m_settings.m_columnSizes[i] > 0)
|
||||||
|
ui->programs->setColumnWidth(i, m_settings.m_columnSizes[i]);
|
||||||
|
header->moveSection(header->visualIndex(i), m_settings.m_columnIndexes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
filter();
|
||||||
|
|
||||||
|
blockApplySettings(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::displayStreamIndex()
|
||||||
|
{
|
||||||
|
if (m_deviceUISet->m_deviceMIMOEngine) {
|
||||||
|
setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex));
|
||||||
|
} else {
|
||||||
|
setStreamIndicator("S"); // single channel indicator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::leaveEvent(QEvent*)
|
||||||
|
{
|
||||||
|
m_channelMarker.setHighlighted(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::enterEvent(QEvent*)
|
||||||
|
{
|
||||||
|
m_channelMarker.setHighlighted(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::resetService()
|
||||||
|
{
|
||||||
|
// Reset DAB audio service, to avoid unpleasent noise when changing frequency
|
||||||
|
DABDemod::MsgDABResetService* message = DABDemod::MsgDABResetService::create();
|
||||||
|
m_dabDemod->getInputMessageQueue()->push(message);
|
||||||
|
// Clear current program
|
||||||
|
ui->program->setText("-");
|
||||||
|
ui->ensemble->setText("-");
|
||||||
|
ui->programType->setText("-");
|
||||||
|
ui->language->setText("-");
|
||||||
|
ui->audio->setText("-");
|
||||||
|
ui->bitrate->setText("-");
|
||||||
|
ui->sampleRate->setText("-");
|
||||||
|
ui->data->setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::on_channel_currentIndexChanged(int index)
|
||||||
|
{
|
||||||
|
(void) index;
|
||||||
|
|
||||||
|
QString text = ui->channel->currentText();
|
||||||
|
if (!text.isEmpty())
|
||||||
|
{
|
||||||
|
resetService();
|
||||||
|
// Tune to requested channel
|
||||||
|
QString freq = text.split(" ")[2];
|
||||||
|
m_channelFreq = freq.toDouble() * 1e6;
|
||||||
|
ChannelWebAPIUtils::setCenterFrequency(m_dabDemod->getDeviceSetIndex(), m_channelFreq - m_settings.m_inputFrequencyOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::audioSelect()
|
||||||
|
{
|
||||||
|
AudioSelectDialog audioSelect(DSPEngine::instance()->getAudioDeviceManager(), m_settings.m_audioDeviceName);
|
||||||
|
audioSelect.exec();
|
||||||
|
|
||||||
|
if (audioSelect.m_selected)
|
||||||
|
{
|
||||||
|
m_settings.m_audioDeviceName = audioSelect.m_audioDeviceName;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodGUI::tick()
|
||||||
|
{
|
||||||
|
double magsqAvg, magsqPeak;
|
||||||
|
int nbMagsqSamples;
|
||||||
|
m_dabDemod->getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples);
|
||||||
|
double powDbAvg = CalcDb::dbPower(magsqAvg);
|
||||||
|
double powDbPeak = CalcDb::dbPower(magsqPeak);
|
||||||
|
|
||||||
|
ui->channelPowerMeter->levelChanged(
|
||||||
|
(100.0f + powDbAvg) / 100.0f,
|
||||||
|
(100.0f + powDbPeak) / 100.0f,
|
||||||
|
nbMagsqSamples);
|
||||||
|
|
||||||
|
if (m_tickCount % 4 == 0) {
|
||||||
|
ui->channelPower->setText(QString::number(powDbAvg, 'f', 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update channel combobox according to current frequency
|
||||||
|
double frequencyInHz;
|
||||||
|
if (ChannelWebAPIUtils::getCenterFrequency(m_dabDemod->getDeviceSetIndex(), frequencyInHz))
|
||||||
|
{
|
||||||
|
frequencyInHz += m_settings.m_inputFrequencyOffset;
|
||||||
|
double frequencyInkHz = std::round(frequencyInHz / 1e3);
|
||||||
|
double frequencyInMHz = frequencyInkHz / 1000.0;
|
||||||
|
|
||||||
|
if (m_channelFreq != frequencyInMHz * 1e6)
|
||||||
|
{
|
||||||
|
QString freqText = QString::number(frequencyInMHz, 'f', 3);
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < ui->channel->count(); i++)
|
||||||
|
{
|
||||||
|
if (ui->channel->itemText(i).contains(freqText))
|
||||||
|
{
|
||||||
|
ui->channel->blockSignals(true);
|
||||||
|
ui->channel->setCurrentIndex(i);
|
||||||
|
ui->channel->blockSignals(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == ui->channel->count())
|
||||||
|
{
|
||||||
|
ui->channel->setCurrentIndex(-1);
|
||||||
|
m_channelFreq = -1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_tickCount++;
|
||||||
|
}
|
113
plugins/channelrx/demoddab/dabdemodgui.h
Normal file
113
plugins/channelrx/demoddab/dabdemodgui.h
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef INCLUDE_DABDEMODGUI_H
|
||||||
|
#define INCLUDE_DABDEMODGUI_H
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QTableWidgetItem>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
#include "channel/channelgui.h"
|
||||||
|
#include "dsp/channelmarker.h"
|
||||||
|
#include "dsp/movingaverage.h"
|
||||||
|
#include "util/messagequeue.h"
|
||||||
|
#include "dabdemodsettings.h"
|
||||||
|
#include "dabdemod.h"
|
||||||
|
|
||||||
|
class PluginAPI;
|
||||||
|
class DeviceUISet;
|
||||||
|
class BasebandSampleSink;
|
||||||
|
class DABDemod;
|
||||||
|
class DABDemodGUI;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class DABDemodGUI;
|
||||||
|
}
|
||||||
|
class DABDemodGUI;
|
||||||
|
|
||||||
|
class DABDemodGUI : public ChannelGUI {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
static DABDemodGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel);
|
||||||
|
virtual void destroy();
|
||||||
|
|
||||||
|
void resetToDefaults();
|
||||||
|
QByteArray serialize() const;
|
||||||
|
bool deserialize(const QByteArray& data);
|
||||||
|
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void channelMarkerChangedByCursor();
|
||||||
|
void channelMarkerHighlightedByCursor();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::DABDemodGUI* ui;
|
||||||
|
PluginAPI* m_pluginAPI;
|
||||||
|
DeviceUISet* m_deviceUISet;
|
||||||
|
ChannelMarker m_channelMarker;
|
||||||
|
DABDemodSettings m_settings;
|
||||||
|
bool m_doApplySettings;
|
||||||
|
|
||||||
|
DABDemod* m_dabDemod;
|
||||||
|
int m_basebandSampleRate;
|
||||||
|
uint32_t m_tickCount;
|
||||||
|
MessageQueue m_inputMessageQueue;
|
||||||
|
double m_channelFreq;
|
||||||
|
|
||||||
|
QMenu *menu; // Column select context menu
|
||||||
|
|
||||||
|
explicit DABDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0);
|
||||||
|
virtual ~DABDemodGUI();
|
||||||
|
|
||||||
|
void blockApplySettings(bool block);
|
||||||
|
void applySettings(bool force = false);
|
||||||
|
void displaySettings();
|
||||||
|
void displayStreamIndex();
|
||||||
|
void addProgramName(const DABDemod::MsgDABProgramName& program);
|
||||||
|
bool handleMessage(const Message& message);
|
||||||
|
void audioSelect();
|
||||||
|
void leaveEvent(QEvent*);
|
||||||
|
void enterEvent(QEvent*);
|
||||||
|
void resetService();
|
||||||
|
void resizeTable();
|
||||||
|
QAction *createCheckableItem(QString& text, int idx, bool checked);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_deltaFrequency_changed(qint64 value);
|
||||||
|
void on_audioMute_toggled(bool checked);
|
||||||
|
void on_volume_valueChanged(int value);
|
||||||
|
void on_rfBW_valueChanged(int index);
|
||||||
|
void on_filter_editingFinished();
|
||||||
|
void on_clearTable_clicked();
|
||||||
|
void on_programs_cellDoubleClicked(int row, int column);
|
||||||
|
void on_channel_currentIndexChanged(int index);
|
||||||
|
void filterRow(int row);
|
||||||
|
void filter();
|
||||||
|
void programs_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
|
||||||
|
void programs_sectionResized(int logicalIndex, int oldSize, int newSize);
|
||||||
|
void columnSelectMenu(QPoint pos);
|
||||||
|
void columnSelectMenuChecked(bool checked = false);
|
||||||
|
void onWidgetRolled(QWidget* widget, bool rollDown);
|
||||||
|
void onMenuDialogCalled(const QPoint& p);
|
||||||
|
void handleInputMessages();
|
||||||
|
void tick();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_DABDEMODGUI_H
|
1017
plugins/channelrx/demoddab/dabdemodgui.ui
Normal file
1017
plugins/channelrx/demoddab/dabdemodgui.ui
Normal file
File diff suppressed because it is too large
Load Diff
92
plugins/channelrx/demoddab/dabdemodplugin.cpp
Normal file
92
plugins/channelrx/demoddab/dabdemodplugin.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <QtPlugin>
|
||||||
|
#include "plugin/pluginapi.h"
|
||||||
|
|
||||||
|
#ifndef SERVER_MODE
|
||||||
|
#include "dabdemodgui.h"
|
||||||
|
#endif
|
||||||
|
#include "dabdemod.h"
|
||||||
|
#include "dabdemodwebapiadapter.h"
|
||||||
|
#include "dabdemodplugin.h"
|
||||||
|
|
||||||
|
const PluginDescriptor DABDemodPlugin::m_pluginDescriptor = {
|
||||||
|
DABDemod::m_channelId,
|
||||||
|
QStringLiteral("DAB Demodulator"),
|
||||||
|
QStringLiteral("6.9.0"),
|
||||||
|
QStringLiteral("(c) Jon Beniston, M7RCE. DAB library by Jvan Katwijk"),
|
||||||
|
QStringLiteral("https://github.com/f4exb/sdrangel"),
|
||||||
|
true,
|
||||||
|
QStringLiteral("https://github.com/f4exb/sdrangel")
|
||||||
|
};
|
||||||
|
|
||||||
|
DABDemodPlugin::DABDemodPlugin(QObject* parent) :
|
||||||
|
QObject(parent),
|
||||||
|
m_pluginAPI(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const PluginDescriptor& DABDemodPlugin::getPluginDescriptor() const
|
||||||
|
{
|
||||||
|
return m_pluginDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||||
|
{
|
||||||
|
m_pluginAPI = pluginAPI;
|
||||||
|
|
||||||
|
m_pluginAPI->registerRxChannel(DABDemod::m_channelIdURI, DABDemod::m_channelId, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodPlugin::createRxChannel(DeviceAPI *deviceAPI, BasebandSampleSink **bs, ChannelAPI **cs) const
|
||||||
|
{
|
||||||
|
if (bs || cs)
|
||||||
|
{
|
||||||
|
DABDemod *instance = new DABDemod(deviceAPI);
|
||||||
|
|
||||||
|
if (bs) {
|
||||||
|
*bs = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cs) {
|
||||||
|
*cs = instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SERVER_MODE
|
||||||
|
ChannelGUI* DABDemodPlugin::createRxChannelGUI(
|
||||||
|
DeviceUISet *deviceUISet,
|
||||||
|
BasebandSampleSink *rxChannel) const
|
||||||
|
{
|
||||||
|
(void) deviceUISet;
|
||||||
|
(void) rxChannel;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ChannelGUI* DABDemodPlugin::createRxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) const
|
||||||
|
{
|
||||||
|
return DABDemodGUI::create(m_pluginAPI, deviceUISet, rxChannel);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ChannelWebAPIAdapter* DABDemodPlugin::createChannelWebAPIAdapter() const
|
||||||
|
{
|
||||||
|
return new DABDemodWebAPIAdapter();
|
||||||
|
}
|
49
plugins/channelrx/demoddab/dabdemodplugin.h
Normal file
49
plugins/channelrx/demoddab/dabdemodplugin.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef INCLUDE_DABDEMODPLUGIN_H
|
||||||
|
#define INCLUDE_DABDEMODPLUGIN_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include "plugin/plugininterface.h"
|
||||||
|
|
||||||
|
class DeviceUISet;
|
||||||
|
class BasebandSampleSink;
|
||||||
|
|
||||||
|
class DABDemodPlugin : public QObject, PluginInterface {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(PluginInterface)
|
||||||
|
Q_PLUGIN_METADATA(IID "sdrangel.channel.dabdemod")
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DABDemodPlugin(QObject* parent = NULL);
|
||||||
|
|
||||||
|
const PluginDescriptor& getPluginDescriptor() const;
|
||||||
|
void initPlugin(PluginAPI* pluginAPI);
|
||||||
|
|
||||||
|
virtual void createRxChannel(DeviceAPI *deviceAPI, BasebandSampleSink **bs, ChannelAPI **cs) const;
|
||||||
|
virtual ChannelGUI* createRxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) const;
|
||||||
|
virtual ChannelWebAPIAdapter* createChannelWebAPIAdapter() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const PluginDescriptor m_pluginDescriptor;
|
||||||
|
|
||||||
|
PluginAPI* m_pluginAPI;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_DABDEMODPLUGIN_H
|
149
plugins/channelrx/demoddab/dabdemodsettings.cpp
Normal file
149
plugins/channelrx/demoddab/dabdemodsettings.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2015 Edouard Griffiths, F4EXB. //
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
|
#include "dsp/dspengine.h"
|
||||||
|
#include "util/simpleserializer.h"
|
||||||
|
#include "settings/serializable.h"
|
||||||
|
#include "dabdemodsettings.h"
|
||||||
|
|
||||||
|
DABDemodSettings::DABDemodSettings() :
|
||||||
|
m_channelMarker(0)
|
||||||
|
{
|
||||||
|
resetToDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSettings::resetToDefaults()
|
||||||
|
{
|
||||||
|
m_inputFrequencyOffset = 0;
|
||||||
|
m_rfBandwidth = 1537000.0f;
|
||||||
|
m_filter = "";
|
||||||
|
m_volume = 5.0f;
|
||||||
|
m_audioMute = false;
|
||||||
|
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
|
|
||||||
|
m_rgbColor = QColor(77, 105, 25).rgb();
|
||||||
|
m_title = "DAB Demodulator";
|
||||||
|
m_streamIndex = 0;
|
||||||
|
m_useReverseAPI = false;
|
||||||
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
m_reverseAPIDeviceIndex = 0;
|
||||||
|
m_reverseAPIChannelIndex = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < DABDEMOD_COLUMNS; i++)
|
||||||
|
{
|
||||||
|
m_columnIndexes[i] = i;
|
||||||
|
m_columnSizes[i] = -1; // Autosize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray DABDemodSettings::serialize() const
|
||||||
|
{
|
||||||
|
SimpleSerializer s(1);
|
||||||
|
s.writeS32(1, m_inputFrequencyOffset);
|
||||||
|
s.writeS32(2, m_streamIndex);
|
||||||
|
s.writeString(3, m_filter);
|
||||||
|
s.writeFloat(4, m_rfBandwidth);
|
||||||
|
s.writeFloat(5, m_volume);
|
||||||
|
s.writeBool(6, m_audioMute);
|
||||||
|
s.writeString(7, m_audioDeviceName);
|
||||||
|
|
||||||
|
if (m_channelMarker) {
|
||||||
|
s.writeBlob(8, m_channelMarker->serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
s.writeU32(9, m_rgbColor);
|
||||||
|
s.writeString(10, m_title);
|
||||||
|
s.writeBool(11, m_useReverseAPI);
|
||||||
|
s.writeString(12, m_reverseAPIAddress);
|
||||||
|
s.writeU32(13, m_reverseAPIPort);
|
||||||
|
s.writeU32(14, m_reverseAPIDeviceIndex);
|
||||||
|
s.writeU32(15, m_reverseAPIChannelIndex);
|
||||||
|
|
||||||
|
for (int i = 0; i < DABDEMOD_COLUMNS; i++)
|
||||||
|
s.writeS32(100 + i, m_columnIndexes[i]);
|
||||||
|
for (int i = 0; i < DABDEMOD_COLUMNS; i++)
|
||||||
|
s.writeS32(200 + i, m_columnSizes[i]);
|
||||||
|
|
||||||
|
return s.final();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DABDemodSettings::deserialize(const QByteArray& data)
|
||||||
|
{
|
||||||
|
SimpleDeserializer d(data);
|
||||||
|
|
||||||
|
if(!d.isValid())
|
||||||
|
{
|
||||||
|
resetToDefaults();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(d.getVersion() == 1)
|
||||||
|
{
|
||||||
|
QByteArray bytetmp;
|
||||||
|
uint32_t utmp;
|
||||||
|
QString strtmp;
|
||||||
|
|
||||||
|
d.readS32(1, &m_inputFrequencyOffset, 0);
|
||||||
|
d.readS32(2, &m_streamIndex, 0);
|
||||||
|
d.readString(3, &m_filter, "");
|
||||||
|
d.readFloat(4, &m_rfBandwidth, 1537000.0f);
|
||||||
|
d.readFloat(5, &m_volume, 5.0f);
|
||||||
|
d.readBool(6, &m_audioMute, false);
|
||||||
|
d.readString(7, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName);
|
||||||
|
|
||||||
|
d.readBlob(8, &bytetmp);
|
||||||
|
|
||||||
|
if (m_channelMarker) {
|
||||||
|
m_channelMarker->deserialize(bytetmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
d.readU32(9, &m_rgbColor, QColor(77, 105, 25).rgb());
|
||||||
|
d.readString(10, &m_title, "DAB Demodulator");
|
||||||
|
d.readBool(11, &m_useReverseAPI, false);
|
||||||
|
d.readString(12, &m_reverseAPIAddress, "127.0.0.1");
|
||||||
|
d.readU32(13, &utmp, 0);
|
||||||
|
|
||||||
|
if ((utmp > 1023) && (utmp < 65535)) {
|
||||||
|
m_reverseAPIPort = utmp;
|
||||||
|
} else {
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.readU32(14, &utmp, 0);
|
||||||
|
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
d.readU32(15, &utmp, 0);
|
||||||
|
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
|
||||||
|
for (int i = 0; i < DABDEMOD_COLUMNS; i++)
|
||||||
|
d.readS32(100 + i, &m_columnIndexes[i], i);
|
||||||
|
for (int i = 0; i < DABDEMOD_COLUMNS; i++)
|
||||||
|
d.readS32(200 + i, &m_columnSizes[i], -1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resetToDefaults();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
59
plugins/channelrx/demoddab/dabdemodsettings.h
Normal file
59
plugins/channelrx/demoddab/dabdemodsettings.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2017 Edouard Griffiths, F4EXB. //
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef INCLUDE_DABDEMODSETTINGS_H
|
||||||
|
#define INCLUDE_DABDEMODSETTINGS_H
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
|
class Serializable;
|
||||||
|
|
||||||
|
// Number of columns in the table
|
||||||
|
#define DABDEMOD_COLUMNS 3
|
||||||
|
|
||||||
|
struct DABDemodSettings
|
||||||
|
{
|
||||||
|
qint32 m_inputFrequencyOffset;
|
||||||
|
Real m_rfBandwidth;
|
||||||
|
QString m_filter;
|
||||||
|
QString m_program;
|
||||||
|
Real m_volume;
|
||||||
|
bool m_audioMute;
|
||||||
|
|
||||||
|
quint32 m_rgbColor;
|
||||||
|
QString m_title;
|
||||||
|
Serializable *m_channelMarker;
|
||||||
|
QString m_audioDeviceName;
|
||||||
|
int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx).
|
||||||
|
bool m_useReverseAPI;
|
||||||
|
QString m_reverseAPIAddress;
|
||||||
|
uint16_t m_reverseAPIPort;
|
||||||
|
uint16_t m_reverseAPIDeviceIndex;
|
||||||
|
uint16_t m_reverseAPIChannelIndex;
|
||||||
|
|
||||||
|
int m_columnIndexes[DABDEMOD_COLUMNS];//!< How the columns are ordered in the table
|
||||||
|
int m_columnSizes[DABDEMOD_COLUMNS]; //!< Size of the columns in the table
|
||||||
|
|
||||||
|
DABDemodSettings();
|
||||||
|
void resetToDefaults();
|
||||||
|
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
|
||||||
|
QByteArray serialize() const;
|
||||||
|
bool deserialize(const QByteArray& data);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* INCLUDE_DABDEMODSETTINGS_H */
|
644
plugins/channelrx/demoddab/dabdemodsink.cpp
Normal file
644
plugins/channelrx/demoddab/dabdemodsink.cpp
Normal file
@ -0,0 +1,644 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <complex.h>
|
||||||
|
|
||||||
|
#include "dsp/dspengine.h"
|
||||||
|
#include "dsp/datafifo.h"
|
||||||
|
#include "util/db.h"
|
||||||
|
#include "pipes/pipeendpoint.h"
|
||||||
|
#include "maincore.h"
|
||||||
|
|
||||||
|
#include "dabdemod.h"
|
||||||
|
#include "dabdemodsink.h"
|
||||||
|
|
||||||
|
// Callbacks from DAB library
|
||||||
|
|
||||||
|
void syncHandler(bool value, void *ctx)
|
||||||
|
{
|
||||||
|
(void)value;
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void systemDataHandler(bool sync, int16_t snr, int32_t freqOffset, void *ctx)
|
||||||
|
{
|
||||||
|
DABDemodSink *sink = (DABDemodSink *)ctx;
|
||||||
|
sink->systemData(sync, snr, freqOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ensembleNameHandler(std::string name, int32_t id, void *ctx)
|
||||||
|
{
|
||||||
|
DABDemodSink *sink = (DABDemodSink *)ctx;
|
||||||
|
sink->ensembleName(QString::fromStdString(name), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void programNameHandler(std::string name, int32_t id, void *ctx)
|
||||||
|
{
|
||||||
|
DABDemodSink *sink = (DABDemodSink *)ctx;
|
||||||
|
sink->programName(QString::fromStdString(name), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fibQualityHandler(int16_t percent, void *ctx)
|
||||||
|
{
|
||||||
|
DABDemodSink *sink = (DABDemodSink *)ctx;
|
||||||
|
sink->fibQuality(percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void audioHandler(int16_t *buffer, int size, int samplerate, bool stereo, void *ctx)
|
||||||
|
{
|
||||||
|
DABDemodSink *sink = (DABDemodSink *)ctx;
|
||||||
|
sink->audio(buffer, size, samplerate, stereo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dataHandler(std::string data, void *ctx)
|
||||||
|
{
|
||||||
|
DABDemodSink *sink = (DABDemodSink *)ctx;
|
||||||
|
sink->data(QString::fromStdString(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void byteHandler(uint8_t *data, int16_t a, uint8_t b, void *ctx)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
(void)a;
|
||||||
|
(void)b;
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: North America has different table
|
||||||
|
static const char *dabProgramType[] =
|
||||||
|
{
|
||||||
|
"No programme type",
|
||||||
|
"News",
|
||||||
|
"Current Affairs",
|
||||||
|
"Information",
|
||||||
|
"Sport",
|
||||||
|
"Education",
|
||||||
|
"Drama",
|
||||||
|
"Culture",
|
||||||
|
"Science",
|
||||||
|
"Varied",
|
||||||
|
"Pop Music",
|
||||||
|
"Rock Music",
|
||||||
|
"Easy Listening Music",
|
||||||
|
"Light Classical",
|
||||||
|
"Serious Classical",
|
||||||
|
"Other Music",
|
||||||
|
"Weather/meteorology",
|
||||||
|
"Finance/Business",
|
||||||
|
"Children's programmes",
|
||||||
|
"Social Affairs",
|
||||||
|
"Religion",
|
||||||
|
"Phone In",
|
||||||
|
"Travel",
|
||||||
|
"Leisure",
|
||||||
|
"Jazz Music",
|
||||||
|
"Country Music",
|
||||||
|
"National Music",
|
||||||
|
"Oldies Music",
|
||||||
|
"Folk Music",
|
||||||
|
"Documentary",
|
||||||
|
"Not used",
|
||||||
|
"Not used",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *dabLanguageCode[] =
|
||||||
|
{
|
||||||
|
"Unknown",
|
||||||
|
"Albanian",
|
||||||
|
"Breton",
|
||||||
|
"Catalan",
|
||||||
|
"Croatian",
|
||||||
|
"Welsh",
|
||||||
|
"Czech",
|
||||||
|
"Danish",
|
||||||
|
"German",
|
||||||
|
"English",
|
||||||
|
"Spanish",
|
||||||
|
"Esperanto",
|
||||||
|
"Estonian",
|
||||||
|
"Basque",
|
||||||
|
"Faroese",
|
||||||
|
"French",
|
||||||
|
"Frisian",
|
||||||
|
"Irish",
|
||||||
|
"Gaelic",
|
||||||
|
"Galician",
|
||||||
|
"Icelandic",
|
||||||
|
"Italian",
|
||||||
|
"Sami",
|
||||||
|
"Latin",
|
||||||
|
"Latvian",
|
||||||
|
"Luxembourgian",
|
||||||
|
"Lithuanian",
|
||||||
|
"Hungarian",
|
||||||
|
"Maltese",
|
||||||
|
"Dutch",
|
||||||
|
"Norwegian",
|
||||||
|
"Occitan",
|
||||||
|
"Polish",
|
||||||
|
"Portuguese",
|
||||||
|
"Romanian",
|
||||||
|
"Romansh",
|
||||||
|
"Serbian",
|
||||||
|
"Slovak",
|
||||||
|
"Slovene",
|
||||||
|
"Finnish",
|
||||||
|
"Swedish",
|
||||||
|
"Turkish",
|
||||||
|
"Flemish",
|
||||||
|
"Walloon",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Background sound",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Reserved",
|
||||||
|
"Zulu",
|
||||||
|
"Vietnamese",
|
||||||
|
"Uzbek",
|
||||||
|
"Urdu",
|
||||||
|
"Ukranian",
|
||||||
|
"Thai",
|
||||||
|
"Telugu",
|
||||||
|
"Tatar",
|
||||||
|
"Tamil",
|
||||||
|
"Tadzhik",
|
||||||
|
"Swahili",
|
||||||
|
"Sranan Tongo",
|
||||||
|
"Somali",
|
||||||
|
"Sinhalese",
|
||||||
|
"Shona",
|
||||||
|
"Serbo-Croat",
|
||||||
|
"Rusyn",
|
||||||
|
"Russian",
|
||||||
|
"Quechua",
|
||||||
|
"Pushtu",
|
||||||
|
"Punjabi",
|
||||||
|
"Persian",
|
||||||
|
"Papiamento",
|
||||||
|
"Oriya",
|
||||||
|
"Nepali",
|
||||||
|
"Ndebele",
|
||||||
|
"Marathi",
|
||||||
|
"Moldavian",
|
||||||
|
"Malaysian",
|
||||||
|
"Malagasay",
|
||||||
|
"Macedonian",
|
||||||
|
"Laotian",
|
||||||
|
"Korean",
|
||||||
|
"Khmer",
|
||||||
|
"Kazakh",
|
||||||
|
"Kannada",
|
||||||
|
"Japanese",
|
||||||
|
"Indonesian",
|
||||||
|
"Hindi",
|
||||||
|
"Hebrew",
|
||||||
|
"Hausa",
|
||||||
|
"Gurani",
|
||||||
|
"Gujurati",
|
||||||
|
"Greek",
|
||||||
|
"Georgian",
|
||||||
|
"Fulani",
|
||||||
|
"Dari",
|
||||||
|
"Chuvash",
|
||||||
|
"Chinese",
|
||||||
|
"Burmese",
|
||||||
|
"Bulgarian",
|
||||||
|
"Bengali",
|
||||||
|
"Belorussian",
|
||||||
|
"Bambora",
|
||||||
|
"Azerbaijani",
|
||||||
|
"Assamese",
|
||||||
|
"Armenian",
|
||||||
|
"Arabic",
|
||||||
|
"Amharic",
|
||||||
|
};
|
||||||
|
|
||||||
|
void programDataHandler(audiodata *data, void *ctx)
|
||||||
|
{
|
||||||
|
QString audio;
|
||||||
|
if (data->ASCTy == 0)
|
||||||
|
audio = "DAB";
|
||||||
|
else if (data->ASCTy == 63)
|
||||||
|
audio = "DAB+";
|
||||||
|
else
|
||||||
|
audio = "Unknown";
|
||||||
|
|
||||||
|
QString language = "";
|
||||||
|
if ((data->language < 0x80) && (data->language >= 0))
|
||||||
|
language = dabLanguageCode[data->language & 0x7f];
|
||||||
|
|
||||||
|
DABDemodSink *sink = (DABDemodSink *)ctx;
|
||||||
|
sink->programData(data->bitRate, audio, language, dabProgramType[data->programType & 0x1f]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void programQualityHandler(int16_t frames, int16_t rs, int16_t aac, void *ctx)
|
||||||
|
{
|
||||||
|
DABDemodSink *sink = (DABDemodSink *)ctx;
|
||||||
|
sink->programQuality(frames, rs, aac);
|
||||||
|
}
|
||||||
|
|
||||||
|
void motDataHandler(std::string data, int a, void *ctx)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::systemData(bool sync, int16_t snr, int32_t freqOffset)
|
||||||
|
{
|
||||||
|
if (getMessageQueueToChannel())
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABSystemData *msg = DABDemod::MsgDABSystemData::create(sync, snr, freqOffset);
|
||||||
|
getMessageQueueToChannel()->push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DABDemodSink::ensembleName(const QString& name, int id)
|
||||||
|
{
|
||||||
|
if (getMessageQueueToChannel())
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABEnsembleName *msg = DABDemod::MsgDABEnsembleName::create(name, id);
|
||||||
|
getMessageQueueToChannel()->push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::programName(const QString& name, int id)
|
||||||
|
{
|
||||||
|
if (getMessageQueueToChannel())
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABProgramName *msg = DABDemod::MsgDABProgramName::create(name, id);
|
||||||
|
getMessageQueueToChannel()->push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::programData(int bitrate, const QString& audio, const QString& language, const QString& programType)
|
||||||
|
{
|
||||||
|
if (getMessageQueueToChannel())
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABProgramData *msg = DABDemod::MsgDABProgramData::create(bitrate, audio, language, programType);
|
||||||
|
getMessageQueueToChannel()->push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::fibQuality(int16_t percent)
|
||||||
|
{
|
||||||
|
if (getMessageQueueToChannel())
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABFIBQuality *msg = DABDemod::MsgDABFIBQuality::create(percent);
|
||||||
|
getMessageQueueToChannel()->push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::programQuality(int16_t frames, int16_t rs, int16_t aac)
|
||||||
|
{
|
||||||
|
if (getMessageQueueToChannel())
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABProgramQuality *msg = DABDemod::MsgDABProgramQuality::create(frames, rs, aac);
|
||||||
|
getMessageQueueToChannel()->push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::data(const QString& data)
|
||||||
|
{
|
||||||
|
if (getMessageQueueToChannel())
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABData *msg = DABDemod::MsgDABData::create(data);
|
||||||
|
getMessageQueueToChannel()->push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int16_t scale(int16_t sample, float factor)
|
||||||
|
{
|
||||||
|
int32_t prod = (int32_t)(((int32_t)sample) * factor);
|
||||||
|
prod = std::min(prod, 32767);
|
||||||
|
prod = std::max(prod, -32768);
|
||||||
|
return (int16_t)prod;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::audio(int16_t *buffer, int size, int samplerate, bool stereo)
|
||||||
|
{
|
||||||
|
(void)stereo;
|
||||||
|
(void)samplerate;
|
||||||
|
|
||||||
|
if (samplerate != m_dabAudioSampleRate)
|
||||||
|
{
|
||||||
|
applyDABAudioSampleRate(samplerate);
|
||||||
|
if (getMessageQueueToChannel())
|
||||||
|
{
|
||||||
|
DABDemod::MsgDABSampleRate *msg = DABDemod::MsgDABSampleRate::create(samplerate);
|
||||||
|
getMessageQueueToChannel()->push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// buffer is always 2 channels
|
||||||
|
for (int i = 0; i < size; i+=2)
|
||||||
|
{
|
||||||
|
Complex ci, ca;
|
||||||
|
if (!m_settings.m_audioMute)
|
||||||
|
{
|
||||||
|
ci.real(buffer[i]);
|
||||||
|
ci.imag(buffer[i+1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ci.real(0.0f);
|
||||||
|
ci.imag(0.0f);
|
||||||
|
}
|
||||||
|
if (m_audioInterpolatorDistance < 1.0f) // interpolate
|
||||||
|
{
|
||||||
|
while (!m_audioInterpolator.interpolate(&m_audioInterpolatorDistanceRemain, ci, &ca))
|
||||||
|
{
|
||||||
|
processOneAudioSample(ca);
|
||||||
|
m_audioInterpolatorDistanceRemain += m_audioInterpolatorDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // decimate
|
||||||
|
{
|
||||||
|
if (m_audioInterpolator.decimate(&m_audioInterpolatorDistanceRemain, ci, &ca))
|
||||||
|
{
|
||||||
|
processOneAudioSample(ca);
|
||||||
|
m_audioInterpolatorDistanceRemain += m_audioInterpolatorDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::reset()
|
||||||
|
{
|
||||||
|
dabReset(m_dab);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::resetService()
|
||||||
|
{
|
||||||
|
dabReset_msc(m_dab);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::processOneAudioSample(Complex &ci)
|
||||||
|
{
|
||||||
|
float factor = m_settings.m_volume / 5.0f; // Should this be 5 or 10? 5 allows some positive gain
|
||||||
|
|
||||||
|
qint16 l = scale(ci.real(), factor);
|
||||||
|
qint16 r = scale(ci.real(), factor);
|
||||||
|
|
||||||
|
m_audioBuffer[m_audioBufferFill].l = l;
|
||||||
|
m_audioBuffer[m_audioBufferFill].r = r;
|
||||||
|
++m_audioBufferFill;
|
||||||
|
|
||||||
|
if (m_audioBufferFill >= m_audioBuffer.size())
|
||||||
|
{
|
||||||
|
uint res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
|
||||||
|
|
||||||
|
if (res != m_audioBufferFill)
|
||||||
|
{
|
||||||
|
qDebug("DABDemodSink::audio: %u/%u audio samples written", res, m_audioBufferFill);
|
||||||
|
m_audioFifo.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_audioBufferFill = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_demodBuffer[m_demodBufferFill++] = l; // FIXME: What about right channel?
|
||||||
|
if (m_demodBufferFill >= m_demodBuffer.size())
|
||||||
|
{
|
||||||
|
QList<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
|
||||||
|
|
||||||
|
if (dataFifos)
|
||||||
|
{
|
||||||
|
QList<DataFifo*>::iterator it = dataFifos->begin();
|
||||||
|
|
||||||
|
for (; it != dataFifos->end(); ++it) {
|
||||||
|
(*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_demodBufferFill = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DABDemodSink::DABDemodSink(DABDemod *packetDemod) :
|
||||||
|
m_dabDemod(packetDemod),
|
||||||
|
m_audioSampleRate(48000),
|
||||||
|
m_dabAudioSampleRate(10000), // Unused value to begin with
|
||||||
|
m_channelSampleRate(DABDEMOD_CHANNEL_SAMPLE_RATE),
|
||||||
|
m_channelFrequencyOffset(0),
|
||||||
|
m_magsqSum(0.0f),
|
||||||
|
m_magsqPeak(0.0f),
|
||||||
|
m_magsqCount(0),
|
||||||
|
m_messageQueueToChannel(nullptr),
|
||||||
|
m_audioFifo(48000)
|
||||||
|
{
|
||||||
|
m_audioBuffer.resize(1<<14);
|
||||||
|
m_audioBufferFill = 0;
|
||||||
|
|
||||||
|
m_magsq = 0.0;
|
||||||
|
|
||||||
|
m_demodBuffer.resize(1<<12);
|
||||||
|
m_demodBufferFill = 0;
|
||||||
|
|
||||||
|
applySettings(m_settings, true);
|
||||||
|
applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true);
|
||||||
|
|
||||||
|
int mode = 1; // Latest DAB spec only has mode 1
|
||||||
|
m_dab = dabInit(&m_device,
|
||||||
|
mode,
|
||||||
|
syncHandler,
|
||||||
|
systemDataHandler,
|
||||||
|
ensembleNameHandler,
|
||||||
|
programNameHandler,
|
||||||
|
fibQualityHandler,
|
||||||
|
audioHandler,
|
||||||
|
dataHandler,
|
||||||
|
byteHandler,
|
||||||
|
programDataHandler,
|
||||||
|
programQualityHandler,
|
||||||
|
motDataHandler,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
this);
|
||||||
|
dabStartProcessing(m_dab);
|
||||||
|
}
|
||||||
|
|
||||||
|
DABDemodSink::~DABDemodSink()
|
||||||
|
{
|
||||||
|
dabExit(m_dab);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
|
||||||
|
{
|
||||||
|
Complex ci;
|
||||||
|
|
||||||
|
for (SampleVector::const_iterator it = begin; it != end; ++it)
|
||||||
|
{
|
||||||
|
Complex c(it->real(), it->imag());
|
||||||
|
c *= m_nco.nextIQ();
|
||||||
|
|
||||||
|
if (m_interpolatorDistance == 1.0f)
|
||||||
|
{
|
||||||
|
processOneSample(c);
|
||||||
|
}
|
||||||
|
else if (m_interpolatorDistance < 1.0f) // interpolate
|
||||||
|
{
|
||||||
|
while (!m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci))
|
||||||
|
{
|
||||||
|
processOneSample(ci);
|
||||||
|
m_interpolatorDistanceRemain += m_interpolatorDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // decimate
|
||||||
|
{
|
||||||
|
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci))
|
||||||
|
{
|
||||||
|
processOneSample(ci);
|
||||||
|
m_interpolatorDistanceRemain += m_interpolatorDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::processOneSample(Complex &ci)
|
||||||
|
{
|
||||||
|
// Calculate average and peak levels for level meter
|
||||||
|
double magsqRaw = ci.real()*ci.real() + ci.imag()*ci.imag();
|
||||||
|
Real magsq = (Real)(magsqRaw / (SDR_RX_SCALED*SDR_RX_SCALED));
|
||||||
|
m_movingAverage(magsq);
|
||||||
|
m_magsq = m_movingAverage.asDouble();
|
||||||
|
m_magsqSum += magsq;
|
||||||
|
if (magsq > m_magsqPeak)
|
||||||
|
{
|
||||||
|
m_magsqPeak = magsq;
|
||||||
|
}
|
||||||
|
m_magsqCount++;
|
||||||
|
|
||||||
|
// Send sample to DAB library
|
||||||
|
std::complex<float> c;
|
||||||
|
c.real(ci.real()/SDR_RX_SCALED);
|
||||||
|
c.imag(ci.imag()/SDR_RX_SCALED);
|
||||||
|
m_device.putSample(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
|
||||||
|
{
|
||||||
|
qDebug() << "DABDemodSink::applyChannelSettings:"
|
||||||
|
<< " channelSampleRate: " << channelSampleRate
|
||||||
|
<< " channelFrequencyOffset: " << channelFrequencyOffset;
|
||||||
|
|
||||||
|
if ((m_channelFrequencyOffset != channelFrequencyOffset) ||
|
||||||
|
(m_channelSampleRate != channelSampleRate) || force)
|
||||||
|
{
|
||||||
|
m_nco.setFreq(-channelFrequencyOffset, channelSampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_channelSampleRate != channelSampleRate) || force)
|
||||||
|
{
|
||||||
|
m_interpolator.create(16, channelSampleRate, m_settings.m_rfBandwidth / 2.2);
|
||||||
|
m_interpolatorDistance = (Real) channelSampleRate / (Real) DABDEMOD_CHANNEL_SAMPLE_RATE;
|
||||||
|
m_interpolatorDistanceRemain = m_interpolatorDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_channelSampleRate = channelSampleRate;
|
||||||
|
m_channelFrequencyOffset = channelFrequencyOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DABDemodSink::applySettings(const DABDemodSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
qDebug() << "DABDemodSink::applySettings:"
|
||||||
|
<< " force: " << force;
|
||||||
|
|
||||||
|
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
|
||||||
|
{
|
||||||
|
m_interpolator.create(16, m_channelSampleRate, settings.m_rfBandwidth / 2.2);
|
||||||
|
m_interpolatorDistance = (Real) m_channelSampleRate / (Real) DABDEMOD_CHANNEL_SAMPLE_RATE;
|
||||||
|
m_interpolatorDistanceRemain = m_interpolatorDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((settings.m_program != m_settings.m_program) || force)
|
||||||
|
{
|
||||||
|
if (!settings.m_program.isEmpty())
|
||||||
|
{
|
||||||
|
QByteArray ba = settings.m_program.toLatin1();
|
||||||
|
const char *program = ba.data();
|
||||||
|
if (!is_audioService (m_dab, program))
|
||||||
|
qWarning() << settings.m_program << " is not an audio service";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dataforAudioService(m_dab, program, &m_ad, 0);
|
||||||
|
if (!m_ad.defined)
|
||||||
|
qWarning() << settings.m_program << " audio data is not defined";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dabReset_msc(m_dab);
|
||||||
|
set_audioChannel(m_dab, &m_ad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when audio device sample rate changes
|
||||||
|
void DABDemodSink::applyAudioSampleRate(int sampleRate)
|
||||||
|
{
|
||||||
|
if (sampleRate < 0)
|
||||||
|
{
|
||||||
|
qWarning("DABDemodSink::applyAudioSampleRate: invalid sample rate: %d", sampleRate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug("DABDemodSink::applyAudioSampleRate: m_audioSampleRate: %d m_dabAudioSampleRate: %d", sampleRate, m_dabAudioSampleRate);
|
||||||
|
|
||||||
|
m_audioInterpolator.create(16, m_dabAudioSampleRate, m_dabAudioSampleRate/2.2f);
|
||||||
|
m_audioInterpolatorDistanceRemain = 0;
|
||||||
|
m_audioInterpolatorDistance = (Real) m_dabAudioSampleRate / (Real) sampleRate;
|
||||||
|
|
||||||
|
m_audioFifo.setSize(sampleRate);
|
||||||
|
|
||||||
|
m_audioSampleRate = sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when DAB audio sample rate changes
|
||||||
|
void DABDemodSink::applyDABAudioSampleRate(int sampleRate)
|
||||||
|
{
|
||||||
|
qDebug("DABDemodSink::applyDABAudioSampleRate: m_audioSampleRate: %d new m_dabAudioSampleRate: %d", m_audioSampleRate, sampleRate);
|
||||||
|
|
||||||
|
m_audioInterpolator.create(16, sampleRate, sampleRate/2.2f);
|
||||||
|
m_audioInterpolatorDistanceRemain = 0;
|
||||||
|
m_audioInterpolatorDistance = (Real) sampleRate / (Real) m_audioSampleRate;
|
||||||
|
|
||||||
|
m_dabAudioSampleRate = sampleRate;
|
||||||
|
}
|
147
plugins/channelrx/demoddab/dabdemodsink.h
Normal file
147
plugins/channelrx/demoddab/dabdemodsink.h
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef INCLUDE_DABDEMODSINK_H
|
||||||
|
#define INCLUDE_DABDEMODSINK_H
|
||||||
|
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "dsp/channelsamplesink.h"
|
||||||
|
#include "dsp/nco.h"
|
||||||
|
#include "dsp/interpolator.h"
|
||||||
|
#include "util/movingaverage.h"
|
||||||
|
#include "util/messagequeue.h"
|
||||||
|
#include "audio/audiofifo.h"
|
||||||
|
|
||||||
|
#include "dabdemodsettings.h"
|
||||||
|
#include "dabdemoddevice.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <dab-api.h>
|
||||||
|
|
||||||
|
#define DABDEMOD_CHANNEL_SAMPLE_RATE 2048000
|
||||||
|
|
||||||
|
class ChannelAPI;
|
||||||
|
class DABDemod;
|
||||||
|
|
||||||
|
class DABDemodSink : public ChannelSampleSink {
|
||||||
|
public:
|
||||||
|
DABDemodSink(DABDemod *packetDemod);
|
||||||
|
~DABDemodSink();
|
||||||
|
|
||||||
|
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
|
||||||
|
|
||||||
|
void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false);
|
||||||
|
void applySettings(const DABDemodSettings& settings, bool force = false);
|
||||||
|
void applyAudioSampleRate(int sampleRate);
|
||||||
|
void applyDABAudioSampleRate(int sampleRate);
|
||||||
|
int getAudioSampleRate() const { return m_audioSampleRate; }
|
||||||
|
AudioFifo *getAudioFifo() { return &m_audioFifo; }
|
||||||
|
|
||||||
|
void setMessageQueueToChannel(MessageQueue *messageQueue) { m_messageQueueToChannel = messageQueue; }
|
||||||
|
void setChannel(ChannelAPI *channel) { m_channel = channel; }
|
||||||
|
|
||||||
|
double getMagSq() const { return m_magsq; }
|
||||||
|
|
||||||
|
void getMagSqLevels(double& avg, double& peak, int& nbSamples)
|
||||||
|
{
|
||||||
|
if (m_magsqCount > 0)
|
||||||
|
{
|
||||||
|
m_magsq = m_magsqSum / m_magsqCount;
|
||||||
|
m_magSqLevelStore.m_magsq = m_magsq;
|
||||||
|
m_magSqLevelStore.m_magsqPeak = m_magsqPeak;
|
||||||
|
}
|
||||||
|
|
||||||
|
avg = m_magSqLevelStore.m_magsq;
|
||||||
|
peak = m_magSqLevelStore.m_magsqPeak;
|
||||||
|
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
|
||||||
|
|
||||||
|
m_magsqSum = 0.0f;
|
||||||
|
m_magsqPeak = 0.0f;
|
||||||
|
m_magsqCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
void resetService();
|
||||||
|
|
||||||
|
// Callbacks
|
||||||
|
void systemData(bool sync, int16_t snr, int32_t freqOffset);
|
||||||
|
void ensembleName(const QString& name, int id);
|
||||||
|
void programName(const QString& name, int id);
|
||||||
|
void programData(int bitrate, const QString& audio, const QString& language, const QString& programType);
|
||||||
|
void audio(int16_t *buffer, int size, int samplerate, bool stereo);
|
||||||
|
void programQuality(int16_t frames, int16_t rs, int16_t aac);
|
||||||
|
void fibQuality(int16_t percent);
|
||||||
|
void data(const QString& data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct MagSqLevelsStore
|
||||||
|
{
|
||||||
|
MagSqLevelsStore() :
|
||||||
|
m_magsq(1e-12),
|
||||||
|
m_magsqPeak(1e-12)
|
||||||
|
{}
|
||||||
|
double m_magsq;
|
||||||
|
double m_magsqPeak;
|
||||||
|
};
|
||||||
|
|
||||||
|
DABDemod *m_dabDemod;
|
||||||
|
DABDemodSettings m_settings;
|
||||||
|
ChannelAPI *m_channel;
|
||||||
|
|
||||||
|
int m_audioSampleRate; // Output device sample rate
|
||||||
|
int m_dabAudioSampleRate;
|
||||||
|
int m_channelSampleRate;
|
||||||
|
int m_channelFrequencyOffset;
|
||||||
|
|
||||||
|
void *m_dab;
|
||||||
|
DABDemodDevice m_device;
|
||||||
|
audiodata m_ad;
|
||||||
|
|
||||||
|
NCO m_nco;
|
||||||
|
Interpolator m_interpolator;
|
||||||
|
Real m_interpolatorDistance;
|
||||||
|
Real m_interpolatorDistanceRemain;
|
||||||
|
|
||||||
|
double m_magsq;
|
||||||
|
double m_magsqSum;
|
||||||
|
double m_magsqPeak;
|
||||||
|
int m_magsqCount;
|
||||||
|
MagSqLevelsStore m_magSqLevelStore;
|
||||||
|
|
||||||
|
MessageQueue *m_messageQueueToChannel;
|
||||||
|
|
||||||
|
MovingAverageUtil<Real, double, 16> m_movingAverage;
|
||||||
|
|
||||||
|
Interpolator m_audioInterpolator;
|
||||||
|
Real m_audioInterpolatorDistance;
|
||||||
|
Real m_audioInterpolatorDistanceRemain;
|
||||||
|
AudioVector m_audioBuffer;
|
||||||
|
AudioFifo m_audioFifo;
|
||||||
|
uint32_t m_audioBufferFill;
|
||||||
|
|
||||||
|
QVector<qint16> m_demodBuffer;
|
||||||
|
int m_demodBufferFill;
|
||||||
|
|
||||||
|
void processOneSample(Complex &ci);
|
||||||
|
void processOneAudioSample(Complex &ci);
|
||||||
|
MessageQueue *getMessageQueueToChannel() { return m_messageQueueToChannel; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_DABDEMODSINK_H
|
52
plugins/channelrx/demoddab/dabdemodwebapiadapter.cpp
Normal file
52
plugins/channelrx/demoddab/dabdemodwebapiadapter.cpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2019 Edouard Griffiths, F4EXB. //
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "SWGChannelSettings.h"
|
||||||
|
#include "dabdemod.h"
|
||||||
|
#include "dabdemodwebapiadapter.h"
|
||||||
|
|
||||||
|
DABDemodWebAPIAdapter::DABDemodWebAPIAdapter()
|
||||||
|
{}
|
||||||
|
|
||||||
|
DABDemodWebAPIAdapter::~DABDemodWebAPIAdapter()
|
||||||
|
{}
|
||||||
|
|
||||||
|
int DABDemodWebAPIAdapter::webapiSettingsGet(
|
||||||
|
SWGSDRangel::SWGChannelSettings& response,
|
||||||
|
QString& errorMessage)
|
||||||
|
{
|
||||||
|
(void) errorMessage;
|
||||||
|
response.setDabDemodSettings(new SWGSDRangel::SWGDABDemodSettings());
|
||||||
|
response.getDabDemodSettings()->init();
|
||||||
|
DABDemod::webapiFormatChannelSettings(response, m_settings);
|
||||||
|
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DABDemodWebAPIAdapter::webapiSettingsPutPatch(
|
||||||
|
bool force,
|
||||||
|
const QStringList& channelSettingsKeys,
|
||||||
|
SWGSDRangel::SWGChannelSettings& response,
|
||||||
|
QString& errorMessage)
|
||||||
|
{
|
||||||
|
(void) force;
|
||||||
|
(void) errorMessage;
|
||||||
|
DABDemod::webapiUpdateChannelSettings(m_settings, channelSettingsKeys, response);
|
||||||
|
|
||||||
|
return 200;
|
||||||
|
}
|
50
plugins/channelrx/demoddab/dabdemodwebapiadapter.h
Normal file
50
plugins/channelrx/demoddab/dabdemodwebapiadapter.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2019 Edouard Griffiths, F4EXB. //
|
||||||
|
// Copyright (C) 2020 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef INCLUDE_DABDEMOD_WEBAPIADAPTER_H
|
||||||
|
#define INCLUDE_DABDEMOD_WEBAPIADAPTER_H
|
||||||
|
|
||||||
|
#include "channel/channelwebapiadapter.h"
|
||||||
|
#include "dabdemodsettings.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standalone API adapter only for the settings
|
||||||
|
*/
|
||||||
|
class DABDemodWebAPIAdapter : public ChannelWebAPIAdapter {
|
||||||
|
public:
|
||||||
|
DABDemodWebAPIAdapter();
|
||||||
|
virtual ~DABDemodWebAPIAdapter();
|
||||||
|
|
||||||
|
virtual QByteArray serialize() const { return m_settings.serialize(); }
|
||||||
|
virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); }
|
||||||
|
|
||||||
|
virtual int webapiSettingsGet(
|
||||||
|
SWGSDRangel::SWGChannelSettings& response,
|
||||||
|
QString& errorMessage);
|
||||||
|
|
||||||
|
virtual int webapiSettingsPutPatch(
|
||||||
|
bool force,
|
||||||
|
const QStringList& channelSettingsKeys,
|
||||||
|
SWGSDRangel::SWGChannelSettings& response,
|
||||||
|
QString& errorMessage);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DABDemodSettings m_settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_DABDEMOD_WEBAPIADAPTER_H
|
80
plugins/channelrx/demoddab/readme.md
Normal file
80
plugins/channelrx/demoddab/readme.md
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<h1>DAB demodulator plugin</h1>
|
||||||
|
|
||||||
|
<h2>Introduction</h2>
|
||||||
|
|
||||||
|
This plugin can be used to demodulate DAB and DAB+ radio.
|
||||||
|
|
||||||
|
The DAB demodulator uses a sample rate of 2.048MHz.
|
||||||
|
|
||||||
|
<h2>Interface</h2>
|
||||||
|
|
||||||
|
![DAB Demodulator plugin GUI](../../../doc/img/DABDemod_plugin.png)
|
||||||
|
|
||||||
|
<h3>1: Frequency shift from center frequency of reception</h3>
|
||||||
|
|
||||||
|
Use the wheels to adjust the frequency shift in Hz from the center frequency of reception. Left click on a digit sets the cursor position at this digit. Right click on a digit sets all digits on the right to zero. This effectively floors value at the digit position. Wheels are moved with the mousewheel while pointing at the wheel or by selecting the wheel with the left mouse click and using the keyboard arrows. Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2.
|
||||||
|
|
||||||
|
<h3>2: Channel power</h3>
|
||||||
|
|
||||||
|
Average total power in dB relative to a +/- 1.0 amplitude signal received in the pass band.
|
||||||
|
|
||||||
|
<h3>3: Audio mute</h3>
|
||||||
|
|
||||||
|
Left click on this button to toggle audio mute for this channel.
|
||||||
|
|
||||||
|
If you right click on it it will open a dialog to select the audio output device. See [audio management documentation](../../../sdrgui/audio.md) for details.
|
||||||
|
|
||||||
|
<h3>4: RF level meter in dB</h3>
|
||||||
|
|
||||||
|
- top bar (green): average value
|
||||||
|
- bottom bar (blue green): instantaneous peak value
|
||||||
|
- tip vertical bar (bright green): peak hold value
|
||||||
|
|
||||||
|
<h3>5: Audio volume</h3>
|
||||||
|
|
||||||
|
This is the volume of the audio signal from 0.0 (mute) to 10.0 (maximum). It can be varied continuously in 0.1 steps using the dial button. A value of 5.0 corresponds to a gain of 0dB.
|
||||||
|
|
||||||
|
<h3>8: Channel</h3>
|
||||||
|
|
||||||
|
Displays a list of DAB Band III channels and frequencies. Selecting an item will set the Device center frequency accordingly.
|
||||||
|
If the center frequency is set manually, this box will be updated to reflect the corresponding channel, or left blank if there is not a channel that corresponds to the current centre frequency.
|
||||||
|
|
||||||
|
<h3>5: RF Bandwidth</h3>
|
||||||
|
|
||||||
|
This specifies the bandwidth of a filter that is applied to the input signal before decimation or interpolation to limit the received signal's bandwidth. This should typically be 1.537 MHz.
|
||||||
|
|
||||||
|
<h3>6: Find</h3>
|
||||||
|
|
||||||
|
Enter a regular expression used to filter the program table.
|
||||||
|
|
||||||
|
<h3>7: Clear programs</h3>
|
||||||
|
|
||||||
|
Clear all programs in the table.
|
||||||
|
|
||||||
|
<h3>Program Table</h3>
|
||||||
|
|
||||||
|
The program table shows programs that have been detected within a tuned ensemble. Double clicking on a program will cause
|
||||||
|
the demodulator to set the corresponding center frequency and then to play audio for the program.
|
||||||
|
|
||||||
|
<h3>Current Program</h3>
|
||||||
|
|
||||||
|
The current program area display information about the currently playing program, including:
|
||||||
|
|
||||||
|
* Program name.
|
||||||
|
* Ensemble name.
|
||||||
|
* Program type (E.g. News / Pop).
|
||||||
|
* Language.
|
||||||
|
* Audio (DAB or DAB+).
|
||||||
|
* Bitrate in kbps.
|
||||||
|
* Audio sample rate (in kSa/s). If this does not match the sample rate of the selected audio device, it will be resampled to match.
|
||||||
|
* Data broadcast with the program (E.g. song name).
|
||||||
|
|
||||||
|
<h3>Statistics</h3>
|
||||||
|
|
||||||
|
The statitics areas displays statistics generated by the demodulator that may give an indiciation of the quality of the received signal.
|
||||||
|
|
||||||
|
If you are hearing dropouts in audio, try adjusting your antenna in order to improve the reported SNR.
|
||||||
|
|
||||||
|
<h2>Attribution</h2>
|
||||||
|
|
||||||
|
The DAB demodulator used DAB library by Jvan Katwijk.
|
@ -25,6 +25,7 @@
|
|||||||
const QStringList DemodAnalyzerSettings::m_channelTypes = {
|
const QStringList DemodAnalyzerSettings::m_channelTypes = {
|
||||||
QStringLiteral("AMDemod"),
|
QStringLiteral("AMDemod"),
|
||||||
QStringLiteral("AMMod"),
|
QStringLiteral("AMMod"),
|
||||||
|
QStringLiteral("DABDemod"),
|
||||||
QStringLiteral("DSDDemod"),
|
QStringLiteral("DSDDemod"),
|
||||||
QStringLiteral("NFMDemod"),
|
QStringLiteral("NFMDemod"),
|
||||||
QStringLiteral("NFMMod"),
|
QStringLiteral("NFMMod"),
|
||||||
@ -39,6 +40,7 @@ const QStringList DemodAnalyzerSettings::m_channelTypes = {
|
|||||||
const QStringList DemodAnalyzerSettings::m_channelURIs = {
|
const QStringList DemodAnalyzerSettings::m_channelURIs = {
|
||||||
QStringLiteral("sdrangel.channel.amdemod"),
|
QStringLiteral("sdrangel.channel.amdemod"),
|
||||||
QStringLiteral("sdrangel.channeltx.modam"),
|
QStringLiteral("sdrangel.channeltx.modam"),
|
||||||
|
QStringLiteral("sdrangel.channel.dabdemod"),
|
||||||
QStringLiteral("sdrangel.channel.dsddemod"),
|
QStringLiteral("sdrangel.channel.dsddemod"),
|
||||||
QStringLiteral("sdrangel.channel.nfmdemod"),
|
QStringLiteral("sdrangel.channel.nfmdemod"),
|
||||||
QStringLiteral("sdrangel.channeltx.modnfm"),
|
QStringLiteral("sdrangel.channeltx.modnfm"),
|
||||||
|
@ -3871,6 +3871,11 @@ bool WebAPIRequestMapper::getChannelSettings(
|
|||||||
channelSettings->setDatvModSettings(new SWGSDRangel::SWGDATVModSettings());
|
channelSettings->setDatvModSettings(new SWGSDRangel::SWGDATVModSettings());
|
||||||
channelSettings->getDatvModSettings()->fromJsonObject(settingsJsonObject);
|
channelSettings->getDatvModSettings()->fromJsonObject(settingsJsonObject);
|
||||||
}
|
}
|
||||||
|
else if (channelSettingsKey == "DABDemodSettings")
|
||||||
|
{
|
||||||
|
channelSettings->setDabDemodSettings(new SWGSDRangel::SWGDABDemodSettings());
|
||||||
|
channelSettings->getDabDemodSettings()->fromJsonObject(settingsJsonObject);
|
||||||
|
}
|
||||||
else if (channelSettingsKey == "DSDDemodSettings")
|
else if (channelSettingsKey == "DSDDemodSettings")
|
||||||
{
|
{
|
||||||
channelSettings->setDsdDemodSettings(new SWGSDRangel::SWGDSDDemodSettings());
|
channelSettings->setDsdDemodSettings(new SWGSDRangel::SWGDSDDemodSettings());
|
||||||
@ -4595,6 +4600,7 @@ void WebAPIRequestMapper::resetChannelSettings(SWGSDRangel::SWGChannelSettings&
|
|||||||
channelSettings.setAtvModSettings(nullptr);
|
channelSettings.setAtvModSettings(nullptr);
|
||||||
channelSettings.setBfmDemodSettings(nullptr);
|
channelSettings.setBfmDemodSettings(nullptr);
|
||||||
channelSettings.setDatvModSettings(nullptr);
|
channelSettings.setDatvModSettings(nullptr);
|
||||||
|
channelSettings.setDabDemodSettings(nullptr);
|
||||||
channelSettings.setDsdDemodSettings(nullptr);
|
channelSettings.setDsdDemodSettings(nullptr);
|
||||||
channelSettings.setIeee802154ModSettings(nullptr);
|
channelSettings.setIeee802154ModSettings(nullptr);
|
||||||
channelSettings.setNfmDemodSettings(nullptr);
|
channelSettings.setNfmDemodSettings(nullptr);
|
||||||
|
@ -37,6 +37,7 @@ const QMap<QString, QString> WebAPIUtils::m_channelURIToSettingsKey = {
|
|||||||
{"sdrangel.channel.modchirpchat", "ChirpChatModSettings"},
|
{"sdrangel.channel.modchirpchat", "ChirpChatModSettings"},
|
||||||
{"sdrangel.channel.demodatv", "ATVDemodSettings"},
|
{"sdrangel.channel.demodatv", "ATVDemodSettings"},
|
||||||
{"sdrangel.channel.demoddatv", "DATVDemodSettings"},
|
{"sdrangel.channel.demoddatv", "DATVDemodSettings"},
|
||||||
|
{"sdrangel.channel.dabdemod", "DABDemodSettings"},
|
||||||
{"sdrangel.channel.dsddemod", "DSDDemodSettings"},
|
{"sdrangel.channel.dsddemod", "DSDDemodSettings"},
|
||||||
{"sdrangel.channel.filesink", "FileSinkSettings"},
|
{"sdrangel.channel.filesink", "FileSinkSettings"},
|
||||||
{"sdrangel.channeltx.filesource", "FileSourceSettings"},
|
{"sdrangel.channeltx.filesource", "FileSourceSettings"},
|
||||||
@ -132,6 +133,7 @@ const QMap<QString, QString> WebAPIUtils::m_channelTypeToSettingsKey = {
|
|||||||
{"ChirpChatMod", "ChirpChatModSettings"},
|
{"ChirpChatMod", "ChirpChatModSettings"},
|
||||||
{"DATVDemod", "DATVDemodSettings"},
|
{"DATVDemod", "DATVDemodSettings"},
|
||||||
{"DATVMod", "DATVModSettings"},
|
{"DATVMod", "DATVModSettings"},
|
||||||
|
{"DABDemod", "DABDemodSettings"},
|
||||||
{"DSDDemod", "DSDDemodSettings"},
|
{"DSDDemod", "DSDDemodSettings"},
|
||||||
{"FileSink", "FileSinkSettings"},
|
{"FileSink", "FileSinkSettings"},
|
||||||
{"FileSource", "FileSourceSettings"},
|
{"FileSource", "FileSourceSettings"},
|
||||||
|
@ -43,6 +43,8 @@ ChannelSettings:
|
|||||||
$ref: "http://swgserver:8081/api/swagger/include/DATVMod.yaml#/DATVModSettings"
|
$ref: "http://swgserver:8081/api/swagger/include/DATVMod.yaml#/DATVModSettings"
|
||||||
DATVDemodSettings:
|
DATVDemodSettings:
|
||||||
$ref: "http://swgserver:8081/api/swagger/include/DATVDemod.yaml#/DATVDemodSettings"
|
$ref: "http://swgserver:8081/api/swagger/include/DATVDemod.yaml#/DATVDemodSettings"
|
||||||
|
DABDemodSettings:
|
||||||
|
$ref: "http://swgserver:8081/api/swagger/include/DABDemod.yaml#/DABDemodSettings"
|
||||||
DSDDemodSettings:
|
DSDDemodSettings:
|
||||||
$ref: "http://swgserver:8081/api/swagger/include/DSDDemod.yaml#/DSDDemodSettings"
|
$ref: "http://swgserver:8081/api/swagger/include/DSDDemod.yaml#/DSDDemodSettings"
|
||||||
FileSinkSettings:
|
FileSinkSettings:
|
||||||
|
36
swagger/sdrangel/api/swagger/include/DABDemod.yaml
Normal file
36
swagger/sdrangel/api/swagger/include/DABDemod.yaml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
DABDemodSettings:
|
||||||
|
description: DABDemod
|
||||||
|
properties:
|
||||||
|
inputFrequencyOffset:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
rfBandwidth:
|
||||||
|
type: number
|
||||||
|
format: float
|
||||||
|
program:
|
||||||
|
type: string
|
||||||
|
volume:
|
||||||
|
type: number
|
||||||
|
format: float
|
||||||
|
audioMute:
|
||||||
|
type: integer
|
||||||
|
audioDeviceName:
|
||||||
|
type: string
|
||||||
|
rgbColor:
|
||||||
|
type: integer
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
streamIndex:
|
||||||
|
description: MIMO channel. Not relevant when connected to SI (single Rx).
|
||||||
|
type: integer
|
||||||
|
useReverseAPI:
|
||||||
|
description: Synchronize with reverse API (1 for yes, 0 for no)
|
||||||
|
type: integer
|
||||||
|
reverseAPIAddress:
|
||||||
|
type: string
|
||||||
|
reverseAPIPort:
|
||||||
|
type: integer
|
||||||
|
reverseAPIDeviceIndex:
|
||||||
|
type: integer
|
||||||
|
reverseAPIChannelIndex:
|
||||||
|
type: integer
|
@ -62,6 +62,8 @@ SWGChannelSettings::SWGChannelSettings() {
|
|||||||
m_datv_mod_settings_isSet = false;
|
m_datv_mod_settings_isSet = false;
|
||||||
datv_demod_settings = nullptr;
|
datv_demod_settings = nullptr;
|
||||||
m_datv_demod_settings_isSet = false;
|
m_datv_demod_settings_isSet = false;
|
||||||
|
dab_demod_settings = nullptr;
|
||||||
|
m_dab_demod_settings_isSet = false;
|
||||||
dsd_demod_settings = nullptr;
|
dsd_demod_settings = nullptr;
|
||||||
m_dsd_demod_settings_isSet = false;
|
m_dsd_demod_settings_isSet = false;
|
||||||
file_sink_settings = nullptr;
|
file_sink_settings = nullptr;
|
||||||
@ -154,6 +156,8 @@ SWGChannelSettings::init() {
|
|||||||
m_datv_mod_settings_isSet = false;
|
m_datv_mod_settings_isSet = false;
|
||||||
datv_demod_settings = new SWGDATVDemodSettings();
|
datv_demod_settings = new SWGDATVDemodSettings();
|
||||||
m_datv_demod_settings_isSet = false;
|
m_datv_demod_settings_isSet = false;
|
||||||
|
dab_demod_settings = new SWGDABDemodSettings();
|
||||||
|
m_dab_demod_settings_isSet = false;
|
||||||
dsd_demod_settings = new SWGDSDDemodSettings();
|
dsd_demod_settings = new SWGDSDDemodSettings();
|
||||||
m_dsd_demod_settings_isSet = false;
|
m_dsd_demod_settings_isSet = false;
|
||||||
file_sink_settings = new SWGFileSinkSettings();
|
file_sink_settings = new SWGFileSinkSettings();
|
||||||
@ -253,6 +257,9 @@ SWGChannelSettings::cleanup() {
|
|||||||
if(datv_demod_settings != nullptr) {
|
if(datv_demod_settings != nullptr) {
|
||||||
delete datv_demod_settings;
|
delete datv_demod_settings;
|
||||||
}
|
}
|
||||||
|
if(dab_demod_settings != nullptr) {
|
||||||
|
delete dab_demod_settings;
|
||||||
|
}
|
||||||
if(dsd_demod_settings != nullptr) {
|
if(dsd_demod_settings != nullptr) {
|
||||||
delete dsd_demod_settings;
|
delete dsd_demod_settings;
|
||||||
}
|
}
|
||||||
@ -375,6 +382,8 @@ SWGChannelSettings::fromJsonObject(QJsonObject &pJson) {
|
|||||||
|
|
||||||
::SWGSDRangel::setValue(&datv_demod_settings, pJson["DATVDemodSettings"], "SWGDATVDemodSettings", "SWGDATVDemodSettings");
|
::SWGSDRangel::setValue(&datv_demod_settings, pJson["DATVDemodSettings"], "SWGDATVDemodSettings", "SWGDATVDemodSettings");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&dab_demod_settings, pJson["DABDemodSettings"], "SWGDABDemodSettings", "SWGDABDemodSettings");
|
||||||
|
|
||||||
::SWGSDRangel::setValue(&dsd_demod_settings, pJson["DSDDemodSettings"], "SWGDSDDemodSettings", "SWGDSDDemodSettings");
|
::SWGSDRangel::setValue(&dsd_demod_settings, pJson["DSDDemodSettings"], "SWGDSDDemodSettings", "SWGDSDDemodSettings");
|
||||||
|
|
||||||
::SWGSDRangel::setValue(&file_sink_settings, pJson["FileSinkSettings"], "SWGFileSinkSettings", "SWGFileSinkSettings");
|
::SWGSDRangel::setValue(&file_sink_settings, pJson["FileSinkSettings"], "SWGFileSinkSettings", "SWGFileSinkSettings");
|
||||||
@ -492,6 +501,9 @@ SWGChannelSettings::asJsonObject() {
|
|||||||
if((datv_demod_settings != nullptr) && (datv_demod_settings->isSet())){
|
if((datv_demod_settings != nullptr) && (datv_demod_settings->isSet())){
|
||||||
toJsonValue(QString("DATVDemodSettings"), datv_demod_settings, obj, QString("SWGDATVDemodSettings"));
|
toJsonValue(QString("DATVDemodSettings"), datv_demod_settings, obj, QString("SWGDATVDemodSettings"));
|
||||||
}
|
}
|
||||||
|
if((dab_demod_settings != nullptr) && (dab_demod_settings->isSet())){
|
||||||
|
toJsonValue(QString("DABDemodSettings"), dab_demod_settings, obj, QString("SWGDABDemodSettings"));
|
||||||
|
}
|
||||||
if((dsd_demod_settings != nullptr) && (dsd_demod_settings->isSet())){
|
if((dsd_demod_settings != nullptr) && (dsd_demod_settings->isSet())){
|
||||||
toJsonValue(QString("DSDDemodSettings"), dsd_demod_settings, obj, QString("SWGDSDDemodSettings"));
|
toJsonValue(QString("DSDDemodSettings"), dsd_demod_settings, obj, QString("SWGDSDDemodSettings"));
|
||||||
}
|
}
|
||||||
@ -741,6 +753,16 @@ SWGChannelSettings::setDatvDemodSettings(SWGDATVDemodSettings* datv_demod_settin
|
|||||||
this->m_datv_demod_settings_isSet = true;
|
this->m_datv_demod_settings_isSet = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SWGDABDemodSettings*
|
||||||
|
SWGChannelSettings::getDabDemodSettings() {
|
||||||
|
return dab_demod_settings;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGChannelSettings::setDabDemodSettings(SWGDABDemodSettings* dab_demod_settings) {
|
||||||
|
this->dab_demod_settings = dab_demod_settings;
|
||||||
|
this->m_dab_demod_settings_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
SWGDSDDemodSettings*
|
SWGDSDDemodSettings*
|
||||||
SWGChannelSettings::getDsdDemodSettings() {
|
SWGChannelSettings::getDsdDemodSettings() {
|
||||||
return dsd_demod_settings;
|
return dsd_demod_settings;
|
||||||
@ -1047,6 +1069,9 @@ SWGChannelSettings::isSet(){
|
|||||||
if(datv_demod_settings && datv_demod_settings->isSet()){
|
if(datv_demod_settings && datv_demod_settings->isSet()){
|
||||||
isObjectUpdated = true; break;
|
isObjectUpdated = true; break;
|
||||||
}
|
}
|
||||||
|
if(dab_demod_settings && dab_demod_settings->isSet()){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
if(dsd_demod_settings && dsd_demod_settings->isSet()){
|
if(dsd_demod_settings && dsd_demod_settings->isSet()){
|
||||||
isObjectUpdated = true; break;
|
isObjectUpdated = true; break;
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "SWGChannelAnalyzerSettings.h"
|
#include "SWGChannelAnalyzerSettings.h"
|
||||||
#include "SWGChirpChatDemodSettings.h"
|
#include "SWGChirpChatDemodSettings.h"
|
||||||
#include "SWGChirpChatModSettings.h"
|
#include "SWGChirpChatModSettings.h"
|
||||||
|
#include "SWGDABDemodSettings.h"
|
||||||
#include "SWGDATVDemodSettings.h"
|
#include "SWGDATVDemodSettings.h"
|
||||||
#include "SWGDATVModSettings.h"
|
#include "SWGDATVModSettings.h"
|
||||||
#include "SWGDSDDemodSettings.h"
|
#include "SWGDSDDemodSettings.h"
|
||||||
@ -131,6 +132,9 @@ public:
|
|||||||
SWGDATVDemodSettings* getDatvDemodSettings();
|
SWGDATVDemodSettings* getDatvDemodSettings();
|
||||||
void setDatvDemodSettings(SWGDATVDemodSettings* datv_demod_settings);
|
void setDatvDemodSettings(SWGDATVDemodSettings* datv_demod_settings);
|
||||||
|
|
||||||
|
SWGDABDemodSettings* getDabDemodSettings();
|
||||||
|
void setDabDemodSettings(SWGDABDemodSettings* dab_demod_settings);
|
||||||
|
|
||||||
SWGDSDDemodSettings* getDsdDemodSettings();
|
SWGDSDDemodSettings* getDsdDemodSettings();
|
||||||
void setDsdDemodSettings(SWGDSDDemodSettings* dsd_demod_settings);
|
void setDsdDemodSettings(SWGDSDDemodSettings* dsd_demod_settings);
|
||||||
|
|
||||||
@ -261,6 +265,9 @@ private:
|
|||||||
SWGDATVDemodSettings* datv_demod_settings;
|
SWGDATVDemodSettings* datv_demod_settings;
|
||||||
bool m_datv_demod_settings_isSet;
|
bool m_datv_demod_settings_isSet;
|
||||||
|
|
||||||
|
SWGDABDemodSettings* dab_demod_settings;
|
||||||
|
bool m_dab_demod_settings_isSet;
|
||||||
|
|
||||||
SWGDSDDemodSettings* dsd_demod_settings;
|
SWGDSDDemodSettings* dsd_demod_settings;
|
||||||
bool m_dsd_demod_settings_isSet;
|
bool m_dsd_demod_settings_isSet;
|
||||||
|
|
||||||
|
415
swagger/sdrangel/code/qt5/client/SWGDABDemodSettings.cpp
Normal file
415
swagger/sdrangel/code/qt5/client/SWGDABDemodSettings.cpp
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
/**
|
||||||
|
* SDRangel
|
||||||
|
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
|
||||||
|
*
|
||||||
|
* OpenAPI spec version: 6.0.0
|
||||||
|
* Contact: f4exb06@gmail.com
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by the swagger code generator program.
|
||||||
|
* https://github.com/swagger-api/swagger-codegen.git
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "SWGDABDemodSettings.h"
|
||||||
|
|
||||||
|
#include "SWGHelpers.h"
|
||||||
|
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
namespace SWGSDRangel {
|
||||||
|
|
||||||
|
SWGDABDemodSettings::SWGDABDemodSettings(QString* json) {
|
||||||
|
init();
|
||||||
|
this->fromJson(*json);
|
||||||
|
}
|
||||||
|
|
||||||
|
SWGDABDemodSettings::SWGDABDemodSettings() {
|
||||||
|
input_frequency_offset = 0L;
|
||||||
|
m_input_frequency_offset_isSet = false;
|
||||||
|
rf_bandwidth = 0.0f;
|
||||||
|
m_rf_bandwidth_isSet = false;
|
||||||
|
program = nullptr;
|
||||||
|
m_program_isSet = false;
|
||||||
|
volume = 0.0f;
|
||||||
|
m_volume_isSet = false;
|
||||||
|
audio_mute = 0;
|
||||||
|
m_audio_mute_isSet = false;
|
||||||
|
audio_device_name = nullptr;
|
||||||
|
m_audio_device_name_isSet = false;
|
||||||
|
rgb_color = 0;
|
||||||
|
m_rgb_color_isSet = false;
|
||||||
|
title = nullptr;
|
||||||
|
m_title_isSet = false;
|
||||||
|
stream_index = 0;
|
||||||
|
m_stream_index_isSet = false;
|
||||||
|
use_reverse_api = 0;
|
||||||
|
m_use_reverse_api_isSet = false;
|
||||||
|
reverse_api_address = nullptr;
|
||||||
|
m_reverse_api_address_isSet = false;
|
||||||
|
reverse_api_port = 0;
|
||||||
|
m_reverse_api_port_isSet = false;
|
||||||
|
reverse_api_device_index = 0;
|
||||||
|
m_reverse_api_device_index_isSet = false;
|
||||||
|
reverse_api_channel_index = 0;
|
||||||
|
m_reverse_api_channel_index_isSet = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SWGDABDemodSettings::~SWGDABDemodSettings() {
|
||||||
|
this->cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::init() {
|
||||||
|
input_frequency_offset = 0L;
|
||||||
|
m_input_frequency_offset_isSet = false;
|
||||||
|
rf_bandwidth = 0.0f;
|
||||||
|
m_rf_bandwidth_isSet = false;
|
||||||
|
program = new QString("");
|
||||||
|
m_program_isSet = false;
|
||||||
|
volume = 0.0f;
|
||||||
|
m_volume_isSet = false;
|
||||||
|
audio_mute = 0;
|
||||||
|
m_audio_mute_isSet = false;
|
||||||
|
audio_device_name = new QString("");
|
||||||
|
m_audio_device_name_isSet = false;
|
||||||
|
rgb_color = 0;
|
||||||
|
m_rgb_color_isSet = false;
|
||||||
|
title = new QString("");
|
||||||
|
m_title_isSet = false;
|
||||||
|
stream_index = 0;
|
||||||
|
m_stream_index_isSet = false;
|
||||||
|
use_reverse_api = 0;
|
||||||
|
m_use_reverse_api_isSet = false;
|
||||||
|
reverse_api_address = new QString("");
|
||||||
|
m_reverse_api_address_isSet = false;
|
||||||
|
reverse_api_port = 0;
|
||||||
|
m_reverse_api_port_isSet = false;
|
||||||
|
reverse_api_device_index = 0;
|
||||||
|
m_reverse_api_device_index_isSet = false;
|
||||||
|
reverse_api_channel_index = 0;
|
||||||
|
m_reverse_api_channel_index_isSet = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::cleanup() {
|
||||||
|
|
||||||
|
|
||||||
|
if(program != nullptr) {
|
||||||
|
delete program;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(audio_device_name != nullptr) {
|
||||||
|
delete audio_device_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(title != nullptr) {
|
||||||
|
delete title;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(reverse_api_address != nullptr) {
|
||||||
|
delete reverse_api_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SWGDABDemodSettings*
|
||||||
|
SWGDABDemodSettings::fromJson(QString &json) {
|
||||||
|
QByteArray array (json.toStdString().c_str());
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(array);
|
||||||
|
QJsonObject jsonObject = doc.object();
|
||||||
|
this->fromJsonObject(jsonObject);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::fromJsonObject(QJsonObject &pJson) {
|
||||||
|
::SWGSDRangel::setValue(&input_frequency_offset, pJson["inputFrequencyOffset"], "qint64", "");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&rf_bandwidth, pJson["rfBandwidth"], "float", "");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&program, pJson["program"], "QString", "QString");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&volume, pJson["volume"], "float", "");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&audio_mute, pJson["audioMute"], "qint32", "");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&audio_device_name, pJson["audioDeviceName"], "QString", "QString");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", "");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&stream_index, pJson["streamIndex"], "qint32", "");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", "");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", "");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", "");
|
||||||
|
|
||||||
|
::SWGSDRangel::setValue(&reverse_api_channel_index, pJson["reverseAPIChannelIndex"], "qint32", "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
SWGDABDemodSettings::asJson ()
|
||||||
|
{
|
||||||
|
QJsonObject* obj = this->asJsonObject();
|
||||||
|
|
||||||
|
QJsonDocument doc(*obj);
|
||||||
|
QByteArray bytes = doc.toJson();
|
||||||
|
delete obj;
|
||||||
|
return QString(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject*
|
||||||
|
SWGDABDemodSettings::asJsonObject() {
|
||||||
|
QJsonObject* obj = new QJsonObject();
|
||||||
|
if(m_input_frequency_offset_isSet){
|
||||||
|
obj->insert("inputFrequencyOffset", QJsonValue(input_frequency_offset));
|
||||||
|
}
|
||||||
|
if(m_rf_bandwidth_isSet){
|
||||||
|
obj->insert("rfBandwidth", QJsonValue(rf_bandwidth));
|
||||||
|
}
|
||||||
|
if(program != nullptr && *program != QString("")){
|
||||||
|
toJsonValue(QString("program"), program, obj, QString("QString"));
|
||||||
|
}
|
||||||
|
if(m_volume_isSet){
|
||||||
|
obj->insert("volume", QJsonValue(volume));
|
||||||
|
}
|
||||||
|
if(m_audio_mute_isSet){
|
||||||
|
obj->insert("audioMute", QJsonValue(audio_mute));
|
||||||
|
}
|
||||||
|
if(audio_device_name != nullptr && *audio_device_name != QString("")){
|
||||||
|
toJsonValue(QString("audioDeviceName"), audio_device_name, obj, QString("QString"));
|
||||||
|
}
|
||||||
|
if(m_rgb_color_isSet){
|
||||||
|
obj->insert("rgbColor", QJsonValue(rgb_color));
|
||||||
|
}
|
||||||
|
if(title != nullptr && *title != QString("")){
|
||||||
|
toJsonValue(QString("title"), title, obj, QString("QString"));
|
||||||
|
}
|
||||||
|
if(m_stream_index_isSet){
|
||||||
|
obj->insert("streamIndex", QJsonValue(stream_index));
|
||||||
|
}
|
||||||
|
if(m_use_reverse_api_isSet){
|
||||||
|
obj->insert("useReverseAPI", QJsonValue(use_reverse_api));
|
||||||
|
}
|
||||||
|
if(reverse_api_address != nullptr && *reverse_api_address != QString("")){
|
||||||
|
toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString"));
|
||||||
|
}
|
||||||
|
if(m_reverse_api_port_isSet){
|
||||||
|
obj->insert("reverseAPIPort", QJsonValue(reverse_api_port));
|
||||||
|
}
|
||||||
|
if(m_reverse_api_device_index_isSet){
|
||||||
|
obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index));
|
||||||
|
}
|
||||||
|
if(m_reverse_api_channel_index_isSet){
|
||||||
|
obj->insert("reverseAPIChannelIndex", QJsonValue(reverse_api_channel_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64
|
||||||
|
SWGDABDemodSettings::getInputFrequencyOffset() {
|
||||||
|
return input_frequency_offset;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setInputFrequencyOffset(qint64 input_frequency_offset) {
|
||||||
|
this->input_frequency_offset = input_frequency_offset;
|
||||||
|
this->m_input_frequency_offset_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
SWGDABDemodSettings::getRfBandwidth() {
|
||||||
|
return rf_bandwidth;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setRfBandwidth(float rf_bandwidth) {
|
||||||
|
this->rf_bandwidth = rf_bandwidth;
|
||||||
|
this->m_rf_bandwidth_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString*
|
||||||
|
SWGDABDemodSettings::getProgram() {
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setProgram(QString* program) {
|
||||||
|
this->program = program;
|
||||||
|
this->m_program_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
SWGDABDemodSettings::getVolume() {
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setVolume(float volume) {
|
||||||
|
this->volume = volume;
|
||||||
|
this->m_volume_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32
|
||||||
|
SWGDABDemodSettings::getAudioMute() {
|
||||||
|
return audio_mute;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setAudioMute(qint32 audio_mute) {
|
||||||
|
this->audio_mute = audio_mute;
|
||||||
|
this->m_audio_mute_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString*
|
||||||
|
SWGDABDemodSettings::getAudioDeviceName() {
|
||||||
|
return audio_device_name;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setAudioDeviceName(QString* audio_device_name) {
|
||||||
|
this->audio_device_name = audio_device_name;
|
||||||
|
this->m_audio_device_name_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32
|
||||||
|
SWGDABDemodSettings::getRgbColor() {
|
||||||
|
return rgb_color;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setRgbColor(qint32 rgb_color) {
|
||||||
|
this->rgb_color = rgb_color;
|
||||||
|
this->m_rgb_color_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString*
|
||||||
|
SWGDABDemodSettings::getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setTitle(QString* title) {
|
||||||
|
this->title = title;
|
||||||
|
this->m_title_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32
|
||||||
|
SWGDABDemodSettings::getStreamIndex() {
|
||||||
|
return stream_index;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setStreamIndex(qint32 stream_index) {
|
||||||
|
this->stream_index = stream_index;
|
||||||
|
this->m_stream_index_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32
|
||||||
|
SWGDABDemodSettings::getUseReverseApi() {
|
||||||
|
return use_reverse_api;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setUseReverseApi(qint32 use_reverse_api) {
|
||||||
|
this->use_reverse_api = use_reverse_api;
|
||||||
|
this->m_use_reverse_api_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString*
|
||||||
|
SWGDABDemodSettings::getReverseApiAddress() {
|
||||||
|
return reverse_api_address;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setReverseApiAddress(QString* reverse_api_address) {
|
||||||
|
this->reverse_api_address = reverse_api_address;
|
||||||
|
this->m_reverse_api_address_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32
|
||||||
|
SWGDABDemodSettings::getReverseApiPort() {
|
||||||
|
return reverse_api_port;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setReverseApiPort(qint32 reverse_api_port) {
|
||||||
|
this->reverse_api_port = reverse_api_port;
|
||||||
|
this->m_reverse_api_port_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32
|
||||||
|
SWGDABDemodSettings::getReverseApiDeviceIndex() {
|
||||||
|
return reverse_api_device_index;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) {
|
||||||
|
this->reverse_api_device_index = reverse_api_device_index;
|
||||||
|
this->m_reverse_api_device_index_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32
|
||||||
|
SWGDABDemodSettings::getReverseApiChannelIndex() {
|
||||||
|
return reverse_api_channel_index;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
SWGDABDemodSettings::setReverseApiChannelIndex(qint32 reverse_api_channel_index) {
|
||||||
|
this->reverse_api_channel_index = reverse_api_channel_index;
|
||||||
|
this->m_reverse_api_channel_index_isSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SWGDABDemodSettings::isSet(){
|
||||||
|
bool isObjectUpdated = false;
|
||||||
|
do{
|
||||||
|
if(m_input_frequency_offset_isSet){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
if(m_rf_bandwidth_isSet){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
if(program && *program != QString("")){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
if(m_volume_isSet){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
if(m_audio_mute_isSet){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
if(audio_device_name && *audio_device_name != QString("")){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
if(m_rgb_color_isSet){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
if(title && *title != QString("")){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
if(m_stream_index_isSet){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
if(m_use_reverse_api_isSet){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
if(reverse_api_address && *reverse_api_address != QString("")){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
if(m_reverse_api_port_isSet){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
if(m_reverse_api_device_index_isSet){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
if(m_reverse_api_channel_index_isSet){
|
||||||
|
isObjectUpdated = true; break;
|
||||||
|
}
|
||||||
|
}while(false);
|
||||||
|
return isObjectUpdated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
137
swagger/sdrangel/code/qt5/client/SWGDABDemodSettings.h
Normal file
137
swagger/sdrangel/code/qt5/client/SWGDABDemodSettings.h
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/**
|
||||||
|
* SDRangel
|
||||||
|
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
|
||||||
|
*
|
||||||
|
* OpenAPI spec version: 6.0.0
|
||||||
|
* Contact: f4exb06@gmail.com
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by the swagger code generator program.
|
||||||
|
* https://github.com/swagger-api/swagger-codegen.git
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SWGDABDemodSettings.h
|
||||||
|
*
|
||||||
|
* DABDemod
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SWGDABDemodSettings_H_
|
||||||
|
#define SWGDABDemodSettings_H_
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "SWGObject.h"
|
||||||
|
#include "export.h"
|
||||||
|
|
||||||
|
namespace SWGSDRangel {
|
||||||
|
|
||||||
|
class SWG_API SWGDABDemodSettings: public SWGObject {
|
||||||
|
public:
|
||||||
|
SWGDABDemodSettings();
|
||||||
|
SWGDABDemodSettings(QString* json);
|
||||||
|
virtual ~SWGDABDemodSettings();
|
||||||
|
void init();
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
virtual QString asJson () override;
|
||||||
|
virtual QJsonObject* asJsonObject() override;
|
||||||
|
virtual void fromJsonObject(QJsonObject &json) override;
|
||||||
|
virtual SWGDABDemodSettings* fromJson(QString &jsonString) override;
|
||||||
|
|
||||||
|
qint64 getInputFrequencyOffset();
|
||||||
|
void setInputFrequencyOffset(qint64 input_frequency_offset);
|
||||||
|
|
||||||
|
float getRfBandwidth();
|
||||||
|
void setRfBandwidth(float rf_bandwidth);
|
||||||
|
|
||||||
|
QString* getProgram();
|
||||||
|
void setProgram(QString* program);
|
||||||
|
|
||||||
|
float getVolume();
|
||||||
|
void setVolume(float volume);
|
||||||
|
|
||||||
|
qint32 getAudioMute();
|
||||||
|
void setAudioMute(qint32 audio_mute);
|
||||||
|
|
||||||
|
QString* getAudioDeviceName();
|
||||||
|
void setAudioDeviceName(QString* audio_device_name);
|
||||||
|
|
||||||
|
qint32 getRgbColor();
|
||||||
|
void setRgbColor(qint32 rgb_color);
|
||||||
|
|
||||||
|
QString* getTitle();
|
||||||
|
void setTitle(QString* title);
|
||||||
|
|
||||||
|
qint32 getStreamIndex();
|
||||||
|
void setStreamIndex(qint32 stream_index);
|
||||||
|
|
||||||
|
qint32 getUseReverseApi();
|
||||||
|
void setUseReverseApi(qint32 use_reverse_api);
|
||||||
|
|
||||||
|
QString* getReverseApiAddress();
|
||||||
|
void setReverseApiAddress(QString* reverse_api_address);
|
||||||
|
|
||||||
|
qint32 getReverseApiPort();
|
||||||
|
void setReverseApiPort(qint32 reverse_api_port);
|
||||||
|
|
||||||
|
qint32 getReverseApiDeviceIndex();
|
||||||
|
void setReverseApiDeviceIndex(qint32 reverse_api_device_index);
|
||||||
|
|
||||||
|
qint32 getReverseApiChannelIndex();
|
||||||
|
void setReverseApiChannelIndex(qint32 reverse_api_channel_index);
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool isSet() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
qint64 input_frequency_offset;
|
||||||
|
bool m_input_frequency_offset_isSet;
|
||||||
|
|
||||||
|
float rf_bandwidth;
|
||||||
|
bool m_rf_bandwidth_isSet;
|
||||||
|
|
||||||
|
QString* program;
|
||||||
|
bool m_program_isSet;
|
||||||
|
|
||||||
|
float volume;
|
||||||
|
bool m_volume_isSet;
|
||||||
|
|
||||||
|
qint32 audio_mute;
|
||||||
|
bool m_audio_mute_isSet;
|
||||||
|
|
||||||
|
QString* audio_device_name;
|
||||||
|
bool m_audio_device_name_isSet;
|
||||||
|
|
||||||
|
qint32 rgb_color;
|
||||||
|
bool m_rgb_color_isSet;
|
||||||
|
|
||||||
|
QString* title;
|
||||||
|
bool m_title_isSet;
|
||||||
|
|
||||||
|
qint32 stream_index;
|
||||||
|
bool m_stream_index_isSet;
|
||||||
|
|
||||||
|
qint32 use_reverse_api;
|
||||||
|
bool m_use_reverse_api_isSet;
|
||||||
|
|
||||||
|
QString* reverse_api_address;
|
||||||
|
bool m_reverse_api_address_isSet;
|
||||||
|
|
||||||
|
qint32 reverse_api_port;
|
||||||
|
bool m_reverse_api_port_isSet;
|
||||||
|
|
||||||
|
qint32 reverse_api_device_index;
|
||||||
|
bool m_reverse_api_device_index_isSet;
|
||||||
|
|
||||||
|
qint32 reverse_api_channel_index;
|
||||||
|
bool m_reverse_api_channel_index_isSet;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SWGDABDemodSettings_H_ */
|
@ -72,6 +72,7 @@
|
|||||||
#include "SWGChirpChatModSettings.h"
|
#include "SWGChirpChatModSettings.h"
|
||||||
#include "SWGCommand.h"
|
#include "SWGCommand.h"
|
||||||
#include "SWGComplex.h"
|
#include "SWGComplex.h"
|
||||||
|
#include "SWGDABDemodSettings.h"
|
||||||
#include "SWGDATVDemodSettings.h"
|
#include "SWGDATVDemodSettings.h"
|
||||||
#include "SWGDATVModReport.h"
|
#include "SWGDATVModReport.h"
|
||||||
#include "SWGDATVModSettings.h"
|
#include "SWGDATVModSettings.h"
|
||||||
@ -436,6 +437,9 @@ namespace SWGSDRangel {
|
|||||||
if(QString("SWGComplex").compare(type) == 0) {
|
if(QString("SWGComplex").compare(type) == 0) {
|
||||||
return new SWGComplex();
|
return new SWGComplex();
|
||||||
}
|
}
|
||||||
|
if(QString("SWGDABDemodSettings").compare(type) == 0) {
|
||||||
|
return new SWGDABDemodSettings();
|
||||||
|
}
|
||||||
if(QString("SWGDATVDemodSettings").compare(type) == 0) {
|
if(QString("SWGDATVDemodSettings").compare(type) == 0) {
|
||||||
return new SWGDATVDemodSettings();
|
return new SWGDATVDemodSettings();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user