mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-02-03 09:44:01 -05:00
Merge branch 'master' of https://github.com/f4exb/sdrangel into osx
This commit is contained in:
commit
4f5118a250
2
.gitignore
vendored
2
.gitignore
vendored
@ -20,3 +20,5 @@ debian/files
|
|||||||
debian/sdrangel.debhelper.log
|
debian/sdrangel.debhelper.log
|
||||||
debian/debhelper-build-stamp
|
debian/debhelper-build-stamp
|
||||||
obj-x86_64-linux-gnu/*
|
obj-x86_64-linux-gnu/*
|
||||||
|
**/venv/
|
||||||
|
*.pyc
|
||||||
|
@ -31,6 +31,8 @@ option(SANITIZE_ADDRESS "Activate memory address sanitization" OFF)
|
|||||||
option(HOST_RPI "Compiling on RPi" OFF)
|
option(HOST_RPI "Compiling on RPi" OFF)
|
||||||
option(RX_SAMPLE_24BIT "Internal 24 bit Rx DSP" OFF)
|
option(RX_SAMPLE_24BIT "Internal 24 bit Rx DSP" OFF)
|
||||||
option(NO_DSP_SIMD "Do not use SIMD instructions for DSP even if available" OFF)
|
option(NO_DSP_SIMD "Do not use SIMD instructions for DSP even if available" OFF)
|
||||||
|
option(BUILD_SERVER "Build Server" ON)
|
||||||
|
option(BUILD_GUI "Build GUI" ON)
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
||||||
|
|
||||||
@ -211,7 +213,11 @@ else()
|
|||||||
message(STATUS "Compiling with SIMD instructions for DSP if available")
|
message(STATUS "Compiling with SIMD instructions for DSP if available")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wvla -Woverloaded-virtual -ffast-math -ftree-vectorize ${EXTRA_FLAGS}")
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wvla -Woverloaded-virtual -ffast-math -ftree-vectorize ${EXTRA_FLAGS}")
|
||||||
|
elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W3 -MP ${EXTRA_FLAGS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
if (BUILD_DEBIAN)
|
if (BUILD_DEBIAN)
|
||||||
@ -224,8 +230,12 @@ endif()
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
# base libraries
|
# base libraries
|
||||||
add_subdirectory(sdrbase)
|
add_subdirectory(sdrbase)
|
||||||
|
if (BUILD_GUI)
|
||||||
add_subdirectory(sdrgui)
|
add_subdirectory(sdrgui)
|
||||||
|
endif()
|
||||||
|
if (BUILD_SERVER)
|
||||||
add_subdirectory(sdrsrv)
|
add_subdirectory(sdrsrv)
|
||||||
|
endif()
|
||||||
add_subdirectory(sdrbench)
|
add_subdirectory(sdrbench)
|
||||||
add_subdirectory(httpserver)
|
add_subdirectory(httpserver)
|
||||||
add_subdirectory(logging)
|
add_subdirectory(logging)
|
||||||
@ -250,6 +260,7 @@ qt5_add_external_resources(sdrbase.rcc sdrbase/resources/res.qrc)
|
|||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# main GUI application
|
# main GUI application
|
||||||
|
if (BUILD_GUI)
|
||||||
|
|
||||||
set(sdrangel_SOURCES
|
set(sdrangel_SOURCES
|
||||||
app/main.cpp
|
app/main.cpp
|
||||||
@ -281,9 +292,11 @@ if(WIN32)
|
|||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
||||||
target_link_libraries(sdrangel Qt5::Widgets Qt5::Multimedia)
|
target_link_libraries(sdrangel Qt5::Widgets Qt5::Multimedia)
|
||||||
|
endif()
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# main server application
|
# main server application
|
||||||
|
if (BUILD_SERVER)
|
||||||
|
|
||||||
set(sdrangelsrv_SOURCES
|
set(sdrangelsrv_SOURCES
|
||||||
appsrv/main.cpp
|
appsrv/main.cpp
|
||||||
@ -305,6 +318,7 @@ target_link_libraries(sdrangelsrv
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(sdrangelsrv Qt5::Multimedia)
|
target_link_libraries(sdrangelsrv Qt5::Multimedia)
|
||||||
|
endif()
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# main benchmark application
|
# main benchmark application
|
||||||
@ -350,8 +364,12 @@ if (BUILD_DEBIAN)
|
|||||||
endif (BUILD_DEBIAN)
|
endif (BUILD_DEBIAN)
|
||||||
|
|
||||||
add_subdirectory(devices)
|
add_subdirectory(devices)
|
||||||
|
if (BUILD_GUI)
|
||||||
add_subdirectory(plugins)
|
add_subdirectory(plugins)
|
||||||
|
endif()
|
||||||
|
if (BUILD_SERVER)
|
||||||
add_subdirectory(pluginssrv)
|
add_subdirectory(pluginssrv)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(LIBUSB_FOUND AND UNIX)
|
if(LIBUSB_FOUND AND UNIX)
|
||||||
add_subdirectory(fcdhid)
|
add_subdirectory(fcdhid)
|
||||||
@ -361,15 +379,21 @@ endif(LIBUSB_FOUND AND UNIX)
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
#install targets
|
#install targets
|
||||||
|
if (BUILD_GUI)
|
||||||
install(TARGETS sdrangel DESTINATION bin)
|
install(TARGETS sdrangel DESTINATION bin)
|
||||||
|
endif()
|
||||||
|
if (BUILD_SERVER)
|
||||||
install(TARGETS sdrangelsrv DESTINATION bin)
|
install(TARGETS sdrangelsrv DESTINATION bin)
|
||||||
|
endif()
|
||||||
install(TARGETS sdrangelbench DESTINATION bin)
|
install(TARGETS sdrangelbench DESTINATION bin)
|
||||||
#install(TARGETS sdrbase DESTINATION lib)
|
#install(TARGETS sdrbase DESTINATION lib)
|
||||||
|
|
||||||
#install files and directories
|
#install files and directories
|
||||||
install(DIRECTORY udev-rules DESTINATION share/sdrangel)
|
install(DIRECTORY udev-rules DESTINATION share/sdrangel)
|
||||||
install(FILES udev-rules/install.sh DESTINATION share/sdrangel/udev-rules PERMISSIONS WORLD_EXECUTE)
|
install(FILES udev-rules/install.sh DESTINATION share/sdrangel/udev-rules PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sdrbase.rcc DESTINATION bin)
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sdrbase.rcc DESTINATION bin)
|
||||||
|
install(FILES desktop/sdrangel.desktop DESTINATION share/applications)
|
||||||
|
install(FILES desktop/sdrangel_icon.png DESTINATION share/pixmaps)
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *lo
|
|||||||
*/
|
*/
|
||||||
QCoreApplication::setOrganizationName("f4exb");
|
QCoreApplication::setOrganizationName("f4exb");
|
||||||
QCoreApplication::setApplicationName("SDRangel");
|
QCoreApplication::setApplicationName("SDRangel");
|
||||||
QCoreApplication::setApplicationVersion("4.3.1");
|
QCoreApplication::setApplicationVersion("4.3.2");
|
||||||
#if QT_VERSION >= 0x050600
|
#if QT_VERSION >= 0x050600
|
||||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // DPI support
|
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // DPI support
|
||||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); //HiDPI pixmaps
|
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); //HiDPI pixmaps
|
||||||
|
@ -57,7 +57,7 @@ static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *lo
|
|||||||
|
|
||||||
QCoreApplication::setOrganizationName("f4exb");
|
QCoreApplication::setOrganizationName("f4exb");
|
||||||
QCoreApplication::setApplicationName("SDRangelBench");
|
QCoreApplication::setApplicationName("SDRangelBench");
|
||||||
QCoreApplication::setApplicationVersion("4.3.1");
|
QCoreApplication::setApplicationVersion("4.3.2");
|
||||||
|
|
||||||
int catchSignals[] = {SIGQUIT, SIGINT, SIGTERM, SIGHUP};
|
int catchSignals[] = {SIGQUIT, SIGINT, SIGTERM, SIGHUP};
|
||||||
std::vector<int> vsig(catchSignals, catchSignals + sizeof(catchSignals) / sizeof(int));
|
std::vector<int> vsig(catchSignals, catchSignals + sizeof(catchSignals) / sizeof(int));
|
||||||
|
@ -56,7 +56,7 @@ static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *lo
|
|||||||
|
|
||||||
QCoreApplication::setOrganizationName("f4exb");
|
QCoreApplication::setOrganizationName("f4exb");
|
||||||
QCoreApplication::setApplicationName("SDRangelSrv");
|
QCoreApplication::setApplicationName("SDRangelSrv");
|
||||||
QCoreApplication::setApplicationVersion("4.3.1");
|
QCoreApplication::setApplicationVersion("4.3.2");
|
||||||
|
|
||||||
int catchSignals[] = {SIGQUIT, SIGINT, SIGTERM, SIGHUP};
|
int catchSignals[] = {SIGQUIT, SIGINT, SIGTERM, SIGHUP};
|
||||||
std::vector<int> vsig(catchSignals, catchSignals + sizeof(catchSignals) / sizeof(int));
|
std::vector<int> vsig(catchSignals, catchSignals + sizeof(catchSignals) / sizeof(int));
|
||||||
|
9
debian/changelog
vendored
9
debian/changelog
vendored
@ -1,3 +1,12 @@
|
|||||||
|
sdrangel (4.3.2-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Reverse API to forward device and channel changes to external application
|
||||||
|
* Funcube dongle: fixed segfault when stopping device
|
||||||
|
* Channel analzyer: fixed rational downsampler range
|
||||||
|
* SoapySDR support: fixed memory leaks
|
||||||
|
|
||||||
|
-- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Sun, 09 Dec 2018 21:14:18 +0100
|
||||||
|
|
||||||
sdrangel (4.3.1-1) unstable; urgency=medium
|
sdrangel (4.3.1-1) unstable; urgency=medium
|
||||||
|
|
||||||
* RTL-SDR: offset tuning support
|
* RTL-SDR: offset tuning support
|
||||||
|
@ -3,7 +3,7 @@ Name=SDRangel
|
|||||||
GenericName=SDR/Analyzer frontend
|
GenericName=SDR/Analyzer frontend
|
||||||
Comment=SDR/Analyzer frontend for Airspy, BladeRF, HackRF, RTL-SDR and FunCube
|
Comment=SDR/Analyzer frontend for Airspy, BladeRF, HackRF, RTL-SDR and FunCube
|
||||||
Exec=sdrangel
|
Exec=sdrangel
|
||||||
Icon=sdrangel_icon.xpm
|
Icon=sdrangel_icon.png
|
||||||
StartupNotify=true
|
StartupNotify=true
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
|
BIN
desktop/sdrangel_icon.png
Normal file
BIN
desktop/sdrangel_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
@ -40,7 +40,7 @@ else(BUILD_DEBIAN)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(SoapySDR)
|
find_package(SoapySDR)
|
||||||
if(LIBUSB_FOUND AND SOAPYSDR_FOUND)
|
if(SOAPYSDR_FOUND)
|
||||||
add_subdirectory(soapysdr)
|
add_subdirectory(soapysdr)
|
||||||
endif()
|
endif()
|
||||||
endif (BUILD_DEBIAN)
|
endif (BUILD_DEBIAN)
|
||||||
|
@ -35,6 +35,8 @@ add_library(bladerf1device SHARED
|
|||||||
${bladerf1device_SOURCES}
|
${bladerf1device_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(bladerf1device PROPERTIES DEFINE_SYMBOL "devices_EXPORTS")
|
||||||
|
|
||||||
if (BUILD_DEBIAN)
|
if (BUILD_DEBIAN)
|
||||||
target_link_libraries(bladerf1device
|
target_link_libraries(bladerf1device
|
||||||
bladerf
|
bladerf
|
||||||
|
@ -32,6 +32,8 @@ add_library(bladerf2device SHARED
|
|||||||
${bladerf2device_SOURCES}
|
${bladerf2device_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(bladerf2device PROPERTIES DEFINE_SYMBOL "devices_EXPORTS")
|
||||||
|
|
||||||
if (BUILD_DEBIAN)
|
if (BUILD_DEBIAN)
|
||||||
target_link_libraries(bladerf2device
|
target_link_libraries(bladerf2device
|
||||||
bladerf
|
bladerf
|
||||||
|
@ -34,6 +34,8 @@ add_library(hackrfdevice SHARED
|
|||||||
${hackrfdevice_SOURCES}
|
${hackrfdevice_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(hackrfdevice PROPERTIES DEFINE_SYMBOL "devices_EXPORTS")
|
||||||
|
|
||||||
if (BUILD_DEBIAN)
|
if (BUILD_DEBIAN)
|
||||||
target_link_libraries(hackrfdevice
|
target_link_libraries(hackrfdevice
|
||||||
hackrf
|
hackrf
|
||||||
|
@ -41,6 +41,8 @@ add_library(limesdrdevice SHARED
|
|||||||
${limesdrdevice_SOURCES}
|
${limesdrdevice_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(limesdrdevice PROPERTIES DEFINE_SYMBOL "devices_EXPORTS")
|
||||||
|
|
||||||
if (BUILD_DEBIAN)
|
if (BUILD_DEBIAN)
|
||||||
target_link_libraries(limesdrdevice
|
target_link_libraries(limesdrdevice
|
||||||
limesuite
|
limesuite
|
||||||
|
@ -33,6 +33,8 @@ add_library(perseusdevice SHARED
|
|||||||
${perseusdevice_SOURCES}
|
${perseusdevice_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(perseusdevice PROPERTIES DEFINE_SYMBOL "devices_EXPORTS")
|
||||||
|
|
||||||
if (BUILD_DEBIAN)
|
if (BUILD_DEBIAN)
|
||||||
target_link_libraries(perseusdevice
|
target_link_libraries(perseusdevice
|
||||||
perseus
|
perseus
|
||||||
|
@ -39,6 +39,8 @@ add_library(plutosdrdevice SHARED
|
|||||||
${plutosdrdevice_SOURCES}
|
${plutosdrdevice_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(plutosdrdevice PROPERTIES DEFINE_SYMBOL "devices_EXPORTS")
|
||||||
|
|
||||||
if (BUILD_DEBIAN)
|
if (BUILD_DEBIAN)
|
||||||
target_link_libraries(plutosdrdevice
|
target_link_libraries(plutosdrdevice
|
||||||
iio
|
iio
|
||||||
|
@ -38,6 +38,8 @@ add_library(soapysdrdevice SHARED
|
|||||||
${soapysdrdevice_SOURCES}
|
${soapysdrdevice_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(soapysdrdevice PROPERTIES DEFINE_SYMBOL "devices_EXPORTS")
|
||||||
|
|
||||||
if (BUILD_DEBIAN)
|
if (BUILD_DEBIAN)
|
||||||
target_link_libraries(soapysdrdevice
|
target_link_libraries(soapysdrdevice
|
||||||
SoapySDR
|
SoapySDR
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 21 KiB |
Binary file not shown.
BIN
doc/img/BasicDeviceSettings.png
Normal file
BIN
doc/img/BasicDeviceSettings.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
doc/img/BasicDeviceSettings.xcf
Normal file
BIN
doc/img/BasicDeviceSettings.xcf
Normal file
Binary file not shown.
@ -34,8 +34,8 @@ const char *fcd_traits<ProPlus>::displayedName = "FunCube Dongle Pro+";
|
|||||||
const char *fcd_traits<Pro>::pluginDisplayedName = "FunCube Pro Input";
|
const char *fcd_traits<Pro>::pluginDisplayedName = "FunCube Pro Input";
|
||||||
const char *fcd_traits<ProPlus>::pluginDisplayedName = "FunCube Pro+ Input";
|
const char *fcd_traits<ProPlus>::pluginDisplayedName = "FunCube Pro+ Input";
|
||||||
|
|
||||||
const char *fcd_traits<Pro>::pluginVersion = "4.3.0";
|
const char *fcd_traits<Pro>::pluginVersion = "4.3.2";
|
||||||
const char *fcd_traits<ProPlus>::pluginVersion = "4.3.0";
|
const char *fcd_traits<ProPlus>::pluginVersion = "4.3.2";
|
||||||
|
|
||||||
const int64_t fcd_traits<Pro>::loLowLimitFreq = 64000000L;
|
const int64_t fcd_traits<Pro>::loLowLimitFreq = 64000000L;
|
||||||
const int64_t fcd_traits<ProPlus>::loLowLimitFreq = 150000L;
|
const int64_t fcd_traits<ProPlus>::loLowLimitFreq = 150000L;
|
||||||
|
@ -48,6 +48,8 @@ add_library(httpserver SHARED
|
|||||||
${httpserver_HEADERS_MOC}
|
${httpserver_HEADERS_MOC}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(httpserver PROPERTIES DEFINE_SYMBOL "httpserver_EXPORTS")
|
||||||
|
|
||||||
target_link_libraries(httpserver
|
target_link_libraries(httpserver
|
||||||
${QT_LIBRARIES}
|
${QT_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
@ -34,6 +34,8 @@ add_library(logging SHARED
|
|||||||
${logging_HEADERS_MOC}
|
${logging_HEADERS_MOC}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(logging PROPERTIES DEFINE_SYMBOL "logging_EXPORTS")
|
||||||
|
|
||||||
target_link_libraries(logging
|
target_link_libraries(logging
|
||||||
${QT_LIBRARIES}
|
${QT_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
@ -23,6 +23,7 @@ set(chanalyzer_FORMS
|
|||||||
include_directories(
|
include_directories(
|
||||||
.
|
.
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
${Boost_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
#include(${QT_USE_FILE})
|
#include(${QT_USE_FILE})
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
#include "chanalyzer.h"
|
#include "chanalyzer.h"
|
||||||
|
|
||||||
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelAnalyzer, Message)
|
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelAnalyzer, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelAnalyzerOld, Message)
|
|
||||||
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelizer, Message)
|
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelizer, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgReportChannelSampleRateChanged, Message)
|
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgReportChannelSampleRateChanged, Message)
|
||||||
|
|
||||||
@ -75,20 +74,6 @@ ChannelAnalyzer::~ChannelAnalyzer()
|
|||||||
delete RRCFilter;
|
delete RRCFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelAnalyzer::configure(MessageQueue* messageQueue,
|
|
||||||
int channelSampleRate,
|
|
||||||
Real Bandwidth,
|
|
||||||
Real LowCutoff,
|
|
||||||
int spanLog2,
|
|
||||||
bool ssb,
|
|
||||||
bool pll,
|
|
||||||
bool fll,
|
|
||||||
unsigned int pllPskOrder)
|
|
||||||
{
|
|
||||||
Message* cmd = MsgConfigureChannelAnalyzerOld::create(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb, pll, fll, pllPskOrder);
|
|
||||||
messageQueue->push(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChannelAnalyzer::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly)
|
void ChannelAnalyzer::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly)
|
||||||
{
|
{
|
||||||
(void) positiveOnly;
|
(void) positiveOnly;
|
||||||
@ -234,14 +219,16 @@ bool ChannelAnalyzer::handleMessage(const Message& cmd)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_sampleSink != 0)
|
// Processed through GUI
|
||||||
{
|
// if (m_sampleSink != 0)
|
||||||
return m_sampleSink->handleMessage(cmd);
|
// {
|
||||||
}
|
// return m_sampleSink->handleMessage(cmd);
|
||||||
else
|
// }
|
||||||
{
|
// else
|
||||||
return false;
|
// {
|
||||||
}
|
// return false;
|
||||||
|
// }
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,71 +65,6 @@ public:
|
|||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgConfigureChannelAnalyzerOld : public Message {
|
|
||||||
MESSAGE_CLASS_DECLARATION
|
|
||||||
|
|
||||||
public:
|
|
||||||
int getChannelSampleRate() const { return m_channelSampleRate; }
|
|
||||||
Real getBandwidth() const { return m_Bandwidth; }
|
|
||||||
Real getLoCutoff() const { return m_LowCutoff; }
|
|
||||||
int getSpanLog2() const { return m_spanLog2; }
|
|
||||||
bool getSSB() const { return m_ssb; }
|
|
||||||
bool getPLL() const { return m_pll; }
|
|
||||||
bool getFLL() const { return m_fll; }
|
|
||||||
unsigned int getPLLPSKOrder() const { return m_pllPskOrder; }
|
|
||||||
|
|
||||||
static MsgConfigureChannelAnalyzerOld* create(
|
|
||||||
int channelSampleRate,
|
|
||||||
Real Bandwidth,
|
|
||||||
Real LowCutoff,
|
|
||||||
int spanLog2,
|
|
||||||
bool ssb,
|
|
||||||
bool pll,
|
|
||||||
bool fll,
|
|
||||||
unsigned int pllPskOrder)
|
|
||||||
{
|
|
||||||
return new MsgConfigureChannelAnalyzerOld(
|
|
||||||
channelSampleRate,
|
|
||||||
Bandwidth,
|
|
||||||
LowCutoff,
|
|
||||||
spanLog2,
|
|
||||||
ssb,
|
|
||||||
pll,
|
|
||||||
fll,
|
|
||||||
pllPskOrder);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int m_channelSampleRate;
|
|
||||||
Real m_Bandwidth;
|
|
||||||
Real m_LowCutoff;
|
|
||||||
int m_spanLog2;
|
|
||||||
bool m_ssb;
|
|
||||||
bool m_pll;
|
|
||||||
bool m_fll;
|
|
||||||
unsigned int m_pllPskOrder;
|
|
||||||
|
|
||||||
MsgConfigureChannelAnalyzerOld(
|
|
||||||
int channelSampleRate,
|
|
||||||
Real Bandwidth,
|
|
||||||
Real LowCutoff,
|
|
||||||
int spanLog2,
|
|
||||||
bool ssb,
|
|
||||||
bool pll,
|
|
||||||
bool fll,
|
|
||||||
unsigned int pllPskOrder) :
|
|
||||||
Message(),
|
|
||||||
m_channelSampleRate(channelSampleRate),
|
|
||||||
m_Bandwidth(Bandwidth),
|
|
||||||
m_LowCutoff(LowCutoff),
|
|
||||||
m_spanLog2(spanLog2),
|
|
||||||
m_ssb(ssb),
|
|
||||||
m_pll(pll),
|
|
||||||
m_fll(fll),
|
|
||||||
m_pllPskOrder(pllPskOrder)
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
|
|
||||||
class MsgConfigureChannelizer : public Message {
|
class MsgConfigureChannelizer : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
@ -175,15 +110,15 @@ public:
|
|||||||
virtual void destroy() { delete this; }
|
virtual void destroy() { delete this; }
|
||||||
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
|
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
|
||||||
|
|
||||||
void configure(MessageQueue* messageQueue,
|
// void configure(MessageQueue* messageQueue,
|
||||||
int channelSampleRate,
|
// int channelSampleRate,
|
||||||
Real Bandwidth,
|
// Real Bandwidth,
|
||||||
Real LowCutoff,
|
// Real LowCutoff,
|
||||||
int spanLog2,
|
// int spanLog2,
|
||||||
bool ssb,
|
// bool ssb,
|
||||||
bool pll,
|
// bool pll,
|
||||||
bool fll,
|
// bool fll,
|
||||||
unsigned int pllPskOrder);
|
// unsigned int pllPskOrder);
|
||||||
|
|
||||||
DownChannelizer *getChannelizer() { return m_channelizer; }
|
DownChannelizer *getChannelizer() { return m_channelizer; }
|
||||||
int getInputSampleRate() const { return m_inputSampleRate; }
|
int getInputSampleRate() const { return m_inputSampleRate; }
|
||||||
|
@ -24,7 +24,6 @@ INCLUDEPATH += ../../../sdrgui
|
|||||||
|
|
||||||
CONFIG(ANDROID):INCLUDEPATH += /opt/softs/boost_1_60_0
|
CONFIG(ANDROID):INCLUDEPATH += /opt/softs/boost_1_60_0
|
||||||
CONFIG(MINGW32):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
CONFIG(MINGW32):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
||||||
CONFIG(MINGW64):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
|
||||||
CONFIG(MSVC):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
CONFIG(MSVC):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
||||||
CONFIG(macx):INCLUDEPATH += "../../../../../boost_1_69_0"
|
CONFIG(macx):INCLUDEPATH += "../../../../../boost_1_69_0"
|
||||||
|
|
||||||
|
@ -14,25 +14,25 @@
|
|||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <device/devicesourceapi.h>
|
|
||||||
#include "device/deviceuiset.h"
|
|
||||||
#include <dsp/downchannelizer.h>
|
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
|
||||||
|
#include "device/devicesourceapi.h"
|
||||||
|
#include "device/deviceuiset.h"
|
||||||
|
#include "dsp/downchannelizer.h"
|
||||||
#include "dsp/threadedbasebandsamplesink.h"
|
#include "dsp/threadedbasebandsamplesink.h"
|
||||||
#include "ui_chanalyzergui.h"
|
|
||||||
#include "dsp/spectrumscopecombovis.h"
|
#include "dsp/spectrumscopecombovis.h"
|
||||||
#include "dsp/spectrumvis.h"
|
#include "dsp/spectrumvis.h"
|
||||||
|
#include "dsp/dspengine.h"
|
||||||
#include "gui/glspectrum.h"
|
#include "gui/glspectrum.h"
|
||||||
#include "gui/glscope.h"
|
#include "gui/glscope.h"
|
||||||
#include "gui/basicchannelsettingsdialog.h"
|
#include "gui/basicchannelsettingsdialog.h"
|
||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
#include "util/simpleserializer.h"
|
#include "util/simpleserializer.h"
|
||||||
#include "util/db.h"
|
#include "util/db.h"
|
||||||
#include "dsp/dspengine.h"
|
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
#include "ui_chanalyzergui.h"
|
||||||
#include "chanalyzer.h"
|
#include "chanalyzer.h"
|
||||||
#include "chanalyzergui.h"
|
#include "chanalyzergui.h"
|
||||||
|
|
||||||
@ -101,10 +101,12 @@ void ChannelAnalyzerGUI::displaySettings()
|
|||||||
setTitleColor(m_settings.m_rgbColor);
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
setWindowTitle(m_channelMarker.getTitle());
|
setWindowTitle(m_channelMarker.getTitle());
|
||||||
|
|
||||||
|
ui->channelSampleRate->setValueRange(7, 0.501*m_channelAnalyzer->getInputSampleRate(), m_channelAnalyzer->getInputSampleRate());
|
||||||
|
ui->channelSampleRate->setValue(m_settings.m_downSampleRate);
|
||||||
|
|
||||||
blockApplySettings(true);
|
blockApplySettings(true);
|
||||||
|
|
||||||
ui->useRationalDownsampler->setChecked(m_settings.m_downSample);
|
ui->useRationalDownsampler->setChecked(m_settings.m_downSample);
|
||||||
ui->channelSampleRate->setValue(m_settings.m_downSampleRate);
|
|
||||||
setNewFinalRate();
|
setNewFinalRate();
|
||||||
if (m_settings.m_ssb) {
|
if (m_settings.m_ssb) {
|
||||||
ui->BWLabel->setText("LP");
|
ui->BWLabel->setText("LP");
|
||||||
@ -186,9 +188,10 @@ bool ChannelAnalyzerGUI::handleMessage(const Message& message)
|
|||||||
{
|
{
|
||||||
if (ChannelAnalyzer::MsgReportChannelSampleRateChanged::match(message))
|
if (ChannelAnalyzer::MsgReportChannelSampleRateChanged::match(message))
|
||||||
{
|
{
|
||||||
qDebug() << "ChannelAnalyzerGUI::handleMessage: MsgReportChannelSampleRateChanged";
|
qDebug() << "ChannelAnalyzerGUI::handleMessage: MsgReportChannelSampleRateChanged:" << m_channelAnalyzer->getInputSampleRate();
|
||||||
ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate());
|
ui->channelSampleRate->setValueRange(7, 0.501*m_channelAnalyzer->getInputSampleRate(), m_channelAnalyzer->getInputSampleRate());
|
||||||
ui->channelSampleRate->setValue(m_settings.m_downSampleRate);
|
ui->channelSampleRate->setValue(m_settings.m_downSampleRate);
|
||||||
|
m_settings.m_downSampleRate = ui->channelSampleRate->getValueNew();
|
||||||
setNewFinalRate();
|
setNewFinalRate();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -401,7 +404,7 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceUISet *device
|
|||||||
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
|
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
|
||||||
|
|
||||||
ui->channelSampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
|
ui->channelSampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
|
||||||
ui->channelSampleRate->setValueRange(7, 2000U, 9999999U);
|
ui->channelSampleRate->setValueRange(7, 0.501*m_rate, m_rate);
|
||||||
|
|
||||||
ui->glSpectrum->setCenterFrequency(m_rate/2);
|
ui->glSpectrum->setCenterFrequency(m_rate/2);
|
||||||
ui->glSpectrum->setSampleRate(m_rate);
|
ui->glSpectrum->setSampleRate(m_rate);
|
||||||
@ -544,10 +547,6 @@ void ChannelAnalyzerGUI::applySettings(bool force)
|
|||||||
ChannelAnalyzer::MsgConfigureChannelizer::create(sampleRate, m_channelMarker.getCenterFrequency());
|
ChannelAnalyzer::MsgConfigureChannelizer::create(sampleRate, m_channelMarker.getCenterFrequency());
|
||||||
m_channelAnalyzer->getInputMessageQueue()->push(msgChannelizer);
|
m_channelAnalyzer->getInputMessageQueue()->push(msgChannelizer);
|
||||||
|
|
||||||
ChannelAnalyzer::MsgConfigureChannelizer *msg =
|
|
||||||
ChannelAnalyzer::MsgConfigureChannelizer::create(sampleRate, m_channelMarker.getCenterFrequency());
|
|
||||||
m_channelAnalyzer->getInputMessageQueue()->push(msg);
|
|
||||||
|
|
||||||
ChannelAnalyzer::MsgConfigureChannelAnalyzer* message =
|
ChannelAnalyzer::MsgConfigureChannelAnalyzer* message =
|
||||||
ChannelAnalyzer::MsgConfigureChannelAnalyzer::create( m_settings, force);
|
ChannelAnalyzer::MsgConfigureChannelAnalyzer::create( m_settings, force);
|
||||||
m_channelAnalyzer->getInputMessageQueue()->push(message);
|
m_channelAnalyzer->getInputMessageQueue()->push(message);
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
const PluginDescriptor ChannelAnalyzerPlugin::m_pluginDescriptor = {
|
const PluginDescriptor ChannelAnalyzerPlugin::m_pluginDescriptor = {
|
||||||
QString("Channel Analyzer"),
|
QString("Channel Analyzer"),
|
||||||
QString("4.3.0"),
|
QString("4.3.2"),
|
||||||
QString("(c) Edouard Griffiths, F4EXB"),
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
QString("https://github.com/f4exb/sdrangel"),
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -25,6 +25,10 @@
|
|||||||
#include <boost/crc.hpp>
|
#include <boost/crc.hpp>
|
||||||
#include <boost/cstdint.hpp>
|
#include <boost/cstdint.hpp>
|
||||||
|
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
#include "SWGChannelSettings.h"
|
#include "SWGChannelSettings.h"
|
||||||
|
|
||||||
#include "util/simpleserializer.h"
|
#include "util/simpleserializer.h"
|
||||||
@ -63,14 +67,21 @@ DaemonSink::DaemonSink(DeviceSourceAPI *deviceAPI) :
|
|||||||
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
||||||
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
||||||
m_deviceAPI->addChannelAPI(this);
|
m_deviceAPI->addChannelAPI(this);
|
||||||
|
|
||||||
|
m_networkManager = new QNetworkAccessManager();
|
||||||
|
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
DaemonSink::~DaemonSink()
|
DaemonSink::~DaemonSink()
|
||||||
{
|
{
|
||||||
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
|
delete m_networkManager;
|
||||||
m_dataBlockMutex.lock();
|
m_dataBlockMutex.lock();
|
||||||
|
|
||||||
if (m_dataBlock && !m_dataBlock->m_txControlBlock.m_complete) {
|
if (m_dataBlock && !m_dataBlock->m_txControlBlock.m_complete) {
|
||||||
delete m_dataBlock;
|
delete m_dataBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dataBlockMutex.unlock();
|
m_dataBlockMutex.unlock();
|
||||||
m_deviceAPI->removeChannelAPI(this);
|
m_deviceAPI->removeChannelAPI(this);
|
||||||
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
|
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
|
||||||
@ -325,23 +336,43 @@ void DaemonSink::applySettings(const DaemonSinkSettings& settings, bool force)
|
|||||||
<< " m_dataPort: " << settings.m_dataPort
|
<< " m_dataPort: " << settings.m_dataPort
|
||||||
<< " force: " << force;
|
<< " force: " << force;
|
||||||
|
|
||||||
if ((m_settings.m_nbFECBlocks != settings.m_nbFECBlocks) || force) {
|
QList<QString> reverseAPIKeys;
|
||||||
|
|
||||||
|
if ((m_settings.m_nbFECBlocks != settings.m_nbFECBlocks) || force)
|
||||||
|
{
|
||||||
|
reverseAPIKeys.append("nbFECBlocks");
|
||||||
setNbBlocksFEC(settings.m_nbFECBlocks);
|
setNbBlocksFEC(settings.m_nbFECBlocks);
|
||||||
setTxDelay(settings.m_txDelay, settings.m_nbFECBlocks);
|
setTxDelay(settings.m_txDelay, settings.m_nbFECBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_settings.m_txDelay != settings.m_txDelay) || force) {
|
if ((m_settings.m_txDelay != settings.m_txDelay) || force)
|
||||||
|
{
|
||||||
|
reverseAPIKeys.append("txDelay");
|
||||||
setTxDelay(settings.m_txDelay, settings.m_nbFECBlocks);
|
setTxDelay(settings.m_txDelay, settings.m_nbFECBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_settings.m_dataAddress != settings.m_dataAddress) || force) {
|
if ((m_settings.m_dataAddress != settings.m_dataAddress) || force)
|
||||||
|
{
|
||||||
|
reverseAPIKeys.append("dataAddress");
|
||||||
m_dataAddress = settings.m_dataAddress;
|
m_dataAddress = settings.m_dataAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_settings.m_dataPort != settings.m_dataPort) || force) {
|
if ((m_settings.m_dataPort != settings.m_dataPort) || force)
|
||||||
|
{
|
||||||
|
reverseAPIKeys.append("dataPort");
|
||||||
m_dataPort = settings.m_dataPort;
|
m_dataPort = settings.m_dataPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((settings.m_useReverseAPI) && (reverseAPIKeys.size() != 0))
|
||||||
|
{
|
||||||
|
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;
|
m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,7 +439,21 @@ int DaemonSink::webapiSettingsPutPatch(
|
|||||||
if (channelSettingsKeys.contains("title")) {
|
if (channelSettingsKeys.contains("title")) {
|
||||||
settings.m_title = *response.getDaemonSinkSettings()->getTitle();
|
settings.m_title = *response.getDaemonSinkSettings()->getTitle();
|
||||||
}
|
}
|
||||||
|
if (channelSettingsKeys.contains("useReverseAPI")) {
|
||||||
|
settings.m_useReverseAPI = response.getDaemonSinkSettings()->getUseReverseApi() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIAddress")) {
|
||||||
|
settings.m_reverseAPIAddress = *response.getDaemonSinkSettings()->getReverseApiAddress() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIPort")) {
|
||||||
|
settings.m_reverseAPIPort = response.getDaemonSinkSettings()->getReverseApiPort();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
|
||||||
|
settings.m_reverseAPIDeviceIndex = response.getDaemonSinkSettings()->getReverseApiDeviceIndex();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
|
||||||
|
settings.m_reverseAPIChannelIndex = response.getDaemonSinkSettings()->getReverseApiChannelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
MsgConfigureDaemonSink *msg = MsgConfigureDaemonSink::create(settings, force);
|
MsgConfigureDaemonSink *msg = MsgConfigureDaemonSink::create(settings, force);
|
||||||
m_inputMessageQueue.push(msg);
|
m_inputMessageQueue.push(msg);
|
||||||
@ -445,4 +490,82 @@ void DaemonSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& re
|
|||||||
response.getDaemonSinkSettings()->setTitle(new QString(settings.m_title));
|
response.getDaemonSinkSettings()->setTitle(new QString(settings.m_title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response.getDaemonSinkSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
|
||||||
|
|
||||||
|
if (response.getDaemonSinkSettings()->getReverseApiAddress()) {
|
||||||
|
*response.getDaemonSinkSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
|
||||||
|
} else {
|
||||||
|
response.getDaemonSinkSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
response.getDaemonSinkSettings()->setReverseApiPort(settings.m_reverseAPIPort);
|
||||||
|
response.getDaemonSinkSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
|
||||||
|
response.getDaemonSinkSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const DaemonSinkSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
|
||||||
|
swgChannelSettings->setTx(0);
|
||||||
|
swgChannelSettings->setChannelType(new QString("DaemonSink"));
|
||||||
|
swgChannelSettings->setDaemonSinkSettings(new SWGSDRangel::SWGDaemonSinkSettings());
|
||||||
|
SWGSDRangel::SWGDaemonSinkSettings *swgDaemonSinkSettings = swgChannelSettings->getDaemonSinkSettings();
|
||||||
|
|
||||||
|
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||||
|
|
||||||
|
if (channelSettingsKeys.contains("nbFECBlocks") || force) {
|
||||||
|
swgDaemonSinkSettings->setNbFecBlocks(settings.m_nbFECBlocks);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("txDelay") || force)
|
||||||
|
{
|
||||||
|
swgDaemonSinkSettings->setTxDelay(settings.m_txDelay);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("dataAddress") || force) {
|
||||||
|
swgDaemonSinkSettings->setDataAddress(new QString(settings.m_dataAddress));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("dataPort") || force) {
|
||||||
|
swgDaemonSinkSettings->setDataPort(settings.m_dataPort);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||||
|
swgDaemonSinkSettings->setRgbColor(settings.m_rgbColor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("title") || force) {
|
||||||
|
swgDaemonSinkSettings->setTitle(new QString(settings.m_title));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||||
|
|
||||||
|
delete swgChannelSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonSink::networkManagerFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
QNetworkReply::NetworkError replyError = reply->error();
|
||||||
|
|
||||||
|
if (replyError)
|
||||||
|
{
|
||||||
|
qWarning() << "DaemonSink::networkManagerFinished:"
|
||||||
|
<< " error(" << (int) replyError
|
||||||
|
<< "): " << replyError
|
||||||
|
<< ": " << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString answer = reply->readAll();
|
||||||
|
answer.chop(1); // remove last \n
|
||||||
|
qDebug("DaemonSink::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,15 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
#include "dsp/basebandsamplesink.h"
|
#include "dsp/basebandsamplesink.h"
|
||||||
#include "channel/channelsinkapi.h"
|
#include "channel/channelsinkapi.h"
|
||||||
#include "channel/sdrdaemondatablock.h"
|
#include "channel/sdrdaemondatablock.h"
|
||||||
#include "daemonsinksettings.h"
|
#include "daemonsinksettings.h"
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QNetworkReply;
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
class DownChannelizer;
|
class DownChannelizer;
|
||||||
@ -148,9 +151,15 @@ private:
|
|||||||
int m_txDelay;
|
int m_txDelay;
|
||||||
QString m_dataAddress;
|
QString m_dataAddress;
|
||||||
uint16_t m_dataPort;
|
uint16_t m_dataPort;
|
||||||
|
QNetworkAccessManager *m_networkManager;
|
||||||
|
QNetworkRequest m_networkRequest;
|
||||||
|
|
||||||
void applySettings(const DaemonSinkSettings& settings, bool force = false);
|
void applySettings(const DaemonSinkSettings& settings, bool force = false);
|
||||||
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const DaemonSinkSettings& settings);
|
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const DaemonSinkSettings& settings);
|
||||||
|
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const DaemonSinkSettings& settings, bool force);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void networkManagerFinished(QNetworkReply *reply);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* INCLUDE_DAEMONSINK_H_ */
|
#endif /* INCLUDE_DAEMONSINK_H_ */
|
||||||
|
@ -113,6 +113,7 @@ DaemonSinkGUI::DaemonSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas
|
|||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
|
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
|
||||||
|
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
|
||||||
|
|
||||||
m_daemonSink = (DaemonSink*) channelrx;
|
m_daemonSink = (DaemonSink*) channelrx;
|
||||||
m_daemonSink->setMessageQueueToGUI(getInputMessageQueue());
|
m_daemonSink->setMessageQueueToGUI(getInputMessageQueue());
|
||||||
@ -217,11 +218,22 @@ void DaemonSinkGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
|||||||
void DaemonSinkGUI::onMenuDialogCalled(const QPoint &p)
|
void DaemonSinkGUI::onMenuDialogCalled(const QPoint &p)
|
||||||
{
|
{
|
||||||
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
|
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.move(p);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
|
|
||||||
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
||||||
m_settings.m_title = m_channelMarker.getTitle();
|
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);
|
setWindowTitle(m_settings.m_title);
|
||||||
setTitleColor(m_settings.m_rgbColor);
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
#ifndef PLUGINS_CHANNELRX_DAEMONSINK_DAEMONSINKGUI_H_
|
#ifndef PLUGINS_CHANNELRX_DAEMONSINK_DAEMONSINKGUI_H_
|
||||||
#define PLUGINS_CHANNELRX_DAEMONSINK_DAEMONSINKGUI_H_
|
#define PLUGINS_CHANNELRX_DAEMONSINK_DAEMONSINKGUI_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
const PluginDescriptor DaemonSinkPlugin::m_pluginDescriptor = {
|
const PluginDescriptor DaemonSinkPlugin::m_pluginDescriptor = {
|
||||||
QString("Daemon channel Sink"),
|
QString("Daemon channel Sink"),
|
||||||
QString("4.1.0"),
|
QString("4.3.2"),
|
||||||
QString("(c) Edouard Griffiths, F4EXB"),
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
QString("https://github.com/f4exb/sdrangel"),
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -40,6 +40,11 @@ void DaemonSinkSettings::resetToDefaults()
|
|||||||
m_rgbColor = QColor(140, 4, 4).rgb();
|
m_rgbColor = QColor(140, 4, 4).rgb();
|
||||||
m_title = "Daemon sink";
|
m_title = "Daemon sink";
|
||||||
m_channelMarker = nullptr;
|
m_channelMarker = nullptr;
|
||||||
|
m_useReverseAPI = false;
|
||||||
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
m_reverseAPIDeviceIndex = 0;
|
||||||
|
m_reverseAPIChannelIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray DaemonSinkSettings::serialize() const
|
QByteArray DaemonSinkSettings::serialize() const
|
||||||
@ -51,6 +56,11 @@ QByteArray DaemonSinkSettings::serialize() const
|
|||||||
s.writeU32(4, m_dataPort);
|
s.writeU32(4, m_dataPort);
|
||||||
s.writeU32(5, m_rgbColor);
|
s.writeU32(5, m_rgbColor);
|
||||||
s.writeString(6, m_title);
|
s.writeString(6, m_title);
|
||||||
|
s.writeBool(7, m_useReverseAPI);
|
||||||
|
s.writeString(8, m_reverseAPIAddress);
|
||||||
|
s.writeU32(9, m_reverseAPIPort);
|
||||||
|
s.writeU32(10, m_reverseAPIDeviceIndex);
|
||||||
|
s.writeU32(11, m_reverseAPIChannelIndex);
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -90,6 +100,20 @@ bool DaemonSinkSettings::deserialize(const QByteArray& data)
|
|||||||
|
|
||||||
d.readU32(5, &m_rgbColor, QColor(0, 255, 255).rgb());
|
d.readU32(5, &m_rgbColor, QColor(0, 255, 255).rgb());
|
||||||
d.readString(6, &m_title, "Daemon sink");
|
d.readString(6, &m_title, "Daemon sink");
|
||||||
|
d.readBool(7, &m_useReverseAPI, false);
|
||||||
|
d.readString(8, &m_reverseAPIAddress, "127.0.0.1");
|
||||||
|
d.readU32(9, &tmp, 0);
|
||||||
|
|
||||||
|
if ((tmp > 1023) && (tmp < 65535)) {
|
||||||
|
m_reverseAPIPort = tmp;
|
||||||
|
} else {
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.readU32(10, &tmp, 0);
|
||||||
|
m_reverseAPIDeviceIndex = tmp > 99 ? 99 : tmp;
|
||||||
|
d.readU32(11, &tmp, 0);
|
||||||
|
m_reverseAPIChannelIndex = tmp > 99 ? 99 : tmp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,11 @@ struct DaemonSinkSettings
|
|||||||
uint16_t m_dataPort;
|
uint16_t m_dataPort;
|
||||||
quint32 m_rgbColor;
|
quint32 m_rgbColor;
|
||||||
QString m_title;
|
QString m_title;
|
||||||
|
bool m_useReverseAPI;
|
||||||
|
QString m_reverseAPIAddress;
|
||||||
|
uint16_t m_reverseAPIPort;
|
||||||
|
uint16_t m_reverseAPIDeviceIndex;
|
||||||
|
uint16_t m_reverseAPIChannelIndex;
|
||||||
|
|
||||||
Serializable *m_channelMarker;
|
Serializable *m_channelMarker;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (C) 2015 Edouard Griffiths, F4EXB. //
|
// Copyright (C) 2015-2018 Edouard Griffiths, F4EXB. //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// 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 //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
@ -18,6 +18,9 @@
|
|||||||
|
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <complex.h>
|
#include <complex.h>
|
||||||
@ -85,10 +88,15 @@ AMDemod::AMDemod(DeviceSourceAPI *deviceAPI) :
|
|||||||
m_pllFilt.create(101, m_audioSampleRate, 200.0);
|
m_pllFilt.create(101, m_audioSampleRate, 200.0);
|
||||||
m_pll.computeCoefficients(0.05, 0.707, 1000);
|
m_pll.computeCoefficients(0.05, 0.707, 1000);
|
||||||
m_syncAMBuffIndex = 0;
|
m_syncAMBuffIndex = 0;
|
||||||
|
|
||||||
|
m_networkManager = new QNetworkAccessManager();
|
||||||
|
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
AMDemod::~AMDemod()
|
AMDemod::~AMDemod()
|
||||||
{
|
{
|
||||||
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
|
delete m_networkManager;
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo);
|
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo);
|
||||||
m_deviceAPI->removeChannelAPI(this);
|
m_deviceAPI->removeChannelAPI(this);
|
||||||
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
|
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
|
||||||
@ -427,8 +435,15 @@ void AMDemod::applySettings(const AMDemodSettings& settings, bool force)
|
|||||||
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
||||||
<< " m_pll: " << settings.m_pll
|
<< " m_pll: " << settings.m_pll
|
||||||
<< " m_syncAMOperation: " << (int) settings.m_syncAMOperation
|
<< " m_syncAMOperation: " << (int) settings.m_syncAMOperation
|
||||||
|
<< " m_useReverseAPI: " << settings.m_useReverseAPI
|
||||||
|
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
|
||||||
|
<< " m_reverseAPIAddress: " << settings.m_reverseAPIPort
|
||||||
|
<< " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex
|
||||||
|
<< " m_reverseAPIChannelIndex: " << settings.m_reverseAPIChannelIndex
|
||||||
<< " force: " << force;
|
<< " force: " << force;
|
||||||
|
|
||||||
|
QList<QString> reverseAPIKeys;
|
||||||
|
|
||||||
if((m_settings.m_rfBandwidth != settings.m_rfBandwidth) ||
|
if((m_settings.m_rfBandwidth != settings.m_rfBandwidth) ||
|
||||||
(m_settings.m_bandpassEnable != settings.m_bandpassEnable) || force)
|
(m_settings.m_bandpassEnable != settings.m_bandpassEnable) || force)
|
||||||
{
|
{
|
||||||
@ -439,11 +454,19 @@ void AMDemod::applySettings(const AMDemodSettings& settings, bool force)
|
|||||||
m_bandpass.create(301, m_audioSampleRate, 300.0, settings.m_rfBandwidth / 2.0f);
|
m_bandpass.create(301, m_audioSampleRate, 300.0, settings.m_rfBandwidth / 2.0f);
|
||||||
DSBFilter->create_dsb_filter((2.0f * settings.m_rfBandwidth) / (float) m_audioSampleRate);
|
DSBFilter->create_dsb_filter((2.0f * settings.m_rfBandwidth) / (float) m_audioSampleRate);
|
||||||
m_settingsMutex.unlock();
|
m_settingsMutex.unlock();
|
||||||
|
|
||||||
|
if ((m_settings.m_rfBandwidth != settings.m_rfBandwidth) || force) {
|
||||||
|
reverseAPIKeys.append("rfBandwidth");
|
||||||
|
}
|
||||||
|
if ((m_settings.m_bandpassEnable != settings.m_bandpassEnable) || force) {
|
||||||
|
reverseAPIKeys.append("bandpassEnable");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_settings.m_squelch != settings.m_squelch) || force)
|
if ((m_settings.m_squelch != settings.m_squelch) || force)
|
||||||
{
|
{
|
||||||
m_squelchLevel = CalcDb::powerFromdB(settings.m_squelch);
|
m_squelchLevel = CalcDb::powerFromdB(settings.m_squelch);
|
||||||
|
reverseAPIKeys.append("squelch");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
|
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
|
||||||
@ -457,6 +480,8 @@ void AMDemod::applySettings(const AMDemodSettings& settings, bool force)
|
|||||||
if (m_audioSampleRate != audioSampleRate) {
|
if (m_audioSampleRate != audioSampleRate) {
|
||||||
applyAudioSampleRate(audioSampleRate);
|
applyAudioSampleRate(audioSampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reverseAPIKeys.append("audioDeviceName");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_settings.m_pll != settings.m_pll) || force)
|
if ((m_settings.m_pll != settings.m_pll) || force)
|
||||||
@ -470,10 +495,38 @@ void AMDemod::applySettings(const AMDemodSettings& settings, bool force)
|
|||||||
{
|
{
|
||||||
m_volumeAGC.resizeNew(m_audioSampleRate/10, 0.003);
|
m_volumeAGC.resizeNew(m_audioSampleRate/10, 0.003);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reverseAPIKeys.append("pll");
|
||||||
|
reverseAPIKeys.append("syncAMOperation");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_settings.m_syncAMOperation != settings.m_syncAMOperation) || force) {
|
if ((m_settings.m_syncAMOperation != settings.m_syncAMOperation) || force)
|
||||||
|
{
|
||||||
m_syncAMBuffIndex = 0;
|
m_syncAMBuffIndex = 0;
|
||||||
|
reverseAPIKeys.append("pll");
|
||||||
|
reverseAPIKeys.append("syncAMOperation");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_settings.m_inputFrequencyOffset != settings.m_inputFrequencyOffset) || force) {
|
||||||
|
reverseAPIKeys.append("inputFrequencyOffset");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_settings.m_audioMute != settings.m_audioMute) || force) {
|
||||||
|
reverseAPIKeys.append("audioMute");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_settings.m_volume != settings.m_volume) || force) {
|
||||||
|
reverseAPIKeys.append("volume");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
m_settings = settings;
|
||||||
@ -560,7 +613,23 @@ int AMDemod::webapiSettingsPutPatch(
|
|||||||
qint32 syncAMOperationCode = response.getAmDemodSettings()->getSyncAmOperation();
|
qint32 syncAMOperationCode = response.getAmDemodSettings()->getSyncAmOperation();
|
||||||
settings.m_syncAMOperation = syncAMOperationCode < 0 ?
|
settings.m_syncAMOperation = syncAMOperationCode < 0 ?
|
||||||
AMDemodSettings::SyncAMDSB : syncAMOperationCode > 2 ?
|
AMDemodSettings::SyncAMDSB : syncAMOperationCode > 2 ?
|
||||||
AMDemodSettings::SyncAMDSB : (AMDemodSettings::SyncAMOperation) syncAMOperationCode;
|
AMDemodSettings::SyncAMLSB : (AMDemodSettings::SyncAMOperation) syncAMOperationCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelSettingsKeys.contains("useReverseAPI")) {
|
||||||
|
settings.m_useReverseAPI = response.getAmDemodSettings()->getUseReverseApi() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIAddress")) {
|
||||||
|
settings.m_reverseAPIAddress = *response.getAmDemodSettings()->getReverseApiAddress() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIPort")) {
|
||||||
|
settings.m_reverseAPIPort = response.getAmDemodSettings()->getReverseApiPort();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
|
||||||
|
settings.m_reverseAPIDeviceIndex = response.getAmDemodSettings()->getReverseApiDeviceIndex();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
|
||||||
|
settings.m_reverseAPIChannelIndex = response.getAmDemodSettings()->getReverseApiChannelIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frequencyOffsetChanged)
|
if (frequencyOffsetChanged)
|
||||||
@ -620,6 +689,17 @@ void AMDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& respo
|
|||||||
|
|
||||||
response.getAmDemodSettings()->setPll(settings.m_pll ? 1 : 0);
|
response.getAmDemodSettings()->setPll(settings.m_pll ? 1 : 0);
|
||||||
response.getAmDemodSettings()->setSyncAmOperation((int) m_settings.m_syncAMOperation);
|
response.getAmDemodSettings()->setSyncAmOperation((int) m_settings.m_syncAMOperation);
|
||||||
|
response.getAmDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
|
||||||
|
|
||||||
|
if (response.getAmDemodSettings()->getReverseApiAddress()) {
|
||||||
|
*response.getAmDemodSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
|
||||||
|
} else {
|
||||||
|
response.getAmDemodSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
response.getAmDemodSettings()->setReverseApiPort(settings.m_reverseAPIPort);
|
||||||
|
response.getAmDemodSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
|
||||||
|
response.getAmDemodSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
void AMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
||||||
@ -634,3 +714,83 @@ void AMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
|||||||
response.getAmDemodReport()->setChannelSampleRate(m_inputSampleRate);
|
response.getAmDemodReport()->setChannelSampleRate(m_inputSampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const AMDemodSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
|
||||||
|
swgChannelSettings->setTx(0);
|
||||||
|
swgChannelSettings->setChannelType(new QString("AMDemod"));
|
||||||
|
swgChannelSettings->setAmDemodSettings(new SWGSDRangel::SWGAMDemodSettings());
|
||||||
|
SWGSDRangel::SWGAMDemodSettings *swgAMDemodSettings = swgChannelSettings->getAmDemodSettings();
|
||||||
|
|
||||||
|
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||||
|
|
||||||
|
if (channelSettingsKeys.contains("audioMute") || force) {
|
||||||
|
swgAMDemodSettings->setAudioMute(settings.m_audioMute ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
|
||||||
|
swgAMDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rfBandwidth") || force) {
|
||||||
|
swgAMDemodSettings->setRfBandwidth(settings.m_rfBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||||
|
swgAMDemodSettings->setRgbColor(settings.m_rgbColor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("squelch") || force) {
|
||||||
|
swgAMDemodSettings->setSquelch(settings.m_squelch);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("title") || force) {
|
||||||
|
swgAMDemodSettings->setTitle(new QString(settings.m_title));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("volume") || force) {
|
||||||
|
swgAMDemodSettings->setVolume(settings.m_volume);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("bandpassEnable") || force) {
|
||||||
|
swgAMDemodSettings->setBandpassEnable(settings.m_bandpassEnable ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioDeviceName") || force) {
|
||||||
|
swgAMDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("pll") || force) {
|
||||||
|
swgAMDemodSettings->setPll(settings.m_pll);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("syncAMOperation") || force) {
|
||||||
|
swgAMDemodSettings->setSyncAmOperation((int) settings.m_syncAMOperation);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||||
|
|
||||||
|
delete swgChannelSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AMDemod::networkManagerFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
QNetworkReply::NetworkError replyError = reply->error();
|
||||||
|
|
||||||
|
if (replyError)
|
||||||
|
{
|
||||||
|
qWarning() << "AMDemod::networkManagerFinished:"
|
||||||
|
<< " error(" << (int) replyError
|
||||||
|
<< "): " << replyError
|
||||||
|
<< ": " << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString answer = reply->readAll();
|
||||||
|
answer.chop(1); // remove last \n
|
||||||
|
qDebug("AMDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (C) 2015 Edouard Griffiths, F4EXB. //
|
// Copyright (C) 2015-2018 Edouard Griffiths, F4EXB. //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// 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 //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
@ -17,9 +17,11 @@
|
|||||||
#ifndef INCLUDE_AMDEMOD_H
|
#ifndef INCLUDE_AMDEMOD_H
|
||||||
#define INCLUDE_AMDEMOD_H
|
#define INCLUDE_AMDEMOD_H
|
||||||
|
|
||||||
#include <QMutex>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QMutex>
|
||||||
|
|
||||||
#include "dsp/basebandsamplesink.h"
|
#include "dsp/basebandsamplesink.h"
|
||||||
#include "channel/channelsinkapi.h"
|
#include "channel/channelsinkapi.h"
|
||||||
#include "dsp/nco.h"
|
#include "dsp/nco.h"
|
||||||
@ -35,6 +37,8 @@
|
|||||||
|
|
||||||
#include "amdemodsettings.h"
|
#include "amdemodsettings.h"
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QNetworkReply;
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
class DownChannelizer;
|
class DownChannelizer;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
@ -204,6 +208,9 @@ private:
|
|||||||
|
|
||||||
static const int m_udpBlockSize;
|
static const int m_udpBlockSize;
|
||||||
|
|
||||||
|
QNetworkAccessManager *m_networkManager;
|
||||||
|
QNetworkRequest m_networkRequest;
|
||||||
|
|
||||||
QMutex m_settingsMutex;
|
QMutex m_settingsMutex;
|
||||||
|
|
||||||
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force = false);
|
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force = false);
|
||||||
@ -211,8 +218,13 @@ private:
|
|||||||
void applyAudioSampleRate(int sampleRate);
|
void applyAudioSampleRate(int sampleRate);
|
||||||
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const AMDemodSettings& settings);
|
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const AMDemodSettings& settings);
|
||||||
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
||||||
|
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const AMDemodSettings& settings, bool force);
|
||||||
|
|
||||||
void processOneSample(Complex &ci);
|
void processOneSample(Complex &ci);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void networkManagerFinished(QNetworkReply *reply);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_AMDEMOD_H
|
#endif // INCLUDE_AMDEMOD_H
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include "amdemodgui.h"
|
#include "amdemodgui.h"
|
||||||
#include "amdemodssbdialog.h"
|
#include "amdemodssbdialog.h"
|
||||||
@ -94,7 +95,6 @@ bool AMDemodGUI::deserialize(const QByteArray& data)
|
|||||||
|
|
||||||
bool AMDemodGUI::handleMessage(const Message& message)
|
bool AMDemodGUI::handleMessage(const Message& message)
|
||||||
{
|
{
|
||||||
(void) message;
|
|
||||||
if (AMDemod::MsgConfigureAMDemod::match(message))
|
if (AMDemod::MsgConfigureAMDemod::match(message))
|
||||||
{
|
{
|
||||||
qDebug("AMDemodGUI::handleMessage: AMDemod::MsgConfigureAMDemod");
|
qDebug("AMDemodGUI::handleMessage: AMDemod::MsgConfigureAMDemod");
|
||||||
@ -206,12 +206,22 @@ void AMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
|||||||
void AMDemodGUI::onMenuDialogCalled(const QPoint &p)
|
void AMDemodGUI::onMenuDialogCalled(const QPoint &p)
|
||||||
{
|
{
|
||||||
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
|
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.move(p);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
|
|
||||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
||||||
m_settings.m_title = m_channelMarker.getTitle();
|
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);
|
setWindowTitle(m_settings.m_title);
|
||||||
setTitleColor(m_settings.m_rgbColor);
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
@ -241,10 +251,10 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS
|
|||||||
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
|
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
|
||||||
|
|
||||||
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
||||||
connect(audioMuteRightClickEnabler, SIGNAL(rightClick()), this, SLOT(audioSelect()));
|
connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect()));
|
||||||
|
|
||||||
CRightClickEnabler *samSidebandRightClickEnabler = new CRightClickEnabler(ui->ssb);
|
CRightClickEnabler *samSidebandRightClickEnabler = new CRightClickEnabler(ui->ssb);
|
||||||
connect(samSidebandRightClickEnabler, SIGNAL(rightClick()), this, SLOT(samSSBSelect()));
|
connect(samSidebandRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(samSSBSelect()));
|
||||||
|
|
||||||
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
||||||
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||||
@ -335,17 +345,32 @@ void AMDemodGUI::displaySettings()
|
|||||||
ui->bandpassEnable->setChecked(m_settings.m_bandpassEnable);
|
ui->bandpassEnable->setChecked(m_settings.m_bandpassEnable);
|
||||||
ui->pll->setChecked(m_settings.m_pll);
|
ui->pll->setChecked(m_settings.m_pll);
|
||||||
|
|
||||||
if (m_settings.m_pll) {
|
qDebug() << "AMDemodGUI::displaySettings:"
|
||||||
if (m_settings.m_syncAMOperation == AMDemodSettings::SyncAMLSB) {
|
<< " m_pll: " << m_settings.m_pll
|
||||||
|
<< " m_syncAMOperation: " << m_settings.m_syncAMOperation;
|
||||||
|
|
||||||
|
if (m_settings.m_pll)
|
||||||
|
{
|
||||||
|
if (m_settings.m_syncAMOperation == AMDemodSettings::SyncAMLSB)
|
||||||
|
{
|
||||||
m_samUSB = false;
|
m_samUSB = false;
|
||||||
|
ui->ssb->setChecked(true);
|
||||||
ui->ssb->setIcon(m_iconDSBLSB);
|
ui->ssb->setIcon(m_iconDSBLSB);
|
||||||
} else {
|
}
|
||||||
|
else if (m_settings.m_syncAMOperation == AMDemodSettings::SyncAMUSB)
|
||||||
|
{
|
||||||
m_samUSB = true;
|
m_samUSB = true;
|
||||||
|
ui->ssb->setChecked(true);
|
||||||
ui->ssb->setIcon(m_iconDSBUSB);
|
ui->ssb->setIcon(m_iconDSBUSB);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->ssb->setChecked(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
ui->ssb->setChecked(false);
|
||||||
ui->ssb->setIcon(m_iconDSBUSB);
|
ui->ssb->setIcon(m_iconDSBUSB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
const PluginDescriptor AMDemodPlugin::m_pluginDescriptor = {
|
const PluginDescriptor AMDemodPlugin::m_pluginDescriptor = {
|
||||||
QString("AM Demodulator"),
|
QString("AM Demodulator"),
|
||||||
QString("4.1.0"),
|
QString("4.3.2"),
|
||||||
QString("(c) Edouard Griffiths, F4EXB"),
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
QString("https://github.com/f4exb/sdrangel"),
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -40,6 +40,11 @@ void AMDemodSettings::resetToDefaults()
|
|||||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
m_pll = false;
|
m_pll = false;
|
||||||
m_syncAMOperation = SyncAMDSB;
|
m_syncAMOperation = SyncAMDSB;
|
||||||
|
m_useReverseAPI = false;
|
||||||
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
m_reverseAPIDeviceIndex = 0;
|
||||||
|
m_reverseAPIChannelIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray AMDemodSettings::serialize() const
|
QByteArray AMDemodSettings::serialize() const
|
||||||
@ -60,6 +65,11 @@ QByteArray AMDemodSettings::serialize() const
|
|||||||
s.writeString(11, m_audioDeviceName);
|
s.writeString(11, m_audioDeviceName);
|
||||||
s.writeBool(12, m_pll);
|
s.writeBool(12, m_pll);
|
||||||
s.writeS32(13, (int) m_syncAMOperation);
|
s.writeS32(13, (int) m_syncAMOperation);
|
||||||
|
s.writeBool(14, m_useReverseAPI);
|
||||||
|
s.writeString(15, m_reverseAPIAddress);
|
||||||
|
s.writeU32(16, m_reverseAPIPort);
|
||||||
|
s.writeU32(17, m_reverseAPIDeviceIndex);
|
||||||
|
s.writeU32(18, m_reverseAPIChannelIndex);
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -78,6 +88,7 @@ bool AMDemodSettings::deserialize(const QByteArray& data)
|
|||||||
{
|
{
|
||||||
QByteArray bytetmp;
|
QByteArray bytetmp;
|
||||||
qint32 tmp;
|
qint32 tmp;
|
||||||
|
uint32_t utmp;
|
||||||
QString strtmp;
|
QString strtmp;
|
||||||
|
|
||||||
d.readS32(1, &m_inputFrequencyOffset, 0);
|
d.readS32(1, &m_inputFrequencyOffset, 0);
|
||||||
@ -100,6 +111,20 @@ bool AMDemodSettings::deserialize(const QByteArray& data)
|
|||||||
d.readBool(12, &m_pll, false);
|
d.readBool(12, &m_pll, false);
|
||||||
d.readS32(13, &tmp, 0);
|
d.readS32(13, &tmp, 0);
|
||||||
m_syncAMOperation = tmp < 0 ? SyncAMDSB : tmp > 2 ? SyncAMDSB : (SyncAMOperation) tmp;
|
m_syncAMOperation = tmp < 0 ? SyncAMDSB : tmp > 2 ? SyncAMDSB : (SyncAMOperation) tmp;
|
||||||
|
d.readBool(14, &m_useReverseAPI, false);
|
||||||
|
d.readString(15, &m_reverseAPIAddress, "127.0.0.1");
|
||||||
|
d.readU32(16, &utmp, 0);
|
||||||
|
|
||||||
|
if ((utmp > 1023) && (utmp < 65535)) {
|
||||||
|
m_reverseAPIPort = utmp;
|
||||||
|
} else {
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.readU32(17, &utmp, 0);
|
||||||
|
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
d.readU32(18, &utmp, 0);
|
||||||
|
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,11 @@ struct AMDemodSettings
|
|||||||
QString m_audioDeviceName;
|
QString m_audioDeviceName;
|
||||||
bool m_pll;
|
bool m_pll;
|
||||||
SyncAMOperation m_syncAMOperation;
|
SyncAMOperation m_syncAMOperation;
|
||||||
|
bool m_useReverseAPI;
|
||||||
|
QString m_reverseAPIAddress;
|
||||||
|
uint16_t m_reverseAPIPort;
|
||||||
|
uint16_t m_reverseAPIDeviceIndex;
|
||||||
|
uint16_t m_reverseAPIChannelIndex;
|
||||||
|
|
||||||
AMDemodSettings();
|
AMDemodSettings();
|
||||||
void resetToDefaults();
|
void resetToDefaults();
|
||||||
|
@ -23,6 +23,7 @@ set(atv_FORMS
|
|||||||
include_directories(
|
include_directories(
|
||||||
.
|
.
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
${Boost_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
#include(${QT_USE_FILE})
|
#include(${QT_USE_FILE})
|
||||||
|
@ -26,7 +26,6 @@ CONFIG(Release):build_subdir = release
|
|||||||
CONFIG(Debug):build_subdir = debug
|
CONFIG(Debug):build_subdir = debug
|
||||||
|
|
||||||
CONFIG(MINGW32):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
CONFIG(MINGW32):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
||||||
CONFIG(MINGW64):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
|
||||||
CONFIG(MSVC):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
CONFIG(MSVC):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
||||||
CONFIG(macx):INCLUDEPATH += "../../../../../boost_1_69_0"
|
CONFIG(macx):INCLUDEPATH += "../../../../../boost_1_69_0"
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ include_directories(
|
|||||||
.
|
.
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||||
|
${Boost_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
#include(${QT_USE_FILE})
|
#include(${QT_USE_FILE})
|
||||||
|
@ -15,12 +15,16 @@
|
|||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <QTime>
|
|
||||||
#include <QDebug>
|
|
||||||
#include "boost/format.hpp"
|
#include "boost/format.hpp"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <complex.h>
|
#include <complex.h>
|
||||||
|
|
||||||
|
#include <QTime>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
#include "SWGChannelSettings.h"
|
#include "SWGChannelSettings.h"
|
||||||
#include "SWGBFMDemodSettings.h"
|
#include "SWGBFMDemodSettings.h"
|
||||||
#include "SWGChannelReport.h"
|
#include "SWGChannelReport.h"
|
||||||
@ -100,10 +104,16 @@ BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI) :
|
|||||||
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
||||||
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
||||||
m_deviceAPI->addChannelAPI(this);
|
m_deviceAPI->addChannelAPI(this);
|
||||||
|
|
||||||
|
m_networkManager = new QNetworkAccessManager();
|
||||||
|
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BFMDemod::~BFMDemod()
|
BFMDemod::~BFMDemod()
|
||||||
{
|
{
|
||||||
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
|
delete m_networkManager;
|
||||||
|
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo);
|
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo);
|
||||||
|
|
||||||
m_deviceAPI->removeChannelAPI(this);
|
m_deviceAPI->removeChannelAPI(this);
|
||||||
@ -449,15 +459,38 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force)
|
|||||||
<< " m_showPilot: " << settings.m_showPilot
|
<< " m_showPilot: " << settings.m_showPilot
|
||||||
<< " m_rdsActive: " << settings.m_rdsActive
|
<< " m_rdsActive: " << settings.m_rdsActive
|
||||||
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
||||||
|
<< " m_useReverseAPI: " << settings.m_useReverseAPI
|
||||||
<< " force: " << force;
|
<< " force: " << force;
|
||||||
|
|
||||||
|
QList<QString> reverseAPIKeys;
|
||||||
|
|
||||||
|
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
|
||||||
|
reverseAPIKeys.append("inputFrequencyOffset");
|
||||||
|
}
|
||||||
|
if ((settings.m_volume != m_settings.m_volume) || force) {
|
||||||
|
reverseAPIKeys.append("volume");
|
||||||
|
}
|
||||||
|
if ((settings.m_audioStereo != m_settings.m_audioStereo) || force) {
|
||||||
|
reverseAPIKeys.append("audioStereo");
|
||||||
|
}
|
||||||
|
if ((settings.m_lsbStereo != m_settings.m_lsbStereo) || force) {
|
||||||
|
reverseAPIKeys.append("lsbStereo");
|
||||||
|
}
|
||||||
|
if ((settings.m_showPilot != m_settings.m_showPilot) || force) {
|
||||||
|
reverseAPIKeys.append("showPilot");
|
||||||
|
}
|
||||||
|
if ((settings.m_rdsActive != m_settings.m_rdsActive) || force) {
|
||||||
|
reverseAPIKeys.append("rdsActive");
|
||||||
|
}
|
||||||
|
|
||||||
if ((settings.m_audioStereo && (settings.m_audioStereo != m_settings.m_audioStereo)) || force)
|
if ((settings.m_audioStereo && (settings.m_audioStereo != m_settings.m_audioStereo)) || force)
|
||||||
{
|
{
|
||||||
m_pilotPLL.configure(19000.0/m_inputSampleRate, 50.0/m_inputSampleRate, 0.01);
|
m_pilotPLL.configure(19000.0/m_inputSampleRate, 50.0/m_inputSampleRate, 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((settings.m_afBandwidth != m_settings.m_afBandwidth) || force)
|
if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("afBandwidth");
|
||||||
m_settingsMutex.lock();
|
m_settingsMutex.lock();
|
||||||
|
|
||||||
m_interpolator.create(16, m_inputSampleRate, settings.m_afBandwidth);
|
m_interpolator.create(16, m_inputSampleRate, settings.m_afBandwidth);
|
||||||
@ -472,11 +505,14 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force)
|
|||||||
m_interpolatorRDSDistanceRemain = (Real) m_inputSampleRate / 250000.0;
|
m_interpolatorRDSDistanceRemain = (Real) m_inputSampleRate / 250000.0;
|
||||||
m_interpolatorRDSDistance = (Real) m_inputSampleRate / 250000.0;
|
m_interpolatorRDSDistance = (Real) m_inputSampleRate / 250000.0;
|
||||||
|
|
||||||
|
m_lowpass.create(21, m_audioSampleRate, settings.m_afBandwidth);
|
||||||
|
|
||||||
m_settingsMutex.unlock();
|
m_settingsMutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
|
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("rfBandwidth");
|
||||||
m_settingsMutex.lock();
|
m_settingsMutex.lock();
|
||||||
Real lowCut = -(settings.m_rfBandwidth / 2.0) / m_inputSampleRate;
|
Real lowCut = -(settings.m_rfBandwidth / 2.0) / m_inputSampleRate;
|
||||||
Real hiCut = (settings.m_rfBandwidth / 2.0) / m_inputSampleRate;
|
Real hiCut = (settings.m_rfBandwidth / 2.0) / m_inputSampleRate;
|
||||||
@ -485,22 +521,15 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force)
|
|||||||
m_settingsMutex.unlock();
|
m_settingsMutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || force)
|
|
||||||
{
|
|
||||||
m_settingsMutex.lock();
|
|
||||||
qDebug() << "BFMDemod::handleMessage: m_lowpass.create";
|
|
||||||
m_lowpass.create(21, m_audioSampleRate, settings.m_afBandwidth);
|
|
||||||
m_settingsMutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((settings.m_squelch != m_settings.m_squelch) || force)
|
if ((settings.m_squelch != m_settings.m_squelch) || force)
|
||||||
{
|
{
|
||||||
qDebug() << "BFMDemod::handleMessage: set m_squelchLevel";
|
reverseAPIKeys.append("squelch");
|
||||||
m_squelchLevel = std::pow(10.0, settings.m_squelch / 10.0);
|
m_squelchLevel = std::pow(10.0, settings.m_squelch / 10.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
|
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("audioDeviceName");
|
||||||
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
||||||
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName);
|
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName);
|
||||||
//qDebug("AMDemod::applySettings: audioDeviceName: %s audioDeviceIndex: %d", qPrintable(settings.m_audioDeviceName), audioDeviceIndex);
|
//qDebug("AMDemod::applySettings: audioDeviceName: %s audioDeviceIndex: %d", qPrintable(settings.m_audioDeviceName), audioDeviceIndex);
|
||||||
@ -512,6 +541,16 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,6 +635,21 @@ int BFMDemod::webapiSettingsPutPatch(
|
|||||||
if (channelSettingsKeys.contains("audioDeviceName")) {
|
if (channelSettingsKeys.contains("audioDeviceName")) {
|
||||||
settings.m_audioDeviceName = *response.getBfmDemodSettings()->getAudioDeviceName();
|
settings.m_audioDeviceName = *response.getBfmDemodSettings()->getAudioDeviceName();
|
||||||
}
|
}
|
||||||
|
if (channelSettingsKeys.contains("useReverseAPI")) {
|
||||||
|
settings.m_useReverseAPI = response.getBfmDemodSettings()->getUseReverseApi() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIAddress")) {
|
||||||
|
settings.m_reverseAPIAddress = *response.getBfmDemodSettings()->getReverseApiAddress() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIPort")) {
|
||||||
|
settings.m_reverseAPIPort = response.getBfmDemodSettings()->getReverseApiPort();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
|
||||||
|
settings.m_reverseAPIDeviceIndex = response.getBfmDemodSettings()->getReverseApiDeviceIndex();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
|
||||||
|
settings.m_reverseAPIChannelIndex = response.getBfmDemodSettings()->getReverseApiChannelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
if (frequencyOffsetChanged)
|
if (frequencyOffsetChanged)
|
||||||
{
|
{
|
||||||
@ -654,6 +708,18 @@ void BFMDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& resp
|
|||||||
} else {
|
} else {
|
||||||
response.getBfmDemodSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
response.getBfmDemodSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response.getBfmDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
|
||||||
|
|
||||||
|
if (response.getBfmDemodSettings()->getReverseApiAddress()) {
|
||||||
|
*response.getBfmDemodSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
|
||||||
|
} else {
|
||||||
|
response.getBfmDemodSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
response.getBfmDemodSettings()->setReverseApiPort(settings.m_reverseAPIPort);
|
||||||
|
response.getBfmDemodSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
|
||||||
|
response.getBfmDemodSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BFMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
void BFMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
||||||
@ -707,3 +773,87 @@ void BFMDemod::webapiFormatRDSReport(SWGSDRangel::SWGRDSReport *report)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BFMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const BFMDemodSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
|
||||||
|
swgChannelSettings->setTx(0);
|
||||||
|
swgChannelSettings->setChannelType(new QString("BFMDemod"));
|
||||||
|
swgChannelSettings->setBfmDemodSettings(new SWGSDRangel::SWGBFMDemodSettings());
|
||||||
|
SWGSDRangel::SWGBFMDemodSettings *swgBFMDemodSettings = swgChannelSettings->getBfmDemodSettings();
|
||||||
|
|
||||||
|
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||||
|
|
||||||
|
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
|
||||||
|
swgBFMDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rfBandwidth") || force) {
|
||||||
|
swgBFMDemodSettings->setRfBandwidth(settings.m_rfBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("afBandwidth") || force) {
|
||||||
|
swgBFMDemodSettings->setAfBandwidth(settings.m_afBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("volume") || force) {
|
||||||
|
swgBFMDemodSettings->setVolume(settings.m_volume);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("squelch") || force) {
|
||||||
|
swgBFMDemodSettings->setSquelch(settings.m_squelch);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioStereo") || force) {
|
||||||
|
swgBFMDemodSettings->setAudioStereo(settings.m_audioStereo ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("lsbStereo") || force) {
|
||||||
|
swgBFMDemodSettings->setLsbStereo(settings.m_lsbStereo ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("showPilot") || force) {
|
||||||
|
swgBFMDemodSettings->setShowPilot(settings.m_showPilot ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rdsActive") || force) {
|
||||||
|
swgBFMDemodSettings->setRdsActive(settings.m_rdsActive ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||||
|
swgBFMDemodSettings->setRgbColor(settings.m_rgbColor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("title") || force) {
|
||||||
|
swgBFMDemodSettings->setTitle(new QString(settings.m_title));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioDeviceName") || force) {
|
||||||
|
swgBFMDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||||
|
|
||||||
|
delete swgChannelSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BFMDemod::networkManagerFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
QNetworkReply::NetworkError replyError = reply->error();
|
||||||
|
|
||||||
|
if (replyError)
|
||||||
|
{
|
||||||
|
qWarning() << "BFMDemod::networkManagerFinished:"
|
||||||
|
<< " error(" << (int) replyError
|
||||||
|
<< "): " << replyError
|
||||||
|
<< ": " << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString answer = reply->readAll();
|
||||||
|
answer.chop(1); // remove last \n
|
||||||
|
qDebug("BFMDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||||
|
}
|
||||||
|
@ -18,9 +18,11 @@
|
|||||||
#ifndef INCLUDE_BFMDEMOD_H
|
#ifndef INCLUDE_BFMDEMOD_H
|
||||||
#define INCLUDE_BFMDEMOD_H
|
#define INCLUDE_BFMDEMOD_H
|
||||||
|
|
||||||
#include <QMutex>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
#include "dsp/basebandsamplesink.h"
|
#include "dsp/basebandsamplesink.h"
|
||||||
#include "channel/channelsinkapi.h"
|
#include "channel/channelsinkapi.h"
|
||||||
#include "dsp/nco.h"
|
#include "dsp/nco.h"
|
||||||
@ -39,6 +41,8 @@
|
|||||||
#include "rdsdemod.h"
|
#include "rdsdemod.h"
|
||||||
#include "bfmdemodsettings.h"
|
#include "bfmdemodsettings.h"
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QNetworkReply;
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
class DownChannelizer;
|
class DownChannelizer;
|
||||||
@ -48,6 +52,7 @@ namespace SWGSDRangel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class BFMDemod : public BasebandSampleSink, public ChannelSinkAPI {
|
class BFMDemod : public BasebandSampleSink, public ChannelSinkAPI {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
class MsgConfigureBFMDemod : public Message {
|
class MsgConfigureBFMDemod : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
@ -117,7 +122,7 @@ public:
|
|||||||
|
|
||||||
BFMDemod(DeviceSourceAPI *deviceAPI);
|
BFMDemod(DeviceSourceAPI *deviceAPI);
|
||||||
virtual ~BFMDemod();
|
virtual ~BFMDemod();
|
||||||
virtual void destroy() { delete this; }
|
virtual void destroy() { delete this; }
|
||||||
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
|
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
|
||||||
|
|
||||||
int getSampleRate() const { return m_inputSampleRate; }
|
int getSampleRate() const { return m_inputSampleRate; }
|
||||||
@ -269,6 +274,9 @@ private:
|
|||||||
|
|
||||||
static const int m_udpBlockSize;
|
static const int m_udpBlockSize;
|
||||||
|
|
||||||
|
QNetworkAccessManager *m_networkManager;
|
||||||
|
QNetworkRequest m_networkRequest;
|
||||||
|
|
||||||
void applyAudioSampleRate(int sampleRate);
|
void applyAudioSampleRate(int sampleRate);
|
||||||
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force = false);
|
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force = false);
|
||||||
void applySettings(const BFMDemodSettings& settings, bool force = false);
|
void applySettings(const BFMDemodSettings& settings, bool force = false);
|
||||||
@ -276,6 +284,10 @@ private:
|
|||||||
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const BFMDemodSettings& settings);
|
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const BFMDemodSettings& settings);
|
||||||
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
||||||
void webapiFormatRDSReport(SWGSDRangel::SWGRDSReport *report);
|
void webapiFormatRDSReport(SWGSDRangel::SWGRDSReport *report);
|
||||||
|
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const BFMDemodSettings& settings, bool force);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void networkManagerFinished(QNetworkReply *reply);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_BFMDEMOD_H
|
#endif // INCLUDE_BFMDEMOD_H
|
||||||
|
@ -319,12 +319,23 @@ void BFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
|||||||
void BFMDemodGUI::onMenuDialogCalled(const QPoint &p)
|
void BFMDemodGUI::onMenuDialogCalled(const QPoint &p)
|
||||||
{
|
{
|
||||||
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
|
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.move(p);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
|
|
||||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
||||||
m_settings.m_title = m_channelMarker.getTitle();
|
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);
|
setWindowTitle(m_settings.m_title);
|
||||||
setTitleColor(m_settings.m_rgbColor);
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
@ -348,7 +359,7 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban
|
|||||||
ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue);
|
ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue);
|
||||||
|
|
||||||
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioStereo);
|
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioStereo);
|
||||||
connect(audioMuteRightClickEnabler, SIGNAL(rightClick()), this, SLOT(audioSelect()));
|
connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect()));
|
||||||
|
|
||||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
|
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
|
||||||
|
@ -48,6 +48,11 @@ void BFMDemodSettings::resetToDefaults()
|
|||||||
m_rgbColor = QColor(80, 120, 228).rgb();
|
m_rgbColor = QColor(80, 120, 228).rgb();
|
||||||
m_title = "Broadcast FM Demod";
|
m_title = "Broadcast FM Demod";
|
||||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
|
m_useReverseAPI = false;
|
||||||
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
m_reverseAPIDeviceIndex = 0;
|
||||||
|
m_reverseAPIChannelIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray BFMDemodSettings::serialize() const
|
QByteArray BFMDemodSettings::serialize() const
|
||||||
@ -73,6 +78,11 @@ QByteArray BFMDemodSettings::serialize() const
|
|||||||
|
|
||||||
s.writeString(12, m_title);
|
s.writeString(12, m_title);
|
||||||
s.writeString(13, m_audioDeviceName);
|
s.writeString(13, m_audioDeviceName);
|
||||||
|
s.writeBool(14, m_useReverseAPI);
|
||||||
|
s.writeString(15, m_reverseAPIAddress);
|
||||||
|
s.writeU32(16, m_reverseAPIPort);
|
||||||
|
s.writeU32(17, m_reverseAPIDeviceIndex);
|
||||||
|
s.writeU32(18, m_reverseAPIChannelIndex);
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -91,6 +101,7 @@ bool BFMDemodSettings::deserialize(const QByteArray& data)
|
|||||||
{
|
{
|
||||||
QByteArray bytetmp;
|
QByteArray bytetmp;
|
||||||
qint32 tmp;
|
qint32 tmp;
|
||||||
|
uint32_t utmp;
|
||||||
QString strtmp;
|
QString strtmp;
|
||||||
|
|
||||||
d.readS32(1, &tmp, 0);
|
d.readS32(1, &tmp, 0);
|
||||||
@ -122,6 +133,20 @@ bool BFMDemodSettings::deserialize(const QByteArray& data)
|
|||||||
|
|
||||||
d.readString(12, &m_title, "Broadcast FM Demod");
|
d.readString(12, &m_title, "Broadcast FM Demod");
|
||||||
d.readString(13, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName);
|
d.readString(13, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName);
|
||||||
|
d.readBool(14, &m_useReverseAPI, false);
|
||||||
|
d.readString(15, &m_reverseAPIAddress, "127.0.0.1");
|
||||||
|
d.readU32(16, &utmp, 0);
|
||||||
|
|
||||||
|
if ((utmp > 1023) && (utmp < 65535)) {
|
||||||
|
m_reverseAPIPort = utmp;
|
||||||
|
} else {
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.readU32(17, &utmp, 0);
|
||||||
|
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
d.readU32(18, &utmp, 0);
|
||||||
|
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,11 @@ struct BFMDemodSettings
|
|||||||
quint32 m_rgbColor;
|
quint32 m_rgbColor;
|
||||||
QString m_title;
|
QString m_title;
|
||||||
QString m_audioDeviceName;
|
QString m_audioDeviceName;
|
||||||
|
bool m_useReverseAPI;
|
||||||
|
QString m_reverseAPIAddress;
|
||||||
|
uint16_t m_reverseAPIPort;
|
||||||
|
uint16_t m_reverseAPIDeviceIndex;
|
||||||
|
uint16_t m_reverseAPIChannelIndex;
|
||||||
|
|
||||||
Serializable *m_channelMarker;
|
Serializable *m_channelMarker;
|
||||||
Serializable *m_spectrumGUI;
|
Serializable *m_spectrumGUI;
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
const PluginDescriptor BFMPlugin::m_pluginDescriptor = {
|
const PluginDescriptor BFMPlugin::m_pluginDescriptor = {
|
||||||
QString("Broadcast FM Demodulator"),
|
QString("Broadcast FM Demodulator"),
|
||||||
QString("4.1.0"),
|
QString("4.3.2"),
|
||||||
QString("(c) Edouard Griffiths, F4EXB"),
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
QString("https://github.com/f4exb/sdrangel"),
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -25,7 +25,6 @@ INCLUDEPATH += ../../../swagger/sdrangel/code/qt5/client
|
|||||||
|
|
||||||
CONFIG(ANDROID):INCLUDEPATH += /opt/softs/boost_1_60_0
|
CONFIG(ANDROID):INCLUDEPATH += /opt/softs/boost_1_60_0
|
||||||
CONFIG(MINGW32):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
CONFIG(MINGW32):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
||||||
CONFIG(MINGW64):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
|
||||||
CONFIG(MSVC):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
CONFIG(MSVC):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
||||||
CONFIG(macx):INCLUDEPATH += "../../../../../boost_1_69_0"
|
CONFIG(macx):INCLUDEPATH += "../../../../../boost_1_69_0"
|
||||||
|
|
||||||
|
@ -18,17 +18,14 @@ QMAKE_CXXFLAGS += -msse4.1
|
|||||||
QMAKE_CXXFLAGS += -std=c++11
|
QMAKE_CXXFLAGS += -std=c++11
|
||||||
|
|
||||||
CONFIG(MINGW32):LIBDSDCCSRC = "C:\softs\dsdcc"
|
CONFIG(MINGW32):LIBDSDCCSRC = "C:\softs\dsdcc"
|
||||||
CONFIG(MINGW64):LIBDSDCCSRC = "C:\softs\dsdcc"
|
|
||||||
CONFIG(MSVC):LIBDSDCCSRC = "C:\softs\dsdcc"
|
CONFIG(MSVC):LIBDSDCCSRC = "C:\softs\dsdcc"
|
||||||
CONFIG(macx):LIBDSDCCSRC = "../../../../deps/dsdcc"
|
CONFIG(macx):LIBDSDCCSRC = "../../../../deps/dsdcc"
|
||||||
|
|
||||||
CONFIG(MINGW32):LIBMBELIBSRC = "C:\softs\mbelib"
|
CONFIG(MINGW32):LIBMBELIBSRC = "C:\softs\mbelib"
|
||||||
CONFIG(MINGW64):LIBMBELIBSRC = "C:\softs\mbelib"
|
|
||||||
CONFIG(MSVC):LIBMBELIBSRC = "C:\softs\mbelib"
|
CONFIG(MSVC):LIBMBELIBSRC = "C:\softs\mbelib"
|
||||||
CONFIG(macx):LIBMBELIBSRC = "../../../../deps/mbelib"
|
CONFIG(macx):LIBMBELIBSRC = "../../../../deps/mbelib"
|
||||||
|
|
||||||
CONFIG(MINGW32):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
CONFIG(MINGW32):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
||||||
CONFIG(MINGW64):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
|
||||||
CONFIG(MSVC):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
CONFIG(MSVC):INCLUDEPATH += "C:\softs\boost_1_66_0"
|
||||||
CONFIG(macx):INCLUDEPATH += "../../../../../boost_1_69_0"
|
CONFIG(macx):INCLUDEPATH += "../../../../../boost_1_69_0"
|
||||||
|
|
||||||
|
@ -16,12 +16,16 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
#include <QTime>
|
|
||||||
#include <QDebug>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <complex.h>
|
#include <complex.h>
|
||||||
|
|
||||||
|
#include <QTime>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
#include "SWGChannelSettings.h"
|
#include "SWGChannelSettings.h"
|
||||||
#include "SWGDSDDemodSettings.h"
|
#include "SWGDSDDemodSettings.h"
|
||||||
#include "SWGChannelReport.h"
|
#include "SWGChannelReport.h"
|
||||||
@ -92,10 +96,15 @@ DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) :
|
|||||||
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
||||||
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
||||||
m_deviceAPI->addChannelAPI(this);
|
m_deviceAPI->addChannelAPI(this);
|
||||||
|
|
||||||
|
m_networkManager = new QNetworkAccessManager();
|
||||||
|
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
DSDDemod::~DSDDemod()
|
DSDDemod::~DSDDemod()
|
||||||
{
|
{
|
||||||
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
|
delete m_networkManager;
|
||||||
delete[] m_sampleBuffer;
|
delete[] m_sampleBuffer;
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo1);
|
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo1);
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo2);
|
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo2);
|
||||||
@ -479,10 +488,41 @@ void DSDDemod::applySettings(const DSDDemodSettings& settings, bool force)
|
|||||||
<< " m_pllLock: " << settings.m_pllLock
|
<< " m_pllLock: " << settings.m_pllLock
|
||||||
<< " m_highPassFilter: "<< settings.m_highPassFilter
|
<< " m_highPassFilter: "<< settings.m_highPassFilter
|
||||||
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
||||||
|
<< " m_traceLengthMutliplier: " << settings.m_traceLengthMutliplier
|
||||||
|
<< " m_traceStroke: " << settings.m_traceStroke
|
||||||
|
<< " m_traceDecay: " << settings.m_traceDecay
|
||||||
<< " force: " << force;
|
<< " force: " << force;
|
||||||
|
|
||||||
|
QList<QString> reverseAPIKeys;
|
||||||
|
|
||||||
|
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
|
||||||
|
reverseAPIKeys.append("inputFrequencyOffset");
|
||||||
|
}
|
||||||
|
if ((settings.m_demodGain != m_settings.m_demodGain) || force) {
|
||||||
|
reverseAPIKeys.append("demodGain");
|
||||||
|
}
|
||||||
|
if ((settings.m_audioMute != m_settings.m_audioMute) || force) {
|
||||||
|
reverseAPIKeys.append("audioMute");
|
||||||
|
}
|
||||||
|
if ((settings.m_syncOrConstellation != m_settings.m_syncOrConstellation) || force) {
|
||||||
|
reverseAPIKeys.append("syncOrConstellation");
|
||||||
|
}
|
||||||
|
if ((settings.m_slot1On != m_settings.m_slot1On) || force) {
|
||||||
|
reverseAPIKeys.append("slot1On");
|
||||||
|
}
|
||||||
|
if ((settings.m_slot2On != m_settings.m_slot2On) || force) {
|
||||||
|
reverseAPIKeys.append("slot2On");
|
||||||
|
}
|
||||||
|
if ((settings.m_demodGain != m_settings.m_demodGain) || force) {
|
||||||
|
reverseAPIKeys.append("demodGain");
|
||||||
|
}
|
||||||
|
if ((settings.m_traceLengthMutliplier != m_settings.m_traceLengthMutliplier) || force) {
|
||||||
|
reverseAPIKeys.append("traceLengthMutliplier");
|
||||||
|
}
|
||||||
|
|
||||||
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
|
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("rfBandwidth");
|
||||||
m_settingsMutex.lock();
|
m_settingsMutex.lock();
|
||||||
m_interpolator.create(16, m_inputSampleRate, (settings.m_rfBandwidth) / 2.2);
|
m_interpolator.create(16, m_inputSampleRate, (settings.m_rfBandwidth) / 2.2);
|
||||||
m_interpolatorDistanceRemain = 0;
|
m_interpolatorDistanceRemain = 0;
|
||||||
@ -493,53 +533,63 @@ void DSDDemod::applySettings(const DSDDemodSettings& settings, bool force)
|
|||||||
|
|
||||||
if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force)
|
if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("fmDeviation");
|
||||||
m_phaseDiscri.setFMScaling(48000.0f / (2.0f*settings.m_fmDeviation));
|
m_phaseDiscri.setFMScaling(48000.0f / (2.0f*settings.m_fmDeviation));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_squelchGate != m_settings.m_squelchGate) || force)
|
if ((settings.m_squelchGate != m_settings.m_squelchGate) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("squelchGate");
|
||||||
m_squelchGate = 480 * settings.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate
|
m_squelchGate = 480 * settings.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate
|
||||||
m_squelchCount = 0; // reset squelch open counter
|
m_squelchCount = 0; // reset squelch open counter
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_squelch != m_settings.m_squelch) || force)
|
if ((settings.m_squelch != m_settings.m_squelch) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("squelch");
|
||||||
// input is a value in dB
|
// input is a value in dB
|
||||||
m_squelchLevel = std::pow(10.0, settings.m_squelch / 10.0);
|
m_squelchLevel = std::pow(10.0, settings.m_squelch / 10.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_volume != m_settings.m_volume) || force)
|
if ((settings.m_volume != m_settings.m_volume) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("volume");
|
||||||
m_dsdDecoder.setAudioGain(settings.m_volume);
|
m_dsdDecoder.setAudioGain(settings.m_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_baudRate != m_settings.m_baudRate) || force)
|
if ((settings.m_baudRate != m_settings.m_baudRate) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("baudRate");
|
||||||
m_dsdDecoder.setBaudRate(settings.m_baudRate);
|
m_dsdDecoder.setBaudRate(settings.m_baudRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_enableCosineFiltering != m_settings.m_enableCosineFiltering) || force)
|
if ((settings.m_enableCosineFiltering != m_settings.m_enableCosineFiltering) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("enableCosineFiltering");
|
||||||
m_dsdDecoder.enableCosineFiltering(settings.m_enableCosineFiltering);
|
m_dsdDecoder.enableCosineFiltering(settings.m_enableCosineFiltering);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_tdmaStereo != m_settings.m_tdmaStereo) || force)
|
if ((settings.m_tdmaStereo != m_settings.m_tdmaStereo) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("tdmaStereo");
|
||||||
m_dsdDecoder.setTDMAStereo(settings.m_tdmaStereo);
|
m_dsdDecoder.setTDMAStereo(settings.m_tdmaStereo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_pllLock != m_settings.m_pllLock) || force)
|
if ((settings.m_pllLock != m_settings.m_pllLock) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("pllLock");
|
||||||
m_dsdDecoder.setSymbolPLLLock(settings.m_pllLock);
|
m_dsdDecoder.setSymbolPLLLock(settings.m_pllLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_highPassFilter != m_settings.m_highPassFilter) || force)
|
if ((settings.m_highPassFilter != m_settings.m_highPassFilter) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("highPassFilter");
|
||||||
m_dsdDecoder.useHPMbelib(settings.m_highPassFilter);
|
m_dsdDecoder.useHPMbelib(settings.m_highPassFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
|
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("audioDeviceName");
|
||||||
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
||||||
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName);
|
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName);
|
||||||
//qDebug("AMDemod::applySettings: audioDeviceName: %s audioDeviceIndex: %d", qPrintable(settings.m_audioDeviceName), audioDeviceIndex);
|
//qDebug("AMDemod::applySettings: audioDeviceName: %s audioDeviceIndex: %d", qPrintable(settings.m_audioDeviceName), audioDeviceIndex);
|
||||||
@ -552,6 +602,16 @@ void DSDDemod::applySettings(const DSDDemodSettings& settings, bool force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -855,6 +915,21 @@ int DSDDemod::webapiSettingsPutPatch(
|
|||||||
if (channelSettingsKeys.contains("traceDecay")) {
|
if (channelSettingsKeys.contains("traceDecay")) {
|
||||||
settings.m_traceDecay = response.getDsdDemodSettings()->getTraceDecay();
|
settings.m_traceDecay = response.getDsdDemodSettings()->getTraceDecay();
|
||||||
}
|
}
|
||||||
|
if (channelSettingsKeys.contains("useReverseAPI")) {
|
||||||
|
settings.m_useReverseAPI = response.getDsdDemodSettings()->getUseReverseApi() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIAddress")) {
|
||||||
|
settings.m_reverseAPIAddress = *response.getDsdDemodSettings()->getReverseApiAddress() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIPort")) {
|
||||||
|
settings.m_reverseAPIPort = response.getDsdDemodSettings()->getReverseApiPort();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
|
||||||
|
settings.m_reverseAPIDeviceIndex = response.getDsdDemodSettings()->getReverseApiDeviceIndex();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
|
||||||
|
settings.m_reverseAPIChannelIndex = response.getDsdDemodSettings()->getReverseApiChannelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
if (frequencyOffsetChanged)
|
if (frequencyOffsetChanged)
|
||||||
{
|
{
|
||||||
@ -924,6 +999,18 @@ void DSDDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& resp
|
|||||||
response.getDsdDemodSettings()->setTraceLengthMutliplier(settings.m_traceLengthMutliplier);
|
response.getDsdDemodSettings()->setTraceLengthMutliplier(settings.m_traceLengthMutliplier);
|
||||||
response.getDsdDemodSettings()->setTraceStroke(settings.m_traceStroke);
|
response.getDsdDemodSettings()->setTraceStroke(settings.m_traceStroke);
|
||||||
response.getDsdDemodSettings()->setTraceDecay(settings.m_traceDecay);
|
response.getDsdDemodSettings()->setTraceDecay(settings.m_traceDecay);
|
||||||
|
response.getDsdDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
|
||||||
|
|
||||||
|
if (response.getDsdDemodSettings()->getReverseApiAddress()) {
|
||||||
|
*response.getDsdDemodSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
|
||||||
|
} else {
|
||||||
|
response.getDsdDemodSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
response.getDsdDemodSettings()->setReverseApiPort(settings.m_reverseAPIPort);
|
||||||
|
response.getDsdDemodSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
|
||||||
|
response.getDsdDemodSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSDDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
void DSDDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
||||||
@ -946,3 +1033,117 @@ void DSDDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response
|
|||||||
response.getDsdDemodReport()->setSyncRate(getDecoder().getSymbolSyncQuality());
|
response.getDsdDemodReport()->setSyncRate(getDecoder().getSymbolSyncQuality());
|
||||||
response.getDsdDemodReport()->setStatusText(new QString(updateAndGetStatusText()));
|
response.getDsdDemodReport()->setStatusText(new QString(updateAndGetStatusText()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DSDDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const DSDDemodSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
|
||||||
|
swgChannelSettings->setTx(0);
|
||||||
|
swgChannelSettings->setChannelType(new QString("DSDDemod"));
|
||||||
|
swgChannelSettings->setDsdDemodSettings(new SWGSDRangel::SWGDSDDemodSettings());
|
||||||
|
SWGSDRangel::SWGDSDDemodSettings *swgDSDDemodSettings = swgChannelSettings->getDsdDemodSettings();
|
||||||
|
|
||||||
|
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||||
|
|
||||||
|
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
|
||||||
|
swgDSDDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rfBandwidth") || force) {
|
||||||
|
swgDSDDemodSettings->setRfBandwidth(settings.m_rfBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("fmDeviation") || force) {
|
||||||
|
swgDSDDemodSettings->setFmDeviation(settings.m_fmDeviation);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("demodGain") || force) {
|
||||||
|
swgDSDDemodSettings->setDemodGain(settings.m_demodGain);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("volume") || force) {
|
||||||
|
swgDSDDemodSettings->setVolume(settings.m_volume);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("baudRate") || force) {
|
||||||
|
swgDSDDemodSettings->setBaudRate(settings.m_baudRate);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("squelchGate") || force) {
|
||||||
|
swgDSDDemodSettings->setSquelchGate(settings.m_squelchGate);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("squelch") || force) {
|
||||||
|
swgDSDDemodSettings->setSquelch(settings.m_squelch);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioMute") || force) {
|
||||||
|
swgDSDDemodSettings->setAudioMute(settings.m_audioMute ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("enableCosineFiltering") || force) {
|
||||||
|
swgDSDDemodSettings->setEnableCosineFiltering(settings.m_enableCosineFiltering ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("syncOrConstellation") || force) {
|
||||||
|
swgDSDDemodSettings->setSyncOrConstellation(settings.m_syncOrConstellation ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("slot1On") || force) {
|
||||||
|
swgDSDDemodSettings->setSlot1On(settings.m_slot1On ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("slot2On") || force) {
|
||||||
|
swgDSDDemodSettings->setSlot2On(settings.m_slot2On ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("tdmaStereo") || force) {
|
||||||
|
swgDSDDemodSettings->setTdmaStereo(settings.m_tdmaStereo ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("pllLock") || force) {
|
||||||
|
swgDSDDemodSettings->setPllLock(settings.m_pllLock ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||||
|
swgDSDDemodSettings->setRgbColor(settings.m_rgbColor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("title") || force) {
|
||||||
|
swgDSDDemodSettings->setTitle(new QString(settings.m_title));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioDeviceName") || force) {
|
||||||
|
swgDSDDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("highPassFilter") || force) {
|
||||||
|
swgDSDDemodSettings->setHighPassFilter(settings.m_highPassFilter ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("traceLengthMutliplier") || force) {
|
||||||
|
swgDSDDemodSettings->setTraceLengthMutliplier(settings.m_traceLengthMutliplier);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("traceStroke") || force) {
|
||||||
|
swgDSDDemodSettings->setTraceStroke(settings.m_traceStroke);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("traceDecay") || force) {
|
||||||
|
swgDSDDemodSettings->setTraceDecay(settings.m_traceDecay);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||||
|
|
||||||
|
delete swgChannelSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSDDemod::networkManagerFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
QNetworkReply::NetworkError replyError = reply->error();
|
||||||
|
|
||||||
|
if (replyError)
|
||||||
|
{
|
||||||
|
qWarning() << "DSDDemod::networkManagerFinished:"
|
||||||
|
<< " error(" << (int) replyError
|
||||||
|
<< "): " << replyError
|
||||||
|
<< ": " << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString answer = reply->readAll();
|
||||||
|
answer.chop(1); // remove last \n
|
||||||
|
qDebug("DSDDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||||
|
}
|
||||||
|
@ -18,9 +18,11 @@
|
|||||||
#ifndef INCLUDE_DSDDEMOD_H
|
#ifndef INCLUDE_DSDDEMOD_H
|
||||||
#define INCLUDE_DSDDEMOD_H
|
#define INCLUDE_DSDDEMOD_H
|
||||||
|
|
||||||
#include <QMutex>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
#include "dsp/basebandsamplesink.h"
|
#include "dsp/basebandsamplesink.h"
|
||||||
#include "channel/channelsinkapi.h"
|
#include "channel/channelsinkapi.h"
|
||||||
#include "dsp/phasediscri.h"
|
#include "dsp/phasediscri.h"
|
||||||
@ -38,11 +40,14 @@
|
|||||||
#include "dsddemodsettings.h"
|
#include "dsddemodsettings.h"
|
||||||
#include "dsddecoder.h"
|
#include "dsddecoder.h"
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QNetworkReply;
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
class DownChannelizer;
|
class DownChannelizer;
|
||||||
|
|
||||||
class DSDDemod : public BasebandSampleSink, public ChannelSinkAPI {
|
class DSDDemod : public BasebandSampleSink, public ChannelSinkAPI {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
class MsgConfigureDSDDemod : public Message {
|
class MsgConfigureDSDDemod : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
@ -244,6 +249,9 @@ private:
|
|||||||
SignalFormat m_signalFormat; //!< Used to keep formatting during successive calls for the same standard type
|
SignalFormat m_signalFormat; //!< Used to keep formatting during successive calls for the same standard type
|
||||||
PhaseDiscriminators m_phaseDiscri;
|
PhaseDiscriminators m_phaseDiscri;
|
||||||
|
|
||||||
|
QNetworkAccessManager *m_networkManager;
|
||||||
|
QNetworkRequest m_networkRequest;
|
||||||
|
|
||||||
QMutex m_settingsMutex;
|
QMutex m_settingsMutex;
|
||||||
|
|
||||||
static const int m_udpBlockSize;
|
static const int m_udpBlockSize;
|
||||||
@ -255,6 +263,11 @@ private:
|
|||||||
|
|
||||||
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const DSDDemodSettings& settings);
|
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const DSDDemodSettings& settings);
|
||||||
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
||||||
|
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const DSDDemodSettings& settings, bool force);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void networkManagerFinished(QNetworkReply *reply);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_DSDDEMOD_H
|
#endif // INCLUDE_DSDDEMOD_H
|
||||||
|
@ -274,12 +274,23 @@ void DSDDemodGUI::onMenuDialogCalled(const QPoint &p)
|
|||||||
{
|
{
|
||||||
//qDebug("DSDDemodGUI::onMenuDialogCalled: x: %d y: %d", p.x(), p.y());
|
//qDebug("DSDDemodGUI::onMenuDialogCalled: x: %d y: %d", p.x(), p.y());
|
||||||
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
|
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.move(p);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
|
|
||||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
||||||
m_settings.m_title = m_channelMarker.getTitle();
|
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);
|
setWindowTitle(m_settings.m_title);
|
||||||
setTitleColor(m_settings.m_rgbColor);
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
@ -319,7 +330,7 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban
|
|||||||
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
||||||
|
|
||||||
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
||||||
connect(audioMuteRightClickEnabler, SIGNAL(rightClick()), this, SLOT(audioSelect()));
|
connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect()));
|
||||||
|
|
||||||
m_scopeVisXY = new ScopeVisXY(ui->screenTV);
|
m_scopeVisXY = new ScopeVisXY(ui->screenTV);
|
||||||
m_scopeVisXY->setScale(2.0);
|
m_scopeVisXY->setScale(2.0);
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
const PluginDescriptor DSDDemodPlugin::m_pluginDescriptor = {
|
const PluginDescriptor DSDDemodPlugin::m_pluginDescriptor = {
|
||||||
QString("DSD Demodulator"),
|
QString("DSD Demodulator"),
|
||||||
QString("4.3.1"),
|
QString("4.3.2"),
|
||||||
QString("(c) Edouard Griffiths, F4EXB"),
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
QString("https://github.com/f4exb/sdrangel"),
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -52,6 +52,11 @@ void DSDDemodSettings::resetToDefaults()
|
|||||||
m_traceStroke = 100;
|
m_traceStroke = 100;
|
||||||
m_traceDecay = 200;
|
m_traceDecay = 200;
|
||||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
|
m_useReverseAPI = false;
|
||||||
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
m_reverseAPIDeviceIndex = 0;
|
||||||
|
m_reverseAPIChannelIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray DSDDemodSettings::serialize() const
|
QByteArray DSDDemodSettings::serialize() const
|
||||||
@ -87,6 +92,11 @@ QByteArray DSDDemodSettings::serialize() const
|
|||||||
s.writeS32(21, m_traceLengthMutliplier);
|
s.writeS32(21, m_traceLengthMutliplier);
|
||||||
s.writeS32(22, m_traceStroke);
|
s.writeS32(22, m_traceStroke);
|
||||||
s.writeS32(23, m_traceDecay);
|
s.writeS32(23, m_traceDecay);
|
||||||
|
s.writeBool(24, m_useReverseAPI);
|
||||||
|
s.writeString(25, m_reverseAPIAddress);
|
||||||
|
s.writeU32(26, m_reverseAPIPort);
|
||||||
|
s.writeU32(27, m_reverseAPIDeviceIndex);
|
||||||
|
s.writeU32(28, m_reverseAPIChannelIndex);
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -106,6 +116,7 @@ bool DSDDemodSettings::deserialize(const QByteArray& data)
|
|||||||
QByteArray bytetmp;
|
QByteArray bytetmp;
|
||||||
QString strtmp;
|
QString strtmp;
|
||||||
qint32 tmp;
|
qint32 tmp;
|
||||||
|
uint32_t utmp;
|
||||||
|
|
||||||
if (m_channelMarker) {
|
if (m_channelMarker) {
|
||||||
d.readBlob(17, &bytetmp);
|
d.readBlob(17, &bytetmp);
|
||||||
@ -147,6 +158,20 @@ bool DSDDemodSettings::deserialize(const QByteArray& data)
|
|||||||
m_traceStroke = tmp < 0 ? 0 : tmp > 255 ? 255 : tmp;
|
m_traceStroke = tmp < 0 ? 0 : tmp > 255 ? 255 : tmp;
|
||||||
d.readS32(23, &tmp, 200);
|
d.readS32(23, &tmp, 200);
|
||||||
m_traceDecay = tmp < 0 ? 0 : tmp > 255 ? 255 : tmp;
|
m_traceDecay = tmp < 0 ? 0 : tmp > 255 ? 255 : tmp;
|
||||||
|
d.readBool(24, &m_useReverseAPI, false);
|
||||||
|
d.readString(25, &m_reverseAPIAddress, "127.0.0.1");
|
||||||
|
d.readU32(26, &utmp, 0);
|
||||||
|
|
||||||
|
if ((utmp > 1023) && (utmp < 65535)) {
|
||||||
|
m_reverseAPIPort = utmp;
|
||||||
|
} else {
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.readU32(27, &utmp, 0);
|
||||||
|
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
d.readU32(28, &utmp, 0);
|
||||||
|
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,11 @@ struct DSDDemodSettings
|
|||||||
int m_traceStroke; // [0..255]
|
int m_traceStroke; // [0..255]
|
||||||
int m_traceDecay; // [0..255]
|
int m_traceDecay; // [0..255]
|
||||||
QString m_audioDeviceName;
|
QString m_audioDeviceName;
|
||||||
|
bool m_useReverseAPI;
|
||||||
|
QString m_reverseAPIAddress;
|
||||||
|
uint16_t m_reverseAPIPort;
|
||||||
|
uint16_t m_reverseAPIDeviceIndex;
|
||||||
|
uint16_t m_reverseAPIChannelIndex;
|
||||||
|
|
||||||
Serializable *m_channelMarker;
|
Serializable *m_channelMarker;
|
||||||
Serializable *m_scopeGUI;
|
Serializable *m_scopeGUI;
|
||||||
|
@ -15,11 +15,15 @@
|
|||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <QTime>
|
|
||||||
#include <QDebug>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <complex.h>
|
#include <complex.h>
|
||||||
|
|
||||||
|
#include <QTime>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
#include "SWGChannelSettings.h"
|
#include "SWGChannelSettings.h"
|
||||||
#include "SWGNFMDemodSettings.h"
|
#include "SWGNFMDemodSettings.h"
|
||||||
#include "SWGChannelReport.h"
|
#include "SWGChannelReport.h"
|
||||||
@ -94,10 +98,15 @@ NFMDemod::NFMDemod(DeviceSourceAPI *devieAPI) :
|
|||||||
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
||||||
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
||||||
m_deviceAPI->addChannelAPI(this);
|
m_deviceAPI->addChannelAPI(this);
|
||||||
|
|
||||||
|
m_networkManager = new QNetworkAccessManager();
|
||||||
|
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
NFMDemod::~NFMDemod()
|
NFMDemod::~NFMDemod()
|
||||||
{
|
{
|
||||||
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
|
delete m_networkManager;
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo);
|
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo);
|
||||||
m_deviceAPI->removeChannelAPI(this);
|
m_deviceAPI->removeChannelAPI(this);
|
||||||
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
|
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
|
||||||
@ -491,10 +500,33 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force)
|
|||||||
<< " m_ctcssOn: " << settings.m_ctcssOn
|
<< " m_ctcssOn: " << settings.m_ctcssOn
|
||||||
<< " m_audioMute: " << settings.m_audioMute
|
<< " m_audioMute: " << settings.m_audioMute
|
||||||
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
||||||
|
<< " m_useReverseAPI: " << settings.m_useReverseAPI
|
||||||
<< " force: " << force;
|
<< " force: " << force;
|
||||||
|
|
||||||
|
QList<QString> reverseAPIKeys;
|
||||||
|
|
||||||
|
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
|
||||||
|
reverseAPIKeys.append("inputFrequencyOffset");
|
||||||
|
}
|
||||||
|
if ((settings.m_volume != m_settings.m_volume) || force) {
|
||||||
|
reverseAPIKeys.append("volume");
|
||||||
|
}
|
||||||
|
if ((settings.m_ctcssOn != m_settings.m_ctcssOn) || force) {
|
||||||
|
reverseAPIKeys.append("ctcssOn");
|
||||||
|
}
|
||||||
|
if ((settings.m_audioMute != m_settings.m_audioMute) || force) {
|
||||||
|
reverseAPIKeys.append("audioMute");
|
||||||
|
}
|
||||||
|
if ((settings.m_rgbColor != m_settings.m_rgbColor) || force) {
|
||||||
|
reverseAPIKeys.append("rgbColor");
|
||||||
|
}
|
||||||
|
if ((settings.m_title != m_settings.m_title) || force) {
|
||||||
|
reverseAPIKeys.append("title");
|
||||||
|
}
|
||||||
|
|
||||||
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
|
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("rfBandwidth");
|
||||||
m_settingsMutex.lock();
|
m_settingsMutex.lock();
|
||||||
m_interpolator.create(16, m_inputSampleRate, settings.m_rfBandwidth / 2.2);
|
m_interpolator.create(16, m_inputSampleRate, settings.m_rfBandwidth / 2.2);
|
||||||
m_interpolatorDistanceRemain = 0;
|
m_interpolatorDistanceRemain = 0;
|
||||||
@ -504,11 +536,13 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force)
|
|||||||
|
|
||||||
if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force)
|
if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("fmDeviation");
|
||||||
m_phaseDiscri.setFMScaling((8.0f*m_audioSampleRate) / static_cast<float>(settings.m_fmDeviation)); // integrate 4x factor
|
m_phaseDiscri.setFMScaling((8.0f*m_audioSampleRate) / static_cast<float>(settings.m_fmDeviation)); // integrate 4x factor
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || force)
|
if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("afBandwidth");
|
||||||
m_settingsMutex.lock();
|
m_settingsMutex.lock();
|
||||||
m_bandpass.create(301, m_audioSampleRate, 300.0, settings.m_afBandwidth);
|
m_bandpass.create(301, m_audioSampleRate, 300.0, settings.m_afBandwidth);
|
||||||
m_settingsMutex.unlock();
|
m_settingsMutex.unlock();
|
||||||
@ -516,10 +550,18 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force)
|
|||||||
|
|
||||||
if ((settings.m_squelchGate != m_settings.m_squelchGate) || force)
|
if ((settings.m_squelchGate != m_settings.m_squelchGate) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("squelchGate");
|
||||||
m_squelchGate = (m_audioSampleRate / 100) * settings.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate
|
m_squelchGate = (m_audioSampleRate / 100) * settings.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate
|
||||||
m_squelchCount = 0; // reset squelch open counter
|
m_squelchCount = 0; // reset squelch open counter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((settings.m_squelch != m_settings.m_squelch) || force) {
|
||||||
|
reverseAPIKeys.append("squelch");
|
||||||
|
}
|
||||||
|
if ((settings.m_deltaSquelch != m_settings.m_deltaSquelch) || force) {
|
||||||
|
reverseAPIKeys.append("deltaSquelch");
|
||||||
|
}
|
||||||
|
|
||||||
if ((settings.m_squelch != m_settings.m_squelch) ||
|
if ((settings.m_squelch != m_settings.m_squelch) ||
|
||||||
(settings.m_deltaSquelch != m_settings.m_deltaSquelch) || force)
|
(settings.m_deltaSquelch != m_settings.m_deltaSquelch) || force)
|
||||||
{
|
{
|
||||||
@ -540,11 +582,13 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force)
|
|||||||
|
|
||||||
if ((settings.m_ctcssIndex != m_settings.m_ctcssIndex) || force)
|
if ((settings.m_ctcssIndex != m_settings.m_ctcssIndex) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("ctcssIndex");
|
||||||
setSelectedCtcssIndex(settings.m_ctcssIndex);
|
setSelectedCtcssIndex(settings.m_ctcssIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
|
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("audioDeviceName");
|
||||||
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
||||||
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName);
|
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName);
|
||||||
//qDebug("AMDemod::applySettings: audioDeviceName: %s audioDeviceIndex: %d", qPrintable(settings.m_audioDeviceName), audioDeviceIndex);
|
//qDebug("AMDemod::applySettings: audioDeviceName: %s audioDeviceIndex: %d", qPrintable(settings.m_audioDeviceName), audioDeviceIndex);
|
||||||
@ -556,6 +600,16 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -722,3 +776,93 @@ void NFMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response
|
|||||||
response.getNfmDemodReport()->setAudioSampleRate(m_audioSampleRate);
|
response.getNfmDemodReport()->setAudioSampleRate(m_audioSampleRate);
|
||||||
response.getNfmDemodReport()->setChannelSampleRate(m_inputSampleRate);
|
response.getNfmDemodReport()->setChannelSampleRate(m_inputSampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NFMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const NFMDemodSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
|
||||||
|
swgChannelSettings->setTx(0);
|
||||||
|
swgChannelSettings->setChannelType(new QString("NFMDemod"));
|
||||||
|
swgChannelSettings->setNfmDemodSettings(new SWGSDRangel::SWGNFMDemodSettings());
|
||||||
|
SWGSDRangel::SWGNFMDemodSettings *swgNFMDemodSettings = swgChannelSettings->getNfmDemodSettings();
|
||||||
|
|
||||||
|
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||||
|
|
||||||
|
if (channelSettingsKeys.contains("afBandwidth") || force) {
|
||||||
|
swgNFMDemodSettings->setAfBandwidth(settings.m_afBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioMute") || force) {
|
||||||
|
swgNFMDemodSettings->setAudioMute(settings.m_audioMute ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("ctcssIndex") || force) {
|
||||||
|
swgNFMDemodSettings->setCtcssIndex(settings.m_ctcssIndex);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("ctcssOn") || force) {
|
||||||
|
swgNFMDemodSettings->setCtcssOn(settings.m_ctcssOn ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("deltaSquelch") || force) {
|
||||||
|
swgNFMDemodSettings->setDeltaSquelch(settings.m_deltaSquelch ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("fmDeviation") || force) {
|
||||||
|
swgNFMDemodSettings->setFmDeviation(settings.m_fmDeviation);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
|
||||||
|
swgNFMDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rfBandwidth") || force) {
|
||||||
|
swgNFMDemodSettings->setRfBandwidth(settings.m_rfBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||||
|
swgNFMDemodSettings->setRgbColor(settings.m_rgbColor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("squelch") || force) {
|
||||||
|
swgNFMDemodSettings->setSquelch(settings.m_squelch);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("squelchGate") || force) {
|
||||||
|
swgNFMDemodSettings->setSquelchGate(settings.m_squelchGate);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("title") || force) {
|
||||||
|
swgNFMDemodSettings->setTitle(new QString(settings.m_title));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("volume") || force) {
|
||||||
|
swgNFMDemodSettings->setVolume(settings.m_volume);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioDeviceName") || force) {
|
||||||
|
swgNFMDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||||
|
|
||||||
|
delete swgChannelSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFMDemod::networkManagerFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
QNetworkReply::NetworkError replyError = reply->error();
|
||||||
|
|
||||||
|
if (replyError)
|
||||||
|
{
|
||||||
|
qWarning() << "NFMDemod::networkManagerFinished:"
|
||||||
|
<< " error(" << (int) replyError
|
||||||
|
<< "): " << replyError
|
||||||
|
<< ": " << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString answer = reply->readAll();
|
||||||
|
answer.chop(1); // remove last \n
|
||||||
|
qDebug("NFMDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||||
|
}
|
||||||
|
@ -18,9 +18,11 @@
|
|||||||
#ifndef INCLUDE_NFMDEMOD_H
|
#ifndef INCLUDE_NFMDEMOD_H
|
||||||
#define INCLUDE_NFMDEMOD_H
|
#define INCLUDE_NFMDEMOD_H
|
||||||
|
|
||||||
#include <QMutex>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
#include "dsp/basebandsamplesink.h"
|
#include "dsp/basebandsamplesink.h"
|
||||||
#include "channel/channelsinkapi.h"
|
#include "channel/channelsinkapi.h"
|
||||||
#include "dsp/phasediscri.h"
|
#include "dsp/phasediscri.h"
|
||||||
@ -38,11 +40,14 @@
|
|||||||
|
|
||||||
#include "nfmdemodsettings.h"
|
#include "nfmdemodsettings.h"
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QNetworkReply;
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
class DownChannelizer;
|
class DownChannelizer;
|
||||||
|
|
||||||
class NFMDemod : public BasebandSampleSink, public ChannelSinkAPI {
|
class NFMDemod : public BasebandSampleSink, public ChannelSinkAPI {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
class MsgConfigureNFMDemod : public Message {
|
class MsgConfigureNFMDemod : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
@ -235,6 +240,9 @@ private:
|
|||||||
|
|
||||||
PhaseDiscriminators m_phaseDiscri;
|
PhaseDiscriminators m_phaseDiscri;
|
||||||
|
|
||||||
|
QNetworkAccessManager *m_networkManager;
|
||||||
|
QNetworkRequest m_networkRequest;
|
||||||
|
|
||||||
static const int m_udpBlockSize;
|
static const int m_udpBlockSize;
|
||||||
|
|
||||||
// void apply(bool force = false);
|
// void apply(bool force = false);
|
||||||
@ -243,6 +251,10 @@ private:
|
|||||||
void applyAudioSampleRate(int sampleRate);
|
void applyAudioSampleRate(int sampleRate);
|
||||||
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const NFMDemodSettings& settings);
|
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const NFMDemodSettings& settings);
|
||||||
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
||||||
|
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const NFMDemodSettings& settings, bool force);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void networkManagerFinished(QNetworkReply *reply);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_NFMDEMOD_H
|
#endif // INCLUDE_NFMDEMOD_H
|
||||||
|
@ -227,12 +227,22 @@ void NFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
|||||||
void NFMDemodGUI::onMenuDialogCalled(const QPoint &p)
|
void NFMDemodGUI::onMenuDialogCalled(const QPoint &p)
|
||||||
{
|
{
|
||||||
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
|
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.move(p);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
|
|
||||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
||||||
m_settings.m_title = m_channelMarker.getTitle();
|
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);
|
setWindowTitle(m_settings.m_title);
|
||||||
setTitleColor(m_settings.m_rgbColor);
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
@ -263,7 +273,7 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban
|
|||||||
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
|
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
|
||||||
|
|
||||||
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
||||||
connect(audioMuteRightClickEnabler, SIGNAL(rightClick()), this, SLOT(audioSelect()));
|
connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect()));
|
||||||
|
|
||||||
blockApplySettings(true);
|
blockApplySettings(true);
|
||||||
|
|
||||||
|
@ -52,6 +52,11 @@ void NFMDemodSettings::resetToDefaults()
|
|||||||
m_rgbColor = QColor(255, 0, 0).rgb();
|
m_rgbColor = QColor(255, 0, 0).rgb();
|
||||||
m_title = "NFM Demodulator";
|
m_title = "NFM Demodulator";
|
||||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
|
m_useReverseAPI = false;
|
||||||
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
m_reverseAPIDeviceIndex = 0;
|
||||||
|
m_reverseAPIChannelIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray NFMDemodSettings::serialize() const
|
QByteArray NFMDemodSettings::serialize() const
|
||||||
@ -75,6 +80,11 @@ QByteArray NFMDemodSettings::serialize() const
|
|||||||
|
|
||||||
s.writeString(14, m_title);
|
s.writeString(14, m_title);
|
||||||
s.writeString(15, m_audioDeviceName);
|
s.writeString(15, m_audioDeviceName);
|
||||||
|
s.writeBool(16, m_useReverseAPI);
|
||||||
|
s.writeString(17, m_reverseAPIAddress);
|
||||||
|
s.writeU32(18, m_reverseAPIPort);
|
||||||
|
s.writeU32(19, m_reverseAPIDeviceIndex);
|
||||||
|
s.writeU32(20, m_reverseAPIChannelIndex);
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -93,6 +103,7 @@ bool NFMDemodSettings::deserialize(const QByteArray& data)
|
|||||||
{
|
{
|
||||||
QByteArray bytetmp;
|
QByteArray bytetmp;
|
||||||
qint32 tmp;
|
qint32 tmp;
|
||||||
|
uint32_t utmp;
|
||||||
|
|
||||||
if (m_channelMarker)
|
if (m_channelMarker)
|
||||||
{
|
{
|
||||||
@ -119,6 +130,20 @@ bool NFMDemodSettings::deserialize(const QByteArray& data)
|
|||||||
d.readBool(12, &m_deltaSquelch, false);
|
d.readBool(12, &m_deltaSquelch, false);
|
||||||
d.readString(14, &m_title, "NFM Demodulator");
|
d.readString(14, &m_title, "NFM Demodulator");
|
||||||
d.readString(15, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName);
|
d.readString(15, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName);
|
||||||
|
d.readBool(16, &m_useReverseAPI, false);
|
||||||
|
d.readString(17, &m_reverseAPIAddress, "127.0.0.1");
|
||||||
|
d.readU32(18, &utmp, 0);
|
||||||
|
|
||||||
|
if ((utmp > 1023) && (utmp < 65535)) {
|
||||||
|
m_reverseAPIPort = utmp;
|
||||||
|
} else {
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.readU32(19, &utmp, 0);
|
||||||
|
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
d.readU32(20, &utmp, 0);
|
||||||
|
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,11 @@ struct NFMDemodSettings
|
|||||||
quint32 m_rgbColor;
|
quint32 m_rgbColor;
|
||||||
QString m_title;
|
QString m_title;
|
||||||
QString m_audioDeviceName;
|
QString m_audioDeviceName;
|
||||||
|
bool m_useReverseAPI;
|
||||||
|
QString m_reverseAPIAddress;
|
||||||
|
uint16_t m_reverseAPIPort;
|
||||||
|
uint16_t m_reverseAPIDeviceIndex;
|
||||||
|
uint16_t m_reverseAPIChannelIndex;
|
||||||
|
|
||||||
Serializable *m_channelMarker;
|
Serializable *m_channelMarker;
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
const PluginDescriptor NFMPlugin::m_pluginDescriptor = {
|
const PluginDescriptor NFMPlugin::m_pluginDescriptor = {
|
||||||
QString("NFM Demodulator"),
|
QString("NFM Demodulator"),
|
||||||
QString("4.2.1"),
|
QString("4.3.2"),
|
||||||
QString("(c) Edouard Griffiths, F4EXB"),
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
QString("https://github.com/f4exb/sdrangel"),
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -17,9 +17,13 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <stdio.h>
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
#include "SWGChannelSettings.h"
|
#include "SWGChannelSettings.h"
|
||||||
#include "SWGSSBDemodSettings.h"
|
#include "SWGSSBDemodSettings.h"
|
||||||
@ -98,10 +102,15 @@ SSBDemod::SSBDemod(DeviceSourceAPI *deviceAPI) :
|
|||||||
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
||||||
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
||||||
m_deviceAPI->addChannelAPI(this);
|
m_deviceAPI->addChannelAPI(this);
|
||||||
|
|
||||||
|
m_networkManager = new QNetworkAccessManager();
|
||||||
|
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
SSBDemod::~SSBDemod()
|
SSBDemod::~SSBDemod()
|
||||||
{
|
{
|
||||||
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
|
delete m_networkManager;
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo);
|
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo);
|
||||||
|
|
||||||
m_deviceAPI->removeChannelAPI(this);
|
m_deviceAPI->removeChannelAPI(this);
|
||||||
@ -455,6 +464,18 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
|
|||||||
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
||||||
<< " force: " << force;
|
<< " force: " << force;
|
||||||
|
|
||||||
|
QList<QString> reverseAPIKeys;
|
||||||
|
|
||||||
|
if((m_settings.m_inputFrequencyOffset != settings.m_inputFrequencyOffset) || force) {
|
||||||
|
reverseAPIKeys.append("inputFrequencyOffset");
|
||||||
|
}
|
||||||
|
if((m_settings.m_rfBandwidth != settings.m_rfBandwidth) || force) {
|
||||||
|
reverseAPIKeys.append("rfBandwidth");
|
||||||
|
}
|
||||||
|
if((m_settings.m_lowCutoff != settings.m_lowCutoff) || force) {
|
||||||
|
reverseAPIKeys.append("lowCutoff");
|
||||||
|
}
|
||||||
|
|
||||||
if((m_settings.m_rfBandwidth != settings.m_rfBandwidth) ||
|
if((m_settings.m_rfBandwidth != settings.m_rfBandwidth) ||
|
||||||
(m_settings.m_lowCutoff != settings.m_lowCutoff) || force)
|
(m_settings.m_lowCutoff != settings.m_lowCutoff) || force)
|
||||||
{
|
{
|
||||||
@ -491,10 +512,24 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
|
|||||||
|
|
||||||
if ((m_settings.m_volume != settings.m_volume) || force)
|
if ((m_settings.m_volume != settings.m_volume) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("volume");
|
||||||
m_volume = settings.m_volume;
|
m_volume = settings.m_volume;
|
||||||
m_volume /= 4.0; // for 3276.8
|
m_volume /= 4.0; // for 3276.8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((m_settings.m_agcTimeLog2 != settings.m_agcTimeLog2) || force) {
|
||||||
|
reverseAPIKeys.append("agcTimeLog2");
|
||||||
|
}
|
||||||
|
if ((m_settings.m_agcPowerThreshold != settings.m_agcPowerThreshold) || force) {
|
||||||
|
reverseAPIKeys.append("agcPowerThreshold");
|
||||||
|
}
|
||||||
|
if ((m_settings.m_agcThresholdGate != settings.m_agcThresholdGate) || force) {
|
||||||
|
reverseAPIKeys.append("agcThresholdGate");
|
||||||
|
}
|
||||||
|
if ((m_settings.m_agcClamping != settings.m_agcClamping) || force) {
|
||||||
|
reverseAPIKeys.append("agcClamping");
|
||||||
|
}
|
||||||
|
|
||||||
if ((m_settings.m_agcTimeLog2 != settings.m_agcTimeLog2) ||
|
if ((m_settings.m_agcTimeLog2 != settings.m_agcTimeLog2) ||
|
||||||
(m_settings.m_agcPowerThreshold != settings.m_agcPowerThreshold) ||
|
(m_settings.m_agcPowerThreshold != settings.m_agcPowerThreshold) ||
|
||||||
(m_settings.m_agcThresholdGate != settings.m_agcThresholdGate) ||
|
(m_settings.m_agcThresholdGate != settings.m_agcThresholdGate) ||
|
||||||
@ -542,6 +577,7 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
|
|||||||
|
|
||||||
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
|
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("audioDeviceName");
|
||||||
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
||||||
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName);
|
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName);
|
||||||
audioDeviceManager->addAudioSink(&m_audioFifo, getInputMessageQueue(), audioDeviceIndex);
|
audioDeviceManager->addAudioSink(&m_audioFifo, getInputMessageQueue(), audioDeviceIndex);
|
||||||
@ -552,6 +588,25 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((m_settings.m_spanLog2 != settings.m_spanLog2) || force) {
|
||||||
|
reverseAPIKeys.append("spanLog2");
|
||||||
|
}
|
||||||
|
if ((m_settings.m_audioBinaural != settings.m_audioBinaural) || force) {
|
||||||
|
reverseAPIKeys.append("audioBinaural");
|
||||||
|
}
|
||||||
|
if ((m_settings.m_audioFlipChannels != settings.m_audioFlipChannels) || force) {
|
||||||
|
reverseAPIKeys.append("audioFlipChannels");
|
||||||
|
}
|
||||||
|
if ((m_settings.m_dsb != settings.m_dsb) || force) {
|
||||||
|
reverseAPIKeys.append("dsb");
|
||||||
|
}
|
||||||
|
if ((m_settings.m_audioMute != settings.m_audioMute) || force) {
|
||||||
|
reverseAPIKeys.append("audioMute");
|
||||||
|
}
|
||||||
|
if ((m_settings.m_agc != settings.m_agc) || force) {
|
||||||
|
reverseAPIKeys.append("agc");
|
||||||
|
}
|
||||||
|
|
||||||
m_spanLog2 = settings.m_spanLog2;
|
m_spanLog2 = settings.m_spanLog2;
|
||||||
m_audioBinaual = settings.m_audioBinaural;
|
m_audioBinaual = settings.m_audioBinaural;
|
||||||
m_audioFlipChannels = settings.m_audioFlipChannels;
|
m_audioFlipChannels = settings.m_audioFlipChannels;
|
||||||
@ -559,6 +614,16 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
|
|||||||
m_audioMute = settings.m_audioMute;
|
m_audioMute = settings.m_audioMute;
|
||||||
m_agcActive = settings.m_agc;
|
m_agcActive = settings.m_agc;
|
||||||
|
|
||||||
|
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;
|
m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -736,3 +801,101 @@ void SSBDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response
|
|||||||
response.getSsbDemodReport()->setChannelSampleRate(m_inputSampleRate);
|
response.getSsbDemodReport()->setChannelSampleRate(m_inputSampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSBDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const SSBDemodSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
|
||||||
|
swgChannelSettings->setTx(0);
|
||||||
|
swgChannelSettings->setChannelType(new QString("SSBDemod"));
|
||||||
|
swgChannelSettings->setSsbDemodSettings(new SWGSDRangel::SWGSSBDemodSettings());
|
||||||
|
SWGSDRangel::SWGSSBDemodSettings *swgSSBDemodSettings = swgChannelSettings->getSsbDemodSettings();
|
||||||
|
|
||||||
|
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||||
|
|
||||||
|
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
|
||||||
|
swgSSBDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rfBandwidth") || force) {
|
||||||
|
swgSSBDemodSettings->setRfBandwidth(settings.m_rfBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("lowCutoff") || force) {
|
||||||
|
swgSSBDemodSettings->setLowCutoff(settings.m_lowCutoff);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("volume") || force) {
|
||||||
|
swgSSBDemodSettings->setVolume(settings.m_volume);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("spanLog2") || force) {
|
||||||
|
swgSSBDemodSettings->setSpanLog2(settings.m_spanLog2);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioBinaural") || force) {
|
||||||
|
swgSSBDemodSettings->setAudioBinaural(settings.m_audioBinaural ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioFlipChannels") || force) {
|
||||||
|
swgSSBDemodSettings->setAudioFlipChannels(settings.m_audioFlipChannels ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("dsb") || force) {
|
||||||
|
swgSSBDemodSettings->setDsb(settings.m_dsb ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioMute") || force) {
|
||||||
|
swgSSBDemodSettings->setAudioMute(settings.m_audioMute ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("agc") || force) {
|
||||||
|
swgSSBDemodSettings->setAgc(settings.m_agc ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("agcClamping") || force) {
|
||||||
|
swgSSBDemodSettings->setAgcClamping(settings.m_agcClamping ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("agcTimeLog2") || force) {
|
||||||
|
swgSSBDemodSettings->setAgcTimeLog2(settings.m_agcTimeLog2);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("agcPowerThreshold") || force) {
|
||||||
|
swgSSBDemodSettings->setAgcPowerThreshold(settings.m_agcPowerThreshold);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("agcThresholdGate") || force) {
|
||||||
|
swgSSBDemodSettings->setAgcThresholdGate(settings.m_agcThresholdGate);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||||
|
swgSSBDemodSettings->setRgbColor(settings.m_rgbColor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("title") || force) {
|
||||||
|
swgSSBDemodSettings->setTitle(new QString(settings.m_title));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioDeviceName") || force) {
|
||||||
|
swgSSBDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||||
|
|
||||||
|
delete swgChannelSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSBDemod::networkManagerFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
QNetworkReply::NetworkError replyError = reply->error();
|
||||||
|
|
||||||
|
if (replyError)
|
||||||
|
{
|
||||||
|
qWarning() << "SSBDemod::networkManagerFinished:"
|
||||||
|
<< " error(" << (int) replyError
|
||||||
|
<< "): " << replyError
|
||||||
|
<< ": " << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString answer = reply->readAll();
|
||||||
|
answer.chop(1); // remove last \n
|
||||||
|
qDebug("SSBDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||||
|
}
|
||||||
|
@ -18,9 +18,11 @@
|
|||||||
#ifndef INCLUDE_SSBDEMOD_H
|
#ifndef INCLUDE_SSBDEMOD_H
|
||||||
#define INCLUDE_SSBDEMOD_H
|
#define INCLUDE_SSBDEMOD_H
|
||||||
|
|
||||||
#include <QMutex>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
#include "dsp/basebandsamplesink.h"
|
#include "dsp/basebandsamplesink.h"
|
||||||
#include "channel/channelsinkapi.h"
|
#include "channel/channelsinkapi.h"
|
||||||
#include "dsp/ncof.h"
|
#include "dsp/ncof.h"
|
||||||
@ -36,11 +38,14 @@
|
|||||||
#define ssbFftLen 1024
|
#define ssbFftLen 1024
|
||||||
#define agcTarget 3276.8 // -10 dB amplitude => -20 dB power: center of normal signal
|
#define agcTarget 3276.8 // -10 dB amplitude => -20 dB power: center of normal signal
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QNetworkReply;
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
class DownChannelizer;
|
class DownChannelizer;
|
||||||
|
|
||||||
class SSBDemod : public BasebandSampleSink, public ChannelSinkAPI {
|
class SSBDemod : public BasebandSampleSink, public ChannelSinkAPI {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
class MsgConfigureSSBDemod : public Message {
|
class MsgConfigureSSBDemod : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
@ -310,6 +315,9 @@ private:
|
|||||||
AudioFifo m_audioFifo;
|
AudioFifo m_audioFifo;
|
||||||
quint32 m_audioSampleRate;
|
quint32 m_audioSampleRate;
|
||||||
|
|
||||||
|
QNetworkAccessManager *m_networkManager;
|
||||||
|
QNetworkRequest m_networkRequest;
|
||||||
|
|
||||||
QMutex m_settingsMutex;
|
QMutex m_settingsMutex;
|
||||||
|
|
||||||
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force = false);
|
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force = false);
|
||||||
@ -317,6 +325,10 @@ private:
|
|||||||
void applyAudioSampleRate(int sampleRate);
|
void applyAudioSampleRate(int sampleRate);
|
||||||
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const SSBDemodSettings& settings);
|
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const SSBDemodSettings& settings);
|
||||||
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
||||||
|
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const SSBDemodSettings& settings, bool force);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void networkManagerFinished(QNetworkReply *reply);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_SSBDEMOD_H
|
#endif // INCLUDE_SSBDEMOD_H
|
||||||
|
@ -238,12 +238,23 @@ void SSBDemodGUI::on_flipSidebands_clicked(bool checked)
|
|||||||
void SSBDemodGUI::onMenuDialogCalled(const QPoint &p)
|
void SSBDemodGUI::onMenuDialogCalled(const QPoint &p)
|
||||||
{
|
{
|
||||||
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
|
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.move(p);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
|
|
||||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
||||||
m_settings.m_title = m_channelMarker.getTitle();
|
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);
|
setWindowTitle(m_settings.m_title);
|
||||||
setTitleColor(m_settings.m_rgbColor);
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
@ -281,7 +292,7 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban
|
|||||||
m_ssbDemod->setSampleSink(m_spectrumVis);
|
m_ssbDemod->setSampleSink(m_spectrumVis);
|
||||||
|
|
||||||
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
||||||
connect(audioMuteRightClickEnabler, SIGNAL(rightClick()), this, SLOT(audioSelect()));
|
connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect()));
|
||||||
|
|
||||||
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
||||||
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||||
|
@ -55,6 +55,11 @@ void SSBDemodSettings::resetToDefaults()
|
|||||||
m_rgbColor = QColor(0, 255, 0).rgb();
|
m_rgbColor = QColor(0, 255, 0).rgb();
|
||||||
m_title = "SSB Demodulator";
|
m_title = "SSB Demodulator";
|
||||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
|
m_useReverseAPI = false;
|
||||||
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
m_reverseAPIDeviceIndex = 0;
|
||||||
|
m_reverseAPIChannelIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray SSBDemodSettings::serialize() const
|
QByteArray SSBDemodSettings::serialize() const
|
||||||
@ -81,6 +86,11 @@ QByteArray SSBDemodSettings::serialize() const
|
|||||||
s.writeBool(15, m_agcClamping);
|
s.writeBool(15, m_agcClamping);
|
||||||
s.writeString(16, m_title);
|
s.writeString(16, m_title);
|
||||||
s.writeString(17, m_audioDeviceName);
|
s.writeString(17, m_audioDeviceName);
|
||||||
|
s.writeBool(18, m_useReverseAPI);
|
||||||
|
s.writeString(19, m_reverseAPIAddress);
|
||||||
|
s.writeU32(20, m_reverseAPIPort);
|
||||||
|
s.writeU32(21, m_reverseAPIDeviceIndex);
|
||||||
|
s.writeU32(22, m_reverseAPIChannelIndex);
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -99,6 +109,7 @@ bool SSBDemodSettings::deserialize(const QByteArray& data)
|
|||||||
{
|
{
|
||||||
QByteArray bytetmp;
|
QByteArray bytetmp;
|
||||||
qint32 tmp;
|
qint32 tmp;
|
||||||
|
uint32_t utmp;
|
||||||
QString strtmp;
|
QString strtmp;
|
||||||
|
|
||||||
d.readS32(1, &m_inputFrequencyOffset, 0);
|
d.readS32(1, &m_inputFrequencyOffset, 0);
|
||||||
@ -126,6 +137,20 @@ bool SSBDemodSettings::deserialize(const QByteArray& data)
|
|||||||
d.readBool(15, &m_agcClamping, false);
|
d.readBool(15, &m_agcClamping, false);
|
||||||
d.readString(16, &m_title, "SSB Demodulator");
|
d.readString(16, &m_title, "SSB Demodulator");
|
||||||
d.readString(17, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName);
|
d.readString(17, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName);
|
||||||
|
d.readBool(18, &m_useReverseAPI, false);
|
||||||
|
d.readString(19, &m_reverseAPIAddress, "127.0.0.1");
|
||||||
|
d.readU32(20, &utmp, 0);
|
||||||
|
|
||||||
|
if ((utmp > 1023) && (utmp < 65535)) {
|
||||||
|
m_reverseAPIPort = utmp;
|
||||||
|
} else {
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.readU32(21, &utmp, 0);
|
||||||
|
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
d.readU32(22, &utmp, 0);
|
||||||
|
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,11 @@ struct SSBDemodSettings
|
|||||||
quint32 m_rgbColor;
|
quint32 m_rgbColor;
|
||||||
QString m_title;
|
QString m_title;
|
||||||
QString m_audioDeviceName;
|
QString m_audioDeviceName;
|
||||||
|
bool m_useReverseAPI;
|
||||||
|
QString m_reverseAPIAddress;
|
||||||
|
uint16_t m_reverseAPIPort;
|
||||||
|
uint16_t m_reverseAPIDeviceIndex;
|
||||||
|
uint16_t m_reverseAPIChannelIndex;
|
||||||
|
|
||||||
Serializable *m_channelMarker;
|
Serializable *m_channelMarker;
|
||||||
Serializable *m_spectrumGUI;
|
Serializable *m_spectrumGUI;
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
const PluginDescriptor SSBPlugin::m_pluginDescriptor = {
|
const PluginDescriptor SSBPlugin::m_pluginDescriptor = {
|
||||||
QString("SSB Demodulator"),
|
QString("SSB Demodulator"),
|
||||||
QString("4.1.0"),
|
QString("4.3.2"),
|
||||||
QString("(c) Edouard Griffiths, F4EXB"),
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
QString("https://github.com/f4exb/sdrangel"),
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -16,11 +16,15 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
#include <QTime>
|
|
||||||
#include <QDebug>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <complex.h>
|
#include <complex.h>
|
||||||
|
|
||||||
|
#include <QTime>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
#include "SWGChannelSettings.h"
|
#include "SWGChannelSettings.h"
|
||||||
#include "SWGWFMDemodSettings.h"
|
#include "SWGWFMDemodSettings.h"
|
||||||
#include "SWGChannelReport.h"
|
#include "SWGChannelReport.h"
|
||||||
@ -74,10 +78,15 @@ WFMDemod::WFMDemod(DeviceSourceAPI* deviceAPI) :
|
|||||||
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
||||||
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
||||||
m_deviceAPI->addChannelAPI(this);
|
m_deviceAPI->addChannelAPI(this);
|
||||||
|
|
||||||
|
m_networkManager = new QNetworkAccessManager();
|
||||||
|
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
WFMDemod::~WFMDemod()
|
WFMDemod::~WFMDemod()
|
||||||
{
|
{
|
||||||
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
|
delete m_networkManager;
|
||||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo);
|
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo);
|
||||||
|
|
||||||
m_deviceAPI->removeChannelAPI(this);
|
m_deviceAPI->removeChannelAPI(this);
|
||||||
@ -317,8 +326,39 @@ void WFMDemod::applySettings(const WFMDemodSettings& settings, bool force)
|
|||||||
<< " m_volume: " << settings.m_volume
|
<< " m_volume: " << settings.m_volume
|
||||||
<< " m_squelch: " << settings.m_squelch
|
<< " m_squelch: " << settings.m_squelch
|
||||||
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
||||||
|
<< " m_audioMute: " << settings.m_audioMute
|
||||||
<< " force: " << force;
|
<< " 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_afBandwidth != m_settings.m_afBandwidth) || force) {
|
||||||
|
reverseAPIKeys.append("afBandwidth");
|
||||||
|
}
|
||||||
|
if((settings.m_volume != m_settings.m_volume) || force) {
|
||||||
|
reverseAPIKeys.append("volume");
|
||||||
|
}
|
||||||
|
if((settings.m_squelch != m_settings.m_squelch) || force) {
|
||||||
|
reverseAPIKeys.append("squelch");
|
||||||
|
}
|
||||||
|
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((settings.m_title != m_settings.m_title) || force) {
|
||||||
|
reverseAPIKeys.append("title");
|
||||||
|
}
|
||||||
|
if((settings.m_rgbColor != m_settings.m_rgbColor) || force) {
|
||||||
|
reverseAPIKeys.append("rgbColor");
|
||||||
|
}
|
||||||
|
|
||||||
if((settings.m_afBandwidth != m_settings.m_afBandwidth) ||
|
if((settings.m_afBandwidth != m_settings.m_afBandwidth) ||
|
||||||
(settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
|
(settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
|
||||||
{
|
{
|
||||||
@ -356,6 +396,16 @@ void WFMDemod::applySettings(const WFMDemodSettings& settings, bool force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,3 +550,77 @@ void WFMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response
|
|||||||
response.getWfmDemodReport()->setChannelSampleRate(m_inputSampleRate);
|
response.getWfmDemodReport()->setChannelSampleRate(m_inputSampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WFMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const WFMDemodSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
|
||||||
|
swgChannelSettings->setTx(0);
|
||||||
|
swgChannelSettings->setChannelType(new QString("WFMDemod"));
|
||||||
|
swgChannelSettings->setWfmDemodSettings(new SWGSDRangel::SWGWFMDemodSettings());
|
||||||
|
SWGSDRangel::SWGWFMDemodSettings *swgWFMDemodSettings = swgChannelSettings->getWfmDemodSettings();
|
||||||
|
|
||||||
|
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||||
|
|
||||||
|
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
|
||||||
|
swgWFMDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rfBandwidth") || force) {
|
||||||
|
swgWFMDemodSettings->setRfBandwidth(settings.m_rfBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("afBandwidth") || force) {
|
||||||
|
swgWFMDemodSettings->setAfBandwidth(settings.m_afBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("volume") || force) {
|
||||||
|
swgWFMDemodSettings->setVolume(settings.m_volume);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("squelch") || force) {
|
||||||
|
swgWFMDemodSettings->setSquelch(settings.m_squelch);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioMute") || force) {
|
||||||
|
swgWFMDemodSettings->setAudioMute(settings.m_audioMute ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||||
|
swgWFMDemodSettings->setRgbColor(settings.m_rgbColor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("title") || force) {
|
||||||
|
swgWFMDemodSettings->setTitle(new QString(settings.m_title));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioDeviceName") || force) {
|
||||||
|
swgWFMDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||||
|
|
||||||
|
delete swgChannelSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WFMDemod::networkManagerFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
QNetworkReply::NetworkError replyError = reply->error();
|
||||||
|
|
||||||
|
if (replyError)
|
||||||
|
{
|
||||||
|
qWarning() << "WFMDemod::networkManagerFinished:"
|
||||||
|
<< " error(" << (int) replyError
|
||||||
|
<< "): " << replyError
|
||||||
|
<< ": " << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString answer = reply->readAll();
|
||||||
|
answer.chop(1); // remove last \n
|
||||||
|
qDebug("WFMDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||||
|
}
|
||||||
|
@ -18,9 +18,11 @@
|
|||||||
#ifndef INCLUDE_WFMDEMOD_H
|
#ifndef INCLUDE_WFMDEMOD_H
|
||||||
#define INCLUDE_WFMDEMOD_H
|
#define INCLUDE_WFMDEMOD_H
|
||||||
|
|
||||||
#include <QMutex>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
#include "dsp/basebandsamplesink.h"
|
#include "dsp/basebandsamplesink.h"
|
||||||
#include "channel/channelsinkapi.h"
|
#include "channel/channelsinkapi.h"
|
||||||
#include "dsp/nco.h"
|
#include "dsp/nco.h"
|
||||||
@ -36,11 +38,14 @@
|
|||||||
|
|
||||||
#define rfFilterFftLength 1024
|
#define rfFilterFftLength 1024
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QNetworkReply;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
class DownChannelizer;
|
class DownChannelizer;
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
|
|
||||||
class WFMDemod : public BasebandSampleSink, public ChannelSinkAPI {
|
class WFMDemod : public BasebandSampleSink, public ChannelSinkAPI {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
class MsgConfigureWFMDemod : public Message {
|
class MsgConfigureWFMDemod : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
@ -203,6 +208,9 @@ private:
|
|||||||
|
|
||||||
PhaseDiscriminators m_phaseDiscri;
|
PhaseDiscriminators m_phaseDiscri;
|
||||||
|
|
||||||
|
QNetworkAccessManager *m_networkManager;
|
||||||
|
QNetworkRequest m_networkRequest;
|
||||||
|
|
||||||
static const int m_udpBlockSize;
|
static const int m_udpBlockSize;
|
||||||
|
|
||||||
void applyAudioSampleRate(int sampleRate);
|
void applyAudioSampleRate(int sampleRate);
|
||||||
@ -211,6 +219,10 @@ private:
|
|||||||
|
|
||||||
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const WFMDemodSettings& settings);
|
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const WFMDemodSettings& settings);
|
||||||
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
||||||
|
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const WFMDemodSettings& settings, bool force);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void networkManagerFinished(QNetworkReply *reply);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_WFMDEMOD_H
|
#endif // INCLUDE_WFMDEMOD_H
|
||||||
|
@ -169,12 +169,23 @@ void WFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
|||||||
void WFMDemodGUI::onMenuDialogCalled(const QPoint &p)
|
void WFMDemodGUI::onMenuDialogCalled(const QPoint &p)
|
||||||
{
|
{
|
||||||
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
|
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.move(p);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
|
|
||||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
||||||
m_settings.m_title = m_channelMarker.getTitle();
|
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);
|
setWindowTitle(m_settings.m_title);
|
||||||
setTitleColor(m_settings.m_rgbColor);
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
@ -202,7 +213,7 @@ WFMDemodGUI::WFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban
|
|||||||
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
|
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
|
||||||
|
|
||||||
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
||||||
connect(audioMuteRightClickEnabler, SIGNAL(rightClick()), this, SLOT(audioSelect()));
|
connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect()));
|
||||||
|
|
||||||
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
||||||
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||||
|
@ -45,6 +45,11 @@ void WFMDemodSettings::resetToDefaults()
|
|||||||
m_rgbColor = QColor(0, 0, 255).rgb();
|
m_rgbColor = QColor(0, 0, 255).rgb();
|
||||||
m_title = "WFM Demodulator";
|
m_title = "WFM Demodulator";
|
||||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
|
m_useReverseAPI = false;
|
||||||
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
m_reverseAPIDeviceIndex = 0;
|
||||||
|
m_reverseAPIChannelIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray WFMDemodSettings::serialize() const
|
QByteArray WFMDemodSettings::serialize() const
|
||||||
@ -63,6 +68,11 @@ QByteArray WFMDemodSettings::serialize() const
|
|||||||
s.writeBlob(11, m_channelMarker->serialize());
|
s.writeBlob(11, m_channelMarker->serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.writeBool(12, m_useReverseAPI);
|
||||||
|
s.writeString(13, m_reverseAPIAddress);
|
||||||
|
s.writeU32(14, m_reverseAPIPort);
|
||||||
|
s.writeU32(15, m_reverseAPIDeviceIndex);
|
||||||
|
s.writeU32(16, m_reverseAPIChannelIndex);
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -81,6 +91,7 @@ bool WFMDemodSettings::deserialize(const QByteArray& data)
|
|||||||
{
|
{
|
||||||
QByteArray bytetmp;
|
QByteArray bytetmp;
|
||||||
qint32 tmp;
|
qint32 tmp;
|
||||||
|
uint32_t utmp;
|
||||||
QString strtmp;
|
QString strtmp;
|
||||||
|
|
||||||
d.readS32(1, &tmp, 0);
|
d.readS32(1, &tmp, 0);
|
||||||
@ -103,6 +114,21 @@ bool WFMDemodSettings::deserialize(const QByteArray& data)
|
|||||||
m_channelMarker->deserialize(bytetmp);
|
m_channelMarker->deserialize(bytetmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.readBool(12, &m_useReverseAPI, false);
|
||||||
|
d.readString(13, &m_reverseAPIAddress, "127.0.0.1");
|
||||||
|
d.readU32(14, &utmp, 0);
|
||||||
|
|
||||||
|
if ((utmp > 1023) && (utmp < 65535)) {
|
||||||
|
m_reverseAPIPort = utmp;
|
||||||
|
} else {
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.readU32(15, &utmp, 0);
|
||||||
|
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
d.readU32(16, &utmp, 0);
|
||||||
|
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -33,6 +33,11 @@ struct WFMDemodSettings
|
|||||||
quint32 m_rgbColor;
|
quint32 m_rgbColor;
|
||||||
QString m_title;
|
QString m_title;
|
||||||
QString m_audioDeviceName;
|
QString m_audioDeviceName;
|
||||||
|
bool m_useReverseAPI;
|
||||||
|
QString m_reverseAPIAddress;
|
||||||
|
uint16_t m_reverseAPIPort;
|
||||||
|
uint16_t m_reverseAPIDeviceIndex;
|
||||||
|
uint16_t m_reverseAPIChannelIndex;
|
||||||
|
|
||||||
Serializable *m_channelMarker;
|
Serializable *m_channelMarker;
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
const PluginDescriptor WFMPlugin::m_pluginDescriptor = {
|
const PluginDescriptor WFMPlugin::m_pluginDescriptor = {
|
||||||
QString("WFM Demodulator"),
|
QString("WFM Demodulator"),
|
||||||
QString("4.1.0"),
|
QString("4.3.2"),
|
||||||
QString("(c) Edouard Griffiths, F4EXB"),
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
QString("https://github.com/f4exb/sdrangel"),
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
|
|
||||||
#include <QUdpSocket>
|
#include <QUdpSocket>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
#include "SWGChannelSettings.h"
|
#include "SWGChannelSettings.h"
|
||||||
#include "SWGUDPSinkSettings.h"
|
#include "SWGUDPSinkSettings.h"
|
||||||
@ -110,10 +113,15 @@ UDPSink::UDPSink(DeviceSourceAPI *deviceAPI) :
|
|||||||
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
||||||
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
||||||
m_deviceAPI->addChannelAPI(this);
|
m_deviceAPI->addChannelAPI(this);
|
||||||
|
|
||||||
|
m_networkManager = new QNetworkAccessManager();
|
||||||
|
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
UDPSink::~UDPSink()
|
UDPSink::~UDPSink()
|
||||||
{
|
{
|
||||||
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
|
delete m_networkManager;
|
||||||
delete m_audioSocket;
|
delete m_audioSocket;
|
||||||
delete m_udpBuffer24;
|
delete m_udpBuffer24;
|
||||||
delete m_udpBuffer16;
|
delete m_udpBuffer16;
|
||||||
@ -505,6 +513,57 @@ void UDPSink::applySettings(const UDPSinkSettings& settings, bool force)
|
|||||||
<< " m_audioPort: " << settings.m_audioPort
|
<< " m_audioPort: " << settings.m_audioPort
|
||||||
<< " force: " << force;
|
<< " force: " << force;
|
||||||
|
|
||||||
|
QList<QString> reverseAPIKeys;
|
||||||
|
|
||||||
|
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
|
||||||
|
reverseAPIKeys.append("inputFrequencyOffset");
|
||||||
|
}
|
||||||
|
if ((settings.m_audioActive != m_settings.m_audioActive) || force) {
|
||||||
|
reverseAPIKeys.append("audioActive");
|
||||||
|
}
|
||||||
|
if ((settings.m_audioStereo != m_settings.m_audioStereo) || force) {
|
||||||
|
reverseAPIKeys.append("audioStereo");
|
||||||
|
}
|
||||||
|
if ((settings.m_gain != m_settings.m_gain) || force) {
|
||||||
|
reverseAPIKeys.append("gain");
|
||||||
|
}
|
||||||
|
if ((settings.m_volume != m_settings.m_volume) || force) {
|
||||||
|
reverseAPIKeys.append("volume");
|
||||||
|
}
|
||||||
|
if ((settings.m_squelchEnabled != m_settings.m_squelchEnabled) || force) {
|
||||||
|
reverseAPIKeys.append("squelchEnabled");
|
||||||
|
}
|
||||||
|
if ((settings.m_squelchdB != m_settings.m_squelchdB) || force) {
|
||||||
|
reverseAPIKeys.append("squelchDB");
|
||||||
|
}
|
||||||
|
if ((settings.m_squelchGate != m_settings.m_squelchGate) || force) {
|
||||||
|
reverseAPIKeys.append("squelchGate");
|
||||||
|
}
|
||||||
|
if ((settings.m_agc != m_settings.m_agc) || force) {
|
||||||
|
reverseAPIKeys.append("agc");
|
||||||
|
}
|
||||||
|
if ((settings.m_sampleFormat != m_settings.m_sampleFormat) || force) {
|
||||||
|
reverseAPIKeys.append("sampleFormat");
|
||||||
|
}
|
||||||
|
if ((settings.m_outputSampleRate != m_settings.m_outputSampleRate) || force) {
|
||||||
|
reverseAPIKeys.append("outputSampleRate");
|
||||||
|
}
|
||||||
|
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) {
|
||||||
|
reverseAPIKeys.append("rfBandwidth");
|
||||||
|
}
|
||||||
|
if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force) {
|
||||||
|
reverseAPIKeys.append("fmDeviation");
|
||||||
|
}
|
||||||
|
if ((settings.m_udpAddress != m_settings.m_udpAddress) || force) {
|
||||||
|
reverseAPIKeys.append("udpAddress");
|
||||||
|
}
|
||||||
|
if ((settings.m_udpPort != m_settings.m_udpPort) || force) {
|
||||||
|
reverseAPIKeys.append("udpPort");
|
||||||
|
}
|
||||||
|
if ((settings.m_audioPort != m_settings.m_audioPort) || force) {
|
||||||
|
reverseAPIKeys.append("audioPort");
|
||||||
|
}
|
||||||
|
|
||||||
m_settingsMutex.lock();
|
m_settingsMutex.lock();
|
||||||
|
|
||||||
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) ||
|
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) ||
|
||||||
@ -617,6 +676,16 @@ void UDPSink::applySettings(const UDPSinkSettings& settings, bool force)
|
|||||||
|
|
||||||
m_settingsMutex.unlock();
|
m_settingsMutex.unlock();
|
||||||
|
|
||||||
|
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;
|
m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -798,3 +867,108 @@ void UDPSink::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
|||||||
response.getUdpSinkReport()->setSquelch(m_squelchOpen ? 1 : 0);
|
response.getUdpSinkReport()->setSquelch(m_squelchOpen ? 1 : 0);
|
||||||
response.getUdpSinkReport()->setInputSampleRate(m_inputSampleRate);
|
response.getUdpSinkReport()->setInputSampleRate(m_inputSampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UDPSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const UDPSinkSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
|
||||||
|
swgChannelSettings->setTx(0);
|
||||||
|
swgChannelSettings->setChannelType(new QString("UDPSink"));
|
||||||
|
swgChannelSettings->setUdpSinkSettings(new SWGSDRangel::SWGUDPSinkSettings());
|
||||||
|
SWGSDRangel::SWGUDPSinkSettings *swgUDPSinkSettings = swgChannelSettings->getUdpSinkSettings();
|
||||||
|
|
||||||
|
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||||
|
|
||||||
|
if (channelSettingsKeys.contains("outputSampleRate") || force) {
|
||||||
|
swgUDPSinkSettings->setOutputSampleRate(settings.m_outputSampleRate);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("sampleFormat") || force) {
|
||||||
|
swgUDPSinkSettings->setSampleFormat((int) settings.m_sampleFormat);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
|
||||||
|
swgUDPSinkSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rfBandwidth") || force) {
|
||||||
|
swgUDPSinkSettings->setRfBandwidth(settings.m_rfBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("fmDeviation") || force) {
|
||||||
|
swgUDPSinkSettings->setFmDeviation(settings.m_fmDeviation);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("channelMute") || force) {
|
||||||
|
swgUDPSinkSettings->setChannelMute(settings.m_channelMute ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("gain") || force) {
|
||||||
|
swgUDPSinkSettings->setGain(settings.m_gain);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("squelchDB") || force) {
|
||||||
|
swgUDPSinkSettings->setSquelchDb(settings.m_squelchdB);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("squelchGate") || force) {
|
||||||
|
swgUDPSinkSettings->setSquelchGate(settings.m_squelchGate);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("squelchEnabled") || force) {
|
||||||
|
swgUDPSinkSettings->setSquelchEnabled(settings.m_squelchEnabled ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("agc") || force) {
|
||||||
|
swgUDPSinkSettings->setAgc(settings.m_agc ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioActive") || force) {
|
||||||
|
swgUDPSinkSettings->setAudioActive(settings.m_audioActive ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioStereo") || force) {
|
||||||
|
swgUDPSinkSettings->setAudioStereo(settings.m_audioStereo ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("volume") || force) {
|
||||||
|
swgUDPSinkSettings->setVolume(settings.m_volume);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("udpAddress") || force) {
|
||||||
|
swgUDPSinkSettings->setUdpAddress(new QString(settings.m_udpAddress));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("udpPort") || force) {
|
||||||
|
swgUDPSinkSettings->setUdpPort(settings.m_udpPort);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioPort") || force) {
|
||||||
|
swgUDPSinkSettings->setAudioPort(settings.m_audioPort);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||||
|
swgUDPSinkSettings->setRgbColor(settings.m_rgbColor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("title") || force) {
|
||||||
|
swgUDPSinkSettings->setTitle(new QString(settings.m_title));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||||
|
|
||||||
|
delete swgChannelSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UDPSink::networkManagerFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
QNetworkReply::NetworkError replyError = reply->error();
|
||||||
|
|
||||||
|
if (replyError)
|
||||||
|
{
|
||||||
|
qWarning() << "UDPSink::networkManagerFinished:"
|
||||||
|
<< " error(" << (int) replyError
|
||||||
|
<< "): " << replyError
|
||||||
|
<< ": " << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString answer = reply->readAll();
|
||||||
|
answer.chop(1); // remove last \n
|
||||||
|
qDebug("UDPSink::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
#include "dsp/basebandsamplesink.h"
|
#include "dsp/basebandsamplesink.h"
|
||||||
#include "channel/channelsinkapi.h"
|
#include "channel/channelsinkapi.h"
|
||||||
@ -36,6 +37,8 @@
|
|||||||
|
|
||||||
#include "udpsinksettings.h"
|
#include "udpsinksettings.h"
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QNetworkReply;
|
||||||
class QUdpSocket;
|
class QUdpSocket;
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
@ -135,6 +138,9 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
void audioReadyRead();
|
void audioReadyRead();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void networkManagerFinished(QNetworkReply *reply);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class MsgUDPSinkSpectrum : public Message {
|
class MsgUDPSinkSpectrum : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
@ -227,6 +233,9 @@ protected:
|
|||||||
MagAGC m_agc;
|
MagAGC m_agc;
|
||||||
Bandpass<double> m_bandpass;
|
Bandpass<double> m_bandpass;
|
||||||
|
|
||||||
|
QNetworkAccessManager *m_networkManager;
|
||||||
|
QNetworkRequest m_networkRequest;
|
||||||
|
|
||||||
QMutex m_settingsMutex;
|
QMutex m_settingsMutex;
|
||||||
|
|
||||||
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force = true);
|
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force = true);
|
||||||
@ -234,6 +243,7 @@ protected:
|
|||||||
|
|
||||||
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const UDPSinkSettings& settings);
|
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const UDPSinkSettings& settings);
|
||||||
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
||||||
|
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const UDPSinkSettings& settings, bool force);
|
||||||
|
|
||||||
inline void calculateSquelch(double value)
|
inline void calculateSquelch(double value)
|
||||||
{
|
{
|
||||||
|
@ -615,13 +615,23 @@ void UDPSinkGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
|||||||
void UDPSinkGUI::onMenuDialogCalled(const QPoint &p)
|
void UDPSinkGUI::onMenuDialogCalled(const QPoint &p)
|
||||||
{
|
{
|
||||||
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
|
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.move(p);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
|
|
||||||
|
|
||||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
||||||
m_settings.m_title = m_channelMarker.getTitle();
|
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);
|
setWindowTitle(m_settings.m_title);
|
||||||
setTitleColor(m_settings.m_rgbColor);
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
const PluginDescriptor UDPSinkPlugin::m_pluginDescriptor = {
|
const PluginDescriptor UDPSinkPlugin::m_pluginDescriptor = {
|
||||||
QString("UDP Channel Sink"),
|
QString("UDP Channel Sink"),
|
||||||
QString("4.1.0"),
|
QString("4.3.2"),
|
||||||
QString("(c) Edouard Griffiths, F4EXB"),
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
QString("https://github.com/f4exb/sdrangel"),
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -49,6 +49,11 @@ void UDPSinkSettings::resetToDefaults()
|
|||||||
m_audioPort = 9997;
|
m_audioPort = 9997;
|
||||||
m_rgbColor = QColor(225, 25, 99).rgb();
|
m_rgbColor = QColor(225, 25, 99).rgb();
|
||||||
m_title = "UDP Sample Sink";
|
m_title = "UDP Sample Sink";
|
||||||
|
m_useReverseAPI = false;
|
||||||
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
m_reverseAPIDeviceIndex = 0;
|
||||||
|
m_reverseAPIChannelIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray UDPSinkSettings::serialize() const
|
QByteArray UDPSinkSettings::serialize() const
|
||||||
@ -80,6 +85,11 @@ QByteArray UDPSinkSettings::serialize() const
|
|||||||
s.writeString(20, m_udpAddress);
|
s.writeString(20, m_udpAddress);
|
||||||
s.writeU32(21, m_udpPort);
|
s.writeU32(21, m_udpPort);
|
||||||
s.writeU32(22, m_audioPort);
|
s.writeU32(22, m_audioPort);
|
||||||
|
s.writeBool(23, m_useReverseAPI);
|
||||||
|
s.writeString(24, m_reverseAPIAddress);
|
||||||
|
s.writeU32(25, m_reverseAPIPort);
|
||||||
|
s.writeU32(26, m_reverseAPIDeviceIndex);
|
||||||
|
s.writeU32(27, m_reverseAPIChannelIndex);
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
|
|
||||||
@ -155,6 +165,21 @@ bool UDPSinkSettings::deserialize(const QByteArray& data)
|
|||||||
m_audioPort = 9997;
|
m_audioPort = 9997;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.readBool(23, &m_useReverseAPI, false);
|
||||||
|
d.readString(24, &m_reverseAPIAddress, "127.0.0.1");
|
||||||
|
d.readU32(25, &u32tmp, 0);
|
||||||
|
|
||||||
|
if ((u32tmp > 1023) && (u32tmp < 65535)) {
|
||||||
|
m_reverseAPIPort = u32tmp;
|
||||||
|
} else {
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.readU32(26, &u32tmp, 0);
|
||||||
|
m_reverseAPIDeviceIndex = u32tmp > 99 ? 99 : u32tmp;
|
||||||
|
d.readU32(27, &u32tmp, 0);
|
||||||
|
m_reverseAPIChannelIndex = u32tmp > 99 ? 99 : u32tmp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -62,6 +62,12 @@ struct UDPSinkSettings
|
|||||||
|
|
||||||
QString m_title;
|
QString m_title;
|
||||||
|
|
||||||
|
bool m_useReverseAPI;
|
||||||
|
QString m_reverseAPIAddress;
|
||||||
|
uint16_t m_reverseAPIPort;
|
||||||
|
uint16_t m_reverseAPIDeviceIndex;
|
||||||
|
uint16_t m_reverseAPIChannelIndex;
|
||||||
|
|
||||||
Serializable *m_channelMarker;
|
Serializable *m_channelMarker;
|
||||||
Serializable *m_spectrumGUI;
|
Serializable *m_spectrumGUI;
|
||||||
|
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
#include <boost/cstdint.hpp>
|
#include <boost/cstdint.hpp>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
#include "SWGChannelSettings.h"
|
#include "SWGChannelSettings.h"
|
||||||
#include "SWGChannelReport.h"
|
#include "SWGChannelReport.h"
|
||||||
@ -59,10 +62,15 @@ DaemonSource::DaemonSource(DeviceSinkAPI *deviceAPI) :
|
|||||||
m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this);
|
m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this);
|
||||||
m_deviceAPI->addThreadedSource(m_threadedChannelizer);
|
m_deviceAPI->addThreadedSource(m_threadedChannelizer);
|
||||||
m_deviceAPI->addChannelAPI(this);
|
m_deviceAPI->addChannelAPI(this);
|
||||||
|
|
||||||
|
m_networkManager = new QNetworkAccessManager();
|
||||||
|
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
DaemonSource::~DaemonSource()
|
DaemonSource::~DaemonSource()
|
||||||
{
|
{
|
||||||
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
|
delete m_networkManager;
|
||||||
m_deviceAPI->removeChannelAPI(this);
|
m_deviceAPI->removeChannelAPI(this);
|
||||||
m_deviceAPI->removeThreadedSource(m_threadedChannelizer);
|
m_deviceAPI->removeThreadedSource(m_threadedChannelizer);
|
||||||
delete m_threadedChannelizer;
|
delete m_threadedChannelizer;
|
||||||
@ -201,19 +209,36 @@ void DaemonSource::applySettings(const DaemonSourceSettings& settings, bool forc
|
|||||||
<< " force: " << force;
|
<< " force: " << force;
|
||||||
|
|
||||||
bool change = false;
|
bool change = false;
|
||||||
|
QList<QString> reverseAPIKeys;
|
||||||
|
|
||||||
if ((m_settings.m_dataAddress != settings.m_dataAddress) || force) {
|
if ((m_settings.m_dataAddress != settings.m_dataAddress) || force)
|
||||||
|
{
|
||||||
|
reverseAPIKeys.append("dataAddress");
|
||||||
change = true;
|
change = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_settings.m_dataPort != settings.m_dataPort) || force) {
|
if ((m_settings.m_dataPort != settings.m_dataPort) || force)
|
||||||
|
{
|
||||||
|
reverseAPIKeys.append("dataPort");
|
||||||
change = true;
|
change = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (change && m_sourceThread) {
|
if (change && m_sourceThread)
|
||||||
|
{
|
||||||
|
reverseAPIKeys.append("sourceThread");
|
||||||
m_sourceThread->dataBind(settings.m_dataAddress, settings.m_dataPort);
|
m_sourceThread->dataBind(settings.m_dataAddress, settings.m_dataPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,6 +417,21 @@ int DaemonSource::webapiSettingsPutPatch(
|
|||||||
if (channelSettingsKeys.contains("title")) {
|
if (channelSettingsKeys.contains("title")) {
|
||||||
settings.m_title = *response.getDaemonSourceSettings()->getTitle();
|
settings.m_title = *response.getDaemonSourceSettings()->getTitle();
|
||||||
}
|
}
|
||||||
|
if (channelSettingsKeys.contains("useReverseAPI")) {
|
||||||
|
settings.m_useReverseAPI = response.getDaemonSourceSettings()->getUseReverseApi() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIAddress")) {
|
||||||
|
settings.m_reverseAPIAddress = *response.getDaemonSourceSettings()->getReverseApiAddress() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIPort")) {
|
||||||
|
settings.m_reverseAPIPort = response.getDaemonSourceSettings()->getReverseApiPort();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
|
||||||
|
settings.m_reverseAPIDeviceIndex = response.getDaemonSourceSettings()->getReverseApiDeviceIndex();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
|
||||||
|
settings.m_reverseAPIChannelIndex = response.getDaemonSourceSettings()->getReverseApiChannelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
MsgConfigureDaemonSource *msg = MsgConfigureDaemonSource::create(settings, force);
|
MsgConfigureDaemonSource *msg = MsgConfigureDaemonSource::create(settings, force);
|
||||||
m_inputMessageQueue.push(msg);
|
m_inputMessageQueue.push(msg);
|
||||||
@ -435,6 +475,18 @@ void DaemonSource::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings&
|
|||||||
} else {
|
} else {
|
||||||
response.getDaemonSourceSettings()->setTitle(new QString(settings.m_title));
|
response.getDaemonSourceSettings()->setTitle(new QString(settings.m_title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response.getDaemonSourceSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
|
||||||
|
|
||||||
|
if (response.getDaemonSourceSettings()->getReverseApiAddress()) {
|
||||||
|
*response.getDaemonSourceSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
|
||||||
|
} else {
|
||||||
|
response.getDaemonSourceSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
response.getDaemonSourceSettings()->setReverseApiPort(settings.m_reverseAPIPort);
|
||||||
|
response.getDaemonSourceSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
|
||||||
|
response.getDaemonSourceSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DaemonSource::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
void DaemonSource::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
||||||
@ -457,3 +509,62 @@ void DaemonSource::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& resp
|
|||||||
response.getDaemonSourceReport()->setDeviceSampleRate(m_deviceAPI->getSampleSink()->getSampleRate());
|
response.getDaemonSourceReport()->setDeviceSampleRate(m_deviceAPI->getSampleSink()->getSampleRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DaemonSource::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const DaemonSourceSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
|
||||||
|
swgChannelSettings->setTx(1);
|
||||||
|
swgChannelSettings->setChannelType(new QString("DaemonSource"));
|
||||||
|
swgChannelSettings->setDaemonSourceSettings(new SWGSDRangel::SWGDaemonSourceSettings());
|
||||||
|
SWGSDRangel::SWGDaemonSourceSettings *swgDaemonSourceSettings = swgChannelSettings->getDaemonSourceSettings();
|
||||||
|
|
||||||
|
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||||
|
|
||||||
|
if (channelSettingsKeys.contains("dataAddress") || force) {
|
||||||
|
swgDaemonSourceSettings->setDataAddress(new QString(settings.m_dataAddress));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("dataPort") || force) {
|
||||||
|
swgDaemonSourceSettings->setDataPort(settings.m_dataPort);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||||
|
swgDaemonSourceSettings->setRgbColor(settings.m_rgbColor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("title") || force) {
|
||||||
|
swgDaemonSourceSettings->setTitle(new QString(settings.m_title));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||||
|
|
||||||
|
delete swgChannelSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonSource::networkManagerFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
QNetworkReply::NetworkError replyError = reply->error();
|
||||||
|
|
||||||
|
if (replyError)
|
||||||
|
{
|
||||||
|
qWarning() << "DaemonSource::networkManagerFinished:"
|
||||||
|
<< " error(" << (int) replyError
|
||||||
|
<< "): " << replyError
|
||||||
|
<< ": " << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString answer = reply->readAll();
|
||||||
|
answer.chop(1); // remove last \n
|
||||||
|
qDebug("DaemonSource::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#define PLUGINS_CHANNELTX_DAEMONSRC_DAEMONSRC_H_
|
#define PLUGINS_CHANNELTX_DAEMONSRC_DAEMONSRC_H_
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
#include "cm256.h"
|
#include "cm256.h"
|
||||||
|
|
||||||
@ -35,6 +36,8 @@ class UpChannelizer;
|
|||||||
class DeviceSinkAPI;
|
class DeviceSinkAPI;
|
||||||
class DaemonSourceThread;
|
class DaemonSourceThread;
|
||||||
class SDRDaemonDataBlock;
|
class SDRDaemonDataBlock;
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QNetworkReply;
|
||||||
|
|
||||||
class DaemonSource : public BasebandSampleSource, public ChannelSourceAPI {
|
class DaemonSource : public BasebandSampleSource, public ChannelSourceAPI {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -233,14 +236,19 @@ private:
|
|||||||
uint32_t m_nbCorrectableErrors; //!< count of correctable errors in number of blocks
|
uint32_t m_nbCorrectableErrors; //!< count of correctable errors in number of blocks
|
||||||
uint32_t m_nbUncorrectableErrors; //!< count of uncorrectable errors in number of blocks
|
uint32_t m_nbUncorrectableErrors; //!< count of uncorrectable errors in number of blocks
|
||||||
|
|
||||||
|
QNetworkAccessManager *m_networkManager;
|
||||||
|
QNetworkRequest m_networkRequest;
|
||||||
|
|
||||||
void applySettings(const DaemonSourceSettings& settings, bool force = false);
|
void applySettings(const DaemonSourceSettings& settings, bool force = false);
|
||||||
void handleDataBlock(SDRDaemonDataBlock *dataBlock);
|
void handleDataBlock(SDRDaemonDataBlock *dataBlock);
|
||||||
void printMeta(const QString& header, SDRDaemonMetaDataFEC *metaData);
|
void printMeta(const QString& header, SDRDaemonMetaDataFEC *metaData);
|
||||||
uint32_t calculateDataReadQueueSize(int sampleRate);
|
uint32_t calculateDataReadQueueSize(int sampleRate);
|
||||||
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const DaemonSourceSettings& settings);
|
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const DaemonSourceSettings& settings);
|
||||||
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
||||||
|
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const DaemonSourceSettings& settings, bool force);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void networkManagerFinished(QNetworkReply *reply);
|
||||||
void handleData();
|
void handleData();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -273,11 +273,22 @@ void DaemonSourceGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
|||||||
void DaemonSourceGUI::onMenuDialogCalled(const QPoint &p)
|
void DaemonSourceGUI::onMenuDialogCalled(const QPoint &p)
|
||||||
{
|
{
|
||||||
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
|
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.move(p);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
|
|
||||||
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
||||||
m_settings.m_title = m_channelMarker.getTitle();
|
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);
|
setWindowTitle(m_settings.m_title);
|
||||||
setTitleColor(m_settings.m_rgbColor);
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
const PluginDescriptor DaemonSourcePlugin::m_pluginDescriptor = {
|
const PluginDescriptor DaemonSourcePlugin::m_pluginDescriptor = {
|
||||||
QString("Daemon channel source"),
|
QString("Daemon channel source"),
|
||||||
QString("4.1.0"),
|
QString("4.3.2"),
|
||||||
QString("(c) Edouard Griffiths, F4EXB"),
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
QString("https://github.com/f4exb/sdrangel"),
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -32,6 +32,11 @@ void DaemonSourceSettings::resetToDefaults()
|
|||||||
m_rgbColor = QColor(140, 4, 4).rgb();
|
m_rgbColor = QColor(140, 4, 4).rgb();
|
||||||
m_title = "Daemon source";
|
m_title = "Daemon source";
|
||||||
m_channelMarker = nullptr;
|
m_channelMarker = nullptr;
|
||||||
|
m_useReverseAPI = false;
|
||||||
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
m_reverseAPIDeviceIndex = 0;
|
||||||
|
m_reverseAPIChannelIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray DaemonSourceSettings::serialize() const
|
QByteArray DaemonSourceSettings::serialize() const
|
||||||
@ -41,6 +46,11 @@ QByteArray DaemonSourceSettings::serialize() const
|
|||||||
s.writeU32(2, m_dataPort);
|
s.writeU32(2, m_dataPort);
|
||||||
s.writeU32(3, m_rgbColor);
|
s.writeU32(3, m_rgbColor);
|
||||||
s.writeString(4, m_title);
|
s.writeString(4, m_title);
|
||||||
|
s.writeBool(5, m_useReverseAPI);
|
||||||
|
s.writeString(6, m_reverseAPIAddress);
|
||||||
|
s.writeU32(7, m_reverseAPIPort);
|
||||||
|
s.writeU32(8, m_reverseAPIDeviceIndex);
|
||||||
|
s.writeU32(9, m_reverseAPIChannelIndex);
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -71,7 +81,20 @@ bool DaemonSourceSettings::deserialize(const QByteArray& data)
|
|||||||
|
|
||||||
d.readU32(3, &m_rgbColor, QColor(0, 255, 255).rgb());
|
d.readU32(3, &m_rgbColor, QColor(0, 255, 255).rgb());
|
||||||
d.readString(4, &m_title, "Daemon source");
|
d.readString(4, &m_title, "Daemon source");
|
||||||
|
d.readBool(5, &m_useReverseAPI, false);
|
||||||
|
d.readString(6, &m_reverseAPIAddress, "127.0.0.1");
|
||||||
|
d.readU32(7, &tmp, 0);
|
||||||
|
|
||||||
|
if ((tmp > 1023) && (tmp < 65535)) {
|
||||||
|
m_reverseAPIPort = tmp;
|
||||||
|
} else {
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.readU32(8, &tmp, 0);
|
||||||
|
m_reverseAPIDeviceIndex = tmp > 99 ? 99 : tmp;
|
||||||
|
d.readU32(9, &tmp, 0);
|
||||||
|
m_reverseAPIChannelIndex = tmp > 99 ? 99 : tmp;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -28,6 +28,11 @@ struct DaemonSourceSettings
|
|||||||
uint16_t m_dataPort; //!< Listening data port
|
uint16_t m_dataPort; //!< Listening data port
|
||||||
quint32 m_rgbColor;
|
quint32 m_rgbColor;
|
||||||
QString m_title;
|
QString m_title;
|
||||||
|
bool m_useReverseAPI;
|
||||||
|
QString m_reverseAPIAddress;
|
||||||
|
uint16_t m_reverseAPIPort;
|
||||||
|
uint16_t m_reverseAPIDeviceIndex;
|
||||||
|
uint16_t m_reverseAPIChannelIndex;
|
||||||
|
|
||||||
Serializable *m_channelMarker;
|
Serializable *m_channelMarker;
|
||||||
|
|
||||||
|
@ -14,19 +14,22 @@
|
|||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "ammod.h"
|
#include <stdio.h>
|
||||||
|
#include <complex.h>
|
||||||
|
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QMutexLocker>
|
#include <QMutexLocker>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
#include <stdio.h>
|
#include <QNetworkReply>
|
||||||
#include <complex.h>
|
#include <QBuffer>
|
||||||
|
|
||||||
#include "SWGChannelSettings.h"
|
#include "SWGChannelSettings.h"
|
||||||
#include "SWGChannelReport.h"
|
#include "SWGChannelReport.h"
|
||||||
#include "SWGAMModReport.h"
|
#include "SWGAMModReport.h"
|
||||||
|
|
||||||
|
#include "ammod.h"
|
||||||
|
|
||||||
#include "dsp/upchannelizer.h"
|
#include "dsp/upchannelizer.h"
|
||||||
#include "dsp/dspengine.h"
|
#include "dsp/dspengine.h"
|
||||||
#include "dsp/threadedbasebandsamplesource.h"
|
#include "dsp/threadedbasebandsamplesource.h"
|
||||||
@ -84,10 +87,15 @@ AMMod::AMMod(DeviceSinkAPI *deviceAPI) :
|
|||||||
m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this);
|
m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this);
|
||||||
m_deviceAPI->addThreadedSource(m_threadedChannelizer);
|
m_deviceAPI->addThreadedSource(m_threadedChannelizer);
|
||||||
m_deviceAPI->addChannelAPI(this);
|
m_deviceAPI->addChannelAPI(this);
|
||||||
|
|
||||||
|
m_networkManager = new QNetworkAccessManager();
|
||||||
|
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
AMMod::~AMMod()
|
AMMod::~AMMod()
|
||||||
{
|
{
|
||||||
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
|
delete m_networkManager;
|
||||||
m_deviceAPI->removeChannelAPI(this);
|
m_deviceAPI->removeChannelAPI(this);
|
||||||
m_deviceAPI->removeThreadedSource(m_threadedChannelizer);
|
m_deviceAPI->removeThreadedSource(m_threadedChannelizer);
|
||||||
delete m_threadedChannelizer;
|
delete m_threadedChannelizer;
|
||||||
@ -332,6 +340,16 @@ bool AMMod::handleMessage(const Message& cmd)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if (CWKeyer::MsgConfigureCWKeyer::match(cmd))
|
||||||
|
{
|
||||||
|
const CWKeyer::MsgConfigureCWKeyer& cfg = (CWKeyer::MsgConfigureCWKeyer&) cmd;
|
||||||
|
|
||||||
|
if (m_settings.m_useReverseAPI) {
|
||||||
|
webapiReverseSendCWSettings(cfg.getSettings());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
else if (DSPConfigureAudio::match(cmd))
|
else if (DSPConfigureAudio::match(cmd))
|
||||||
{
|
{
|
||||||
DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
|
DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
|
||||||
@ -451,14 +469,46 @@ void AMMod::applySettings(const AMModSettings& settings, bool force)
|
|||||||
<< " m_modFactor: " << settings.m_modFactor
|
<< " m_modFactor: " << settings.m_modFactor
|
||||||
<< " m_toneFrequency: " << settings.m_toneFrequency
|
<< " m_toneFrequency: " << settings.m_toneFrequency
|
||||||
<< " m_volumeFactor: " << settings.m_volumeFactor
|
<< " m_volumeFactor: " << settings.m_volumeFactor
|
||||||
<< " m_audioMute: " << settings.m_channelMute
|
<< " m_channelMute: " << settings.m_channelMute
|
||||||
<< " m_playLoop: " << settings.m_playLoop
|
<< " m_playLoop: " << settings.m_playLoop
|
||||||
<< " m_modAFInput " << settings.m_modAFInput
|
<< " m_modAFInput " << settings.m_modAFInput
|
||||||
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
||||||
|
<< " m_useReverseAPI: " << settings.m_useReverseAPI
|
||||||
|
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
|
||||||
|
<< " m_reverseAPIAddress: " << settings.m_reverseAPIPort
|
||||||
|
<< " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex
|
||||||
|
<< " m_reverseAPIChannelIndex: " << settings.m_reverseAPIChannelIndex
|
||||||
<< " force: " << force;
|
<< " force: " << force;
|
||||||
|
|
||||||
if((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
|
QList<QString> reverseAPIKeys;
|
||||||
|
|
||||||
|
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
|
||||||
|
reverseAPIKeys.append("inputFrequencyOffset");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((settings.m_modFactor != m_settings.m_modFactor) || force) {
|
||||||
|
reverseAPIKeys.append("modFactor");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((settings.m_volumeFactor != m_settings.m_volumeFactor) || force) {
|
||||||
|
reverseAPIKeys.append("volumeFactor");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((settings.m_channelMute != m_settings.m_channelMute) || force) {
|
||||||
|
reverseAPIKeys.append("channelMute");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((settings.m_playLoop != m_settings.m_playLoop) || force) {
|
||||||
|
reverseAPIKeys.append("playLoop");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((settings.m_modAFInput != m_settings.m_modAFInput) || force) {
|
||||||
|
reverseAPIKeys.append("modAFInput");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("rfBandwidth");
|
||||||
m_settingsMutex.lock();
|
m_settingsMutex.lock();
|
||||||
m_interpolatorDistanceRemain = 0;
|
m_interpolatorDistanceRemain = 0;
|
||||||
m_interpolatorConsumed = false;
|
m_interpolatorConsumed = false;
|
||||||
@ -469,6 +519,7 @@ void AMMod::applySettings(const AMModSettings& settings, bool force)
|
|||||||
|
|
||||||
if ((settings.m_toneFrequency != m_settings.m_toneFrequency) || force)
|
if ((settings.m_toneFrequency != m_settings.m_toneFrequency) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("toneFrequency");
|
||||||
m_settingsMutex.lock();
|
m_settingsMutex.lock();
|
||||||
m_toneNco.setFreq(settings.m_toneFrequency, m_audioSampleRate);
|
m_toneNco.setFreq(settings.m_toneFrequency, m_audioSampleRate);
|
||||||
m_settingsMutex.unlock();
|
m_settingsMutex.unlock();
|
||||||
@ -476,16 +527,28 @@ void AMMod::applySettings(const AMModSettings& settings, bool force)
|
|||||||
|
|
||||||
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
|
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
|
||||||
{
|
{
|
||||||
|
reverseAPIKeys.append("audioDeviceName");
|
||||||
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
||||||
int audioDeviceIndex = audioDeviceManager->getInputDeviceIndex(settings.m_audioDeviceName);
|
int audioDeviceIndex = audioDeviceManager->getInputDeviceIndex(settings.m_audioDeviceName);
|
||||||
audioDeviceManager->addAudioSource(&m_audioFifo, getInputMessageQueue(), audioDeviceIndex);
|
audioDeviceManager->addAudioSource(&m_audioFifo, getInputMessageQueue(), audioDeviceIndex);
|
||||||
uint32_t audioSampleRate = audioDeviceManager->getInputSampleRate(audioDeviceIndex);
|
uint32_t audioSampleRate = audioDeviceManager->getInputSampleRate(audioDeviceIndex);
|
||||||
|
|
||||||
if (m_audioSampleRate != audioSampleRate) {
|
if (m_audioSampleRate != audioSampleRate) {
|
||||||
|
reverseAPIKeys.append("audioSampleRate");
|
||||||
applyAudioSampleRate(audioSampleRate);
|
applyAudioSampleRate(audioSampleRate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,6 +630,21 @@ int AMMod::webapiSettingsPutPatch(
|
|||||||
if (channelSettingsKeys.contains("modFactor")) {
|
if (channelSettingsKeys.contains("modFactor")) {
|
||||||
settings.m_modFactor = response.getAmModSettings()->getModFactor();
|
settings.m_modFactor = response.getAmModSettings()->getModFactor();
|
||||||
}
|
}
|
||||||
|
if (channelSettingsKeys.contains("useReverseAPI")) {
|
||||||
|
settings.m_useReverseAPI = response.getAmModSettings()->getUseReverseApi() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIAddress")) {
|
||||||
|
settings.m_reverseAPIAddress = *response.getAmModSettings()->getReverseApiAddress() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIPort")) {
|
||||||
|
settings.m_reverseAPIPort = response.getAmModSettings()->getReverseApiPort();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
|
||||||
|
settings.m_reverseAPIDeviceIndex = response.getAmModSettings()->getReverseApiDeviceIndex();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
|
||||||
|
settings.m_reverseAPIChannelIndex = response.getAmModSettings()->getReverseApiChannelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
if (channelSettingsKeys.contains("cwKeyer"))
|
if (channelSettingsKeys.contains("cwKeyer"))
|
||||||
{
|
{
|
||||||
@ -676,6 +754,18 @@ void AMMod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& respons
|
|||||||
} else {
|
} else {
|
||||||
response.getAmModSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
response.getAmModSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response.getAmModSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
|
||||||
|
|
||||||
|
if (response.getAmModSettings()->getReverseApiAddress()) {
|
||||||
|
*response.getAmModSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
|
||||||
|
} else {
|
||||||
|
response.getAmModSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
response.getAmModSettings()->setReverseApiPort(settings.m_reverseAPIPort);
|
||||||
|
response.getAmModSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
|
||||||
|
response.getAmModSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AMMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
void AMMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
||||||
@ -684,3 +774,131 @@ void AMMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
|||||||
response.getAmModReport()->setAudioSampleRate(m_audioSampleRate);
|
response.getAmModReport()->setAudioSampleRate(m_audioSampleRate);
|
||||||
response.getAmModReport()->setChannelSampleRate(m_outputSampleRate);
|
response.getAmModReport()->setChannelSampleRate(m_outputSampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AMMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const AMModSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
|
||||||
|
swgChannelSettings->setTx(1);
|
||||||
|
swgChannelSettings->setChannelType(new QString("AMMod"));
|
||||||
|
swgChannelSettings->setAmModSettings(new SWGSDRangel::SWGAMModSettings());
|
||||||
|
SWGSDRangel::SWGAMModSettings *swgAMModSettings = swgChannelSettings->getAmModSettings();
|
||||||
|
|
||||||
|
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||||
|
|
||||||
|
if (channelSettingsKeys.contains("channelMute") || force) {
|
||||||
|
swgAMModSettings->setChannelMute(settings.m_channelMute ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
|
||||||
|
swgAMModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("modAFInput") || force) {
|
||||||
|
swgAMModSettings->setModAfInput((int) settings.m_modAFInput);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("audioDeviceName") || force) {
|
||||||
|
swgAMModSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("playLoop") || force) {
|
||||||
|
swgAMModSettings->setPlayLoop(settings.m_playLoop ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rfBandwidth") || force) {
|
||||||
|
swgAMModSettings->setRfBandwidth(settings.m_rfBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||||
|
swgAMModSettings->setRgbColor(settings.m_rgbColor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("title") || force) {
|
||||||
|
swgAMModSettings->setTitle(new QString(settings.m_title));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("toneFrequency") || force) {
|
||||||
|
swgAMModSettings->setToneFrequency(settings.m_toneFrequency);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("volumeFactor") || force) {
|
||||||
|
swgAMModSettings->setVolumeFactor(settings.m_volumeFactor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("modFactor") || force) {
|
||||||
|
swgAMModSettings->setModFactor(settings.m_modFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (force)
|
||||||
|
{
|
||||||
|
const CWKeyerSettings& cwKeyerSettings = m_cwKeyer.getSettings();
|
||||||
|
swgAMModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
|
||||||
|
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgAMModSettings->getCwKeyer();
|
||||||
|
apiCwKeyerSettings->setLoop(cwKeyerSettings.m_loop ? 1 : 0);
|
||||||
|
apiCwKeyerSettings->setMode(cwKeyerSettings.m_mode);
|
||||||
|
apiCwKeyerSettings->setSampleRate(cwKeyerSettings.m_sampleRate);
|
||||||
|
apiCwKeyerSettings->setText(new QString(cwKeyerSettings.m_text));
|
||||||
|
apiCwKeyerSettings->setWpm(cwKeyerSettings.m_wpm);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||||
|
|
||||||
|
delete swgChannelSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AMMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
|
||||||
|
swgChannelSettings->setTx(1);
|
||||||
|
swgChannelSettings->setChannelType(new QString("AMMod"));
|
||||||
|
swgChannelSettings->setAmModSettings(new SWGSDRangel::SWGAMModSettings());
|
||||||
|
SWGSDRangel::SWGAMModSettings *swgAMModSettings = swgChannelSettings->getAmModSettings();
|
||||||
|
|
||||||
|
swgAMModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
|
||||||
|
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgAMModSettings->getCwKeyer();
|
||||||
|
apiCwKeyerSettings->setLoop(cwKeyerSettings.m_loop ? 1 : 0);
|
||||||
|
apiCwKeyerSettings->setMode(cwKeyerSettings.m_mode);
|
||||||
|
apiCwKeyerSettings->setSampleRate(cwKeyerSettings.m_sampleRate);
|
||||||
|
apiCwKeyerSettings->setText(new QString(cwKeyerSettings.m_text));
|
||||||
|
apiCwKeyerSettings->setWpm(cwKeyerSettings.m_wpm);
|
||||||
|
|
||||||
|
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
|
||||||
|
.arg(m_settings.m_reverseAPIAddress)
|
||||||
|
.arg(m_settings.m_reverseAPIPort)
|
||||||
|
.arg(m_settings.m_reverseAPIDeviceIndex)
|
||||||
|
.arg(m_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
|
||||||
|
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||||
|
|
||||||
|
delete swgChannelSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AMMod::networkManagerFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
QNetworkReply::NetworkError replyError = reply->error();
|
||||||
|
|
||||||
|
if (replyError)
|
||||||
|
{
|
||||||
|
qWarning() << "AMMod::networkManagerFinished:"
|
||||||
|
<< " error(" << (int) replyError
|
||||||
|
<< "): " << replyError
|
||||||
|
<< ": " << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString answer = reply->readAll();
|
||||||
|
answer.chop(1); // remove last \n
|
||||||
|
qDebug("AMMod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||||
|
}
|
||||||
|
@ -17,11 +17,13 @@
|
|||||||
#ifndef PLUGINS_CHANNELTX_MODAM_AMMOD_H_
|
#ifndef PLUGINS_CHANNELTX_MODAM_AMMOD_H_
|
||||||
#define PLUGINS_CHANNELTX_MODAM_AMMOD_H_
|
#define PLUGINS_CHANNELTX_MODAM_AMMOD_H_
|
||||||
|
|
||||||
#include <QMutex>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
#include "dsp/basebandsamplesource.h"
|
#include "dsp/basebandsamplesource.h"
|
||||||
#include "channel/channelsourceapi.h"
|
#include "channel/channelsourceapi.h"
|
||||||
#include "dsp/nco.h"
|
#include "dsp/nco.h"
|
||||||
@ -35,6 +37,8 @@
|
|||||||
|
|
||||||
#include "ammodsettings.h"
|
#include "ammodsettings.h"
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QNetworkReply;
|
||||||
class ThreadedBasebandSampleSource;
|
class ThreadedBasebandSampleSource;
|
||||||
class UpChannelizer;
|
class UpChannelizer;
|
||||||
class DeviceSinkAPI;
|
class DeviceSinkAPI;
|
||||||
@ -291,6 +295,9 @@ private:
|
|||||||
|
|
||||||
static const int m_levelNbSamples;
|
static const int m_levelNbSamples;
|
||||||
|
|
||||||
|
QNetworkAccessManager *m_networkManager;
|
||||||
|
QNetworkRequest m_networkRequest;
|
||||||
|
|
||||||
void applyAudioSampleRate(int sampleRate);
|
void applyAudioSampleRate(int sampleRate);
|
||||||
void applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force = false);
|
void applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force = false);
|
||||||
void applySettings(const AMModSettings& settings, bool force = false);
|
void applySettings(const AMModSettings& settings, bool force = false);
|
||||||
@ -301,6 +308,11 @@ private:
|
|||||||
void seekFileStream(int seekPercentage);
|
void seekFileStream(int seekPercentage);
|
||||||
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const AMModSettings& settings);
|
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const AMModSettings& settings);
|
||||||
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
||||||
|
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const AMModSettings& settings, bool force);
|
||||||
|
void webapiReverseSendCWSettings(const CWKeyerSettings& settings);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void networkManagerFinished(QNetworkReply *reply);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -279,12 +279,22 @@ void AMModGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
|||||||
void AMModGUI::onMenuDialogCalled(const QPoint &p)
|
void AMModGUI::onMenuDialogCalled(const QPoint &p)
|
||||||
{
|
{
|
||||||
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
|
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.move(p);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
|
|
||||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
||||||
m_settings.m_title = m_channelMarker.getTitle();
|
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);
|
setWindowTitle(m_settings.m_title);
|
||||||
setTitleColor(m_settings.m_rgbColor);
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
@ -316,7 +326,7 @@ AMModGUI::AMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampl
|
|||||||
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
|
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
|
||||||
|
|
||||||
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->mic);
|
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->mic);
|
||||||
connect(audioMuteRightClickEnabler, SIGNAL(rightClick()), this, SLOT(audioSelect()));
|
connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect()));
|
||||||
|
|
||||||
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
||||||
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
const PluginDescriptor AMModPlugin::m_pluginDescriptor = {
|
const PluginDescriptor AMModPlugin::m_pluginDescriptor = {
|
||||||
QString("AM Modulator"),
|
QString("AM Modulator"),
|
||||||
QString("4.1.0"),
|
QString("4.3.2"),
|
||||||
QString("(c) Edouard Griffiths, F4EXB"),
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
QString("https://github.com/f4exb/sdrangel"),
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -41,6 +41,11 @@ void AMModSettings::resetToDefaults()
|
|||||||
m_title = "AM Modulator";
|
m_title = "AM Modulator";
|
||||||
m_modAFInput = AMModInputAF::AMModInputNone;
|
m_modAFInput = AMModInputAF::AMModInputNone;
|
||||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||||
|
m_useReverseAPI = false;
|
||||||
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
m_reverseAPIDeviceIndex = 0;
|
||||||
|
m_reverseAPIChannelIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray AMModSettings::serialize() const
|
QByteArray AMModSettings::serialize() const
|
||||||
@ -65,6 +70,11 @@ QByteArray AMModSettings::serialize() const
|
|||||||
s.writeString(9, m_title);
|
s.writeString(9, m_title);
|
||||||
s.writeString(10, m_audioDeviceName);
|
s.writeString(10, m_audioDeviceName);
|
||||||
s.writeS32(11, (int) m_modAFInput);
|
s.writeS32(11, (int) m_modAFInput);
|
||||||
|
s.writeBool(12, m_useReverseAPI);
|
||||||
|
s.writeString(13, m_reverseAPIAddress);
|
||||||
|
s.writeU32(14, m_reverseAPIPort);
|
||||||
|
s.writeU32(15, m_reverseAPIDeviceIndex);
|
||||||
|
s.writeU32(16, m_reverseAPIChannelIndex);
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -83,6 +93,7 @@ bool AMModSettings::deserialize(const QByteArray& data)
|
|||||||
{
|
{
|
||||||
QByteArray bytetmp;
|
QByteArray bytetmp;
|
||||||
qint32 tmp;
|
qint32 tmp;
|
||||||
|
uint32_t utmp;
|
||||||
|
|
||||||
d.readS32(1, &tmp, 0);
|
d.readS32(1, &tmp, 0);
|
||||||
m_inputFrequencyOffset = tmp;
|
m_inputFrequencyOffset = tmp;
|
||||||
@ -112,6 +123,21 @@ bool AMModSettings::deserialize(const QByteArray& data)
|
|||||||
m_modAFInput = (AMModInputAF) tmp;
|
m_modAFInput = (AMModInputAF) tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.readBool(12, &m_useReverseAPI, false);
|
||||||
|
d.readString(13, &m_reverseAPIAddress, "127.0.0.1");
|
||||||
|
d.readU32(14, &utmp, 0);
|
||||||
|
|
||||||
|
if ((utmp > 1023) && (utmp < 65535)) {
|
||||||
|
m_reverseAPIPort = utmp;
|
||||||
|
} else {
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.readU32(15, &utmp, 0);
|
||||||
|
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
d.readU32(16, &utmp, 0);
|
||||||
|
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -43,6 +43,11 @@ struct AMModSettings
|
|||||||
QString m_title;
|
QString m_title;
|
||||||
AMModInputAF m_modAFInput;
|
AMModInputAF m_modAFInput;
|
||||||
QString m_audioDeviceName;
|
QString m_audioDeviceName;
|
||||||
|
bool m_useReverseAPI;
|
||||||
|
QString m_reverseAPIAddress;
|
||||||
|
uint16_t m_reverseAPIPort;
|
||||||
|
uint16_t m_reverseAPIDeviceIndex;
|
||||||
|
uint16_t m_reverseAPIChannelIndex;
|
||||||
|
|
||||||
Serializable *m_channelMarker;
|
Serializable *m_channelMarker;
|
||||||
Serializable *m_cwKeyerGUI;
|
Serializable *m_cwKeyerGUI;
|
||||||
|
@ -14,9 +14,13 @@
|
|||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
#include "SWGChannelSettings.h"
|
#include "SWGChannelSettings.h"
|
||||||
#include "SWGChannelReport.h"
|
#include "SWGChannelReport.h"
|
||||||
#include "SWGATVModReport.h"
|
#include "SWGATVModReport.h"
|
||||||
@ -100,12 +104,21 @@ ATVMod::ATVMod(DeviceSinkAPI *deviceAPI) :
|
|||||||
m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this);
|
m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this);
|
||||||
m_deviceAPI->addThreadedSource(m_threadedChannelizer);
|
m_deviceAPI->addThreadedSource(m_threadedChannelizer);
|
||||||
m_deviceAPI->addChannelAPI(this);
|
m_deviceAPI->addChannelAPI(this);
|
||||||
|
|
||||||
|
m_networkManager = new QNetworkAccessManager();
|
||||||
|
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ATVMod::~ATVMod()
|
ATVMod::~ATVMod()
|
||||||
{
|
{
|
||||||
if (m_video.isOpened()) m_video.release();
|
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||||
releaseCameras();
|
delete m_networkManager;
|
||||||
|
|
||||||
|
if (m_video.isOpened()) {
|
||||||
|
m_video.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseCameras();
|
||||||
m_deviceAPI->removeChannelAPI(this);
|
m_deviceAPI->removeChannelAPI(this);
|
||||||
m_deviceAPI->removeThreadedSource(m_threadedChannelizer);
|
m_deviceAPI->removeThreadedSource(m_threadedChannelizer);
|
||||||
delete m_threadedChannelizer;
|
delete m_threadedChannelizer;
|
||||||
@ -1090,8 +1103,72 @@ void ATVMod::applySettings(const ATVModSettings& settings, bool force)
|
|||||||
<< " m_fmExcursion: " << settings.m_fmExcursion
|
<< " m_fmExcursion: " << settings.m_fmExcursion
|
||||||
<< " m_forceDecimator: " << settings.m_forceDecimator
|
<< " m_forceDecimator: " << settings.m_forceDecimator
|
||||||
<< " m_showOverlayText: " << settings.m_showOverlayText
|
<< " m_showOverlayText: " << settings.m_showOverlayText
|
||||||
|
<< " m_overlayText: " << settings.m_overlayText
|
||||||
<< " force: " << force;
|
<< " 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_rfOppBandwidth != m_settings.m_rfOppBandwidth) || force) {
|
||||||
|
reverseAPIKeys.append("rfOppBandwidth");
|
||||||
|
}
|
||||||
|
if ((settings.m_atvStd != m_settings.m_atvStd) || force) {
|
||||||
|
reverseAPIKeys.append("atvStd");
|
||||||
|
}
|
||||||
|
if ((settings.m_nbLines != m_settings.m_nbLines) || force) {
|
||||||
|
reverseAPIKeys.append("nbLines");
|
||||||
|
}
|
||||||
|
if ((settings.m_fps != m_settings.m_fps) || force) {
|
||||||
|
reverseAPIKeys.append("fps");
|
||||||
|
}
|
||||||
|
if ((settings.m_atvModInput != m_settings.m_atvModInput) || force) {
|
||||||
|
reverseAPIKeys.append("atvModInput");
|
||||||
|
}
|
||||||
|
if ((settings.m_uniformLevel != m_settings.m_uniformLevel) || force) {
|
||||||
|
reverseAPIKeys.append("uniformLevel");
|
||||||
|
}
|
||||||
|
if ((settings.m_uniformLevel != m_settings.m_uniformLevel) || force) {
|
||||||
|
reverseAPIKeys.append("uniformLevel");
|
||||||
|
}
|
||||||
|
if ((settings.m_atvModulation != m_settings.m_atvModulation) || force) {
|
||||||
|
reverseAPIKeys.append("atvModulation");
|
||||||
|
}
|
||||||
|
if ((settings.m_videoPlayLoop != m_settings.m_videoPlayLoop) || force) {
|
||||||
|
reverseAPIKeys.append("videoPlayLoop");
|
||||||
|
}
|
||||||
|
if ((settings.m_videoPlay != m_settings.m_videoPlay) || force) {
|
||||||
|
reverseAPIKeys.append("videoPlay");
|
||||||
|
}
|
||||||
|
if ((settings.m_cameraPlay != m_settings.m_cameraPlay) || force) {
|
||||||
|
reverseAPIKeys.append("cameraPlay");
|
||||||
|
}
|
||||||
|
if ((settings.m_channelMute != m_settings.m_channelMute) || force) {
|
||||||
|
reverseAPIKeys.append("channelMute");
|
||||||
|
}
|
||||||
|
if ((settings.m_invertedVideo != m_settings.m_invertedVideo) || force) {
|
||||||
|
reverseAPIKeys.append("invertedVideo");
|
||||||
|
}
|
||||||
|
if ((settings.m_rfScalingFactor != m_settings.m_rfScalingFactor) || force) {
|
||||||
|
reverseAPIKeys.append("rfScalingFactor");
|
||||||
|
}
|
||||||
|
if ((settings.m_fmExcursion != m_settings.m_fmExcursion) || force) {
|
||||||
|
reverseAPIKeys.append("fmExcursion");
|
||||||
|
}
|
||||||
|
if ((settings.m_forceDecimator != m_settings.m_forceDecimator) || force) {
|
||||||
|
reverseAPIKeys.append("forceDecimator");
|
||||||
|
}
|
||||||
|
if ((settings.m_showOverlayText != m_settings.m_showOverlayText) || force) {
|
||||||
|
reverseAPIKeys.append("showOverlayText");
|
||||||
|
}
|
||||||
|
if ((settings.m_overlayText != m_settings.m_overlayText) || force) {
|
||||||
|
reverseAPIKeys.append("overlayText");
|
||||||
|
}
|
||||||
|
|
||||||
if ((settings.m_atvStd != m_settings.m_atvStd)
|
if ((settings.m_atvStd != m_settings.m_atvStd)
|
||||||
|| (settings.m_nbLines != m_settings.m_nbLines)
|
|| (settings.m_nbLines != m_settings.m_nbLines)
|
||||||
|| (settings.m_fps != m_settings.m_fps)
|
|| (settings.m_fps != m_settings.m_fps)
|
||||||
@ -1159,6 +1236,16 @@ void ATVMod::applySettings(const ATVModSettings& settings, bool force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1214,7 +1301,7 @@ int ATVMod::webapiSettingsPutPatch(
|
|||||||
settings.m_rfBandwidth = response.getAtvModSettings()->getRfBandwidth();
|
settings.m_rfBandwidth = response.getAtvModSettings()->getRfBandwidth();
|
||||||
}
|
}
|
||||||
if (channelSettingsKeys.contains("rfOppBandwidth")) {
|
if (channelSettingsKeys.contains("rfOppBandwidth")) {
|
||||||
settings.m_rfOppBandwidth = response.getAtvModSettings()->getRfBandwidth();
|
settings.m_rfOppBandwidth = response.getAtvModSettings()->getRfOppBandwidth();
|
||||||
}
|
}
|
||||||
if (channelSettingsKeys.contains("atvStd")) {
|
if (channelSettingsKeys.contains("atvStd")) {
|
||||||
settings.m_atvStd = (ATVModSettings::ATVStd) response.getAtvModSettings()->getAtvStd();
|
settings.m_atvStd = (ATVModSettings::ATVStd) response.getAtvModSettings()->getAtvStd();
|
||||||
@ -1270,7 +1357,21 @@ int ATVMod::webapiSettingsPutPatch(
|
|||||||
if (channelSettingsKeys.contains("title")) {
|
if (channelSettingsKeys.contains("title")) {
|
||||||
settings.m_title = *response.getAtvModSettings()->getTitle();
|
settings.m_title = *response.getAtvModSettings()->getTitle();
|
||||||
}
|
}
|
||||||
|
if (channelSettingsKeys.contains("useReverseAPI")) {
|
||||||
|
settings.m_useReverseAPI = response.getAtvModSettings()->getUseReverseApi() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIAddress")) {
|
||||||
|
settings.m_reverseAPIAddress = *response.getAtvModSettings()->getReverseApiAddress() != 0;
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIPort")) {
|
||||||
|
settings.m_reverseAPIPort = response.getAtvModSettings()->getReverseApiPort();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
|
||||||
|
settings.m_reverseAPIDeviceIndex = response.getAtvModSettings()->getReverseApiDeviceIndex();
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
|
||||||
|
settings.m_reverseAPIChannelIndex = response.getAtvModSettings()->getReverseApiChannelIndex();
|
||||||
|
}
|
||||||
if (frequencyOffsetChanged)
|
if (frequencyOffsetChanged)
|
||||||
{
|
{
|
||||||
ATVMod::MsgConfigureChannelizer *msgChan = ATVMod::MsgConfigureChannelizer::create(
|
ATVMod::MsgConfigureChannelizer *msgChan = ATVMod::MsgConfigureChannelizer::create(
|
||||||
@ -1377,6 +1478,18 @@ void ATVMod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& respon
|
|||||||
} else {
|
} else {
|
||||||
response.getAtvModSettings()->setVideoFileName(new QString(m_videoFileName));
|
response.getAtvModSettings()->setVideoFileName(new QString(m_videoFileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response.getAtvModSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
|
||||||
|
|
||||||
|
if (response.getAtvModSettings()->getReverseApiAddress()) {
|
||||||
|
*response.getAtvModSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
|
||||||
|
} else {
|
||||||
|
response.getAtvModSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
response.getAtvModSettings()->setReverseApiPort(settings.m_reverseAPIPort);
|
||||||
|
response.getAtvModSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
|
||||||
|
response.getAtvModSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ATVMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
void ATVMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
||||||
@ -1384,3 +1497,114 @@ void ATVMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
|
|||||||
response.getAtvModReport()->setChannelPowerDb(CalcDb::dbPower(getMagSq()));
|
response.getAtvModReport()->setChannelPowerDb(CalcDb::dbPower(getMagSq()));
|
||||||
response.getAtvModReport()->setChannelSampleRate(m_outputSampleRate);
|
response.getAtvModReport()->setChannelSampleRate(m_outputSampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ATVMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const ATVModSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
|
||||||
|
swgChannelSettings->setTx(1);
|
||||||
|
swgChannelSettings->setChannelType(new QString("ATVMod"));
|
||||||
|
swgChannelSettings->setAtvModSettings(new SWGSDRangel::SWGATVModSettings());
|
||||||
|
SWGSDRangel::SWGATVModSettings *swgATVModSettings = swgChannelSettings->getAtvModSettings();
|
||||||
|
|
||||||
|
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||||
|
|
||||||
|
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
|
||||||
|
swgATVModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rfBandwidth") || force) {
|
||||||
|
swgATVModSettings->setRfBandwidth(settings.m_rfBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rfOppBandwidth") || force) {
|
||||||
|
swgATVModSettings->setRfOppBandwidth(settings.m_rfOppBandwidth);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("atvStd") || force) {
|
||||||
|
swgATVModSettings->setAtvStd((int) settings.m_atvStd);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("nbLines") || force) {
|
||||||
|
swgATVModSettings->setNbLines(settings.m_nbLines);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("fps") || force) {
|
||||||
|
swgATVModSettings->setFps(settings.m_fps);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("atvModInput") || force) {
|
||||||
|
swgATVModSettings->setAtvModInput((int) settings.m_atvModInput);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("uniformLevel") || force) {
|
||||||
|
swgATVModSettings->setUniformLevel(settings.m_uniformLevel);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("atvModulation") || force) {
|
||||||
|
swgATVModSettings->setAtvModulation((int) settings.m_atvModulation);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("videoPlayLoop") || force) {
|
||||||
|
swgATVModSettings->setVideoPlayLoop(settings.m_videoPlayLoop ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("videoPlay") || force) {
|
||||||
|
swgATVModSettings->setVideoPlay(settings.m_videoPlay ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("cameraPlay") || force) {
|
||||||
|
swgATVModSettings->setCameraPlay(settings.m_cameraPlay ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("channelMute") || force) {
|
||||||
|
swgATVModSettings->setChannelMute(settings.m_channelMute ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("invertedVideo") || force) {
|
||||||
|
swgATVModSettings->setInvertedVideo(settings.m_invertedVideo ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rfScalingFactor") || force) {
|
||||||
|
swgATVModSettings->setRfScalingFactor(settings.m_rfScalingFactor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("fmExcursion") || force) {
|
||||||
|
swgATVModSettings->setFmExcursion(settings.m_fmExcursion);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("forceDecimator") || force) {
|
||||||
|
swgATVModSettings->setForceDecimator(settings.m_forceDecimator ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("showOverlayText") || force) {
|
||||||
|
swgATVModSettings->setShowOverlayText(settings.m_showOverlayText ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("overlayText") || force) {
|
||||||
|
swgATVModSettings->setOverlayText(new QString(settings.m_overlayText));
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||||
|
swgATVModSettings->setRgbColor(settings.m_rgbColor);
|
||||||
|
}
|
||||||
|
if (channelSettingsKeys.contains("title") || force) {
|
||||||
|
swgATVModSettings->setTitle(new QString(settings.m_title));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||||
|
|
||||||
|
delete swgChannelSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATVMod::networkManagerFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
QNetworkReply::NetworkError replyError = reply->error();
|
||||||
|
|
||||||
|
if (replyError)
|
||||||
|
{
|
||||||
|
qWarning() << "ATVMod::networkManagerFinished:"
|
||||||
|
<< " error(" << (int) replyError
|
||||||
|
<< "): " << replyError
|
||||||
|
<< ": " << reply->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString answer = reply->readAll();
|
||||||
|
answer.chop(1); // remove last \n
|
||||||
|
qDebug("ATVMod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||||
|
}
|
||||||
|
@ -17,10 +17,11 @@
|
|||||||
#ifndef PLUGINS_CHANNELTX_MODATV_ATVMOD_H_
|
#ifndef PLUGINS_CHANNELTX_MODATV_ATVMOD_H_
|
||||||
#define PLUGINS_CHANNELTX_MODATV_ATVMOD_H_
|
#define PLUGINS_CHANNELTX_MODATV_ATVMOD_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
|
#include <QNetworkRequest>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <opencv2/core/core.hpp>
|
#include <opencv2/core/core.hpp>
|
||||||
#include <opencv2/highgui/highgui.hpp>
|
#include <opencv2/highgui/highgui.hpp>
|
||||||
@ -37,6 +38,8 @@
|
|||||||
|
|
||||||
#include "atvmodsettings.h"
|
#include "atvmodsettings.h"
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QNetworkReply;
|
||||||
class DeviceSinkAPI;
|
class DeviceSinkAPI;
|
||||||
class ThreadedBasebandSampleSource;
|
class ThreadedBasebandSampleSource;
|
||||||
class UpChannelizer;
|
class UpChannelizer;
|
||||||
@ -400,6 +403,9 @@ signals:
|
|||||||
*/
|
*/
|
||||||
void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples);
|
void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void networkManagerFinished(QNetworkReply *reply);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct ATVCamera
|
struct ATVCamera
|
||||||
{
|
{
|
||||||
@ -524,8 +530,10 @@ private:
|
|||||||
Complex* m_DSBFilterBuffer;
|
Complex* m_DSBFilterBuffer;
|
||||||
int m_DSBFilterBufferIndex;
|
int m_DSBFilterBufferIndex;
|
||||||
|
|
||||||
static const int m_ssbFftLen;
|
QNetworkAccessManager *m_networkManager;
|
||||||
|
QNetworkRequest m_networkRequest;
|
||||||
|
|
||||||
|
static const int m_ssbFftLen;
|
||||||
static const float m_blackLevel;
|
static const float m_blackLevel;
|
||||||
static const float m_spanLevel;
|
static const float m_spanLevel;
|
||||||
static const int m_levelNbSamples;
|
static const int m_levelNbSamples;
|
||||||
@ -556,6 +564,7 @@ private:
|
|||||||
|
|
||||||
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const ATVModSettings& settings);
|
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const ATVModSettings& settings);
|
||||||
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
|
||||||
|
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const ATVModSettings& settings, bool force);
|
||||||
|
|
||||||
inline void pullImageLine(Real& sample, bool noHSync = false)
|
inline void pullImageLine(Real& sample, bool noHSync = false)
|
||||||
{
|
{
|
||||||
|
@ -207,8 +207,8 @@ void ATVModGUI::setRFFiltersSlidersRange(int sampleRate)
|
|||||||
ui->rfOppBW->setMaximum((sampleRate) / m_rfSliderDivisor);
|
ui->rfOppBW->setMaximum((sampleRate) / m_rfSliderDivisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->rfBWText->setText(QString("%1k").arg((ui->rfBW->value()*m_rfSliderDivisor) / 1000.0, 0, 'f', 0));
|
ui->rfBWText->setText(QString("%1k").arg((ui->rfBW->value()*m_rfSliderDivisor) / 1000.0, 0, 'f', 1));
|
||||||
ui->rfOppBWText->setText(QString("%1k").arg((ui->rfOppBW->value()*m_rfSliderDivisor) / 1000.0, 0, 'f', 0));
|
ui->rfOppBWText->setText(QString("%1k").arg((ui->rfOppBW->value()*m_rfSliderDivisor) / 1000.0, 0, 'f', 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
int ATVModGUI::getNbLines()
|
int ATVModGUI::getNbLines()
|
||||||
@ -372,6 +372,7 @@ void ATVModGUI::handleSourceMessages()
|
|||||||
void ATVModGUI::on_deltaFrequency_changed(qint64 value)
|
void ATVModGUI::on_deltaFrequency_changed(qint64 value)
|
||||||
{
|
{
|
||||||
m_channelMarker.setCenterFrequency(value);
|
m_channelMarker.setCenterFrequency(value);
|
||||||
|
m_settings.m_inputFrequencyOffset = value;
|
||||||
applySettings();
|
applySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +400,7 @@ void ATVModGUI::on_fmExcursion_valueChanged(int value)
|
|||||||
|
|
||||||
void ATVModGUI::on_rfBW_valueChanged(int value)
|
void ATVModGUI::on_rfBW_valueChanged(int value)
|
||||||
{
|
{
|
||||||
ui->rfBWText->setText(QString("%1k").arg((value*m_rfSliderDivisor) / 1000.0, 0, 'f', 0));
|
ui->rfBWText->setText(QString("%1k").arg((value*m_rfSliderDivisor) / 1000.0, 0, 'f', 1));
|
||||||
m_settings.m_rfBandwidth = value * m_rfSliderDivisor * 1.0f;
|
m_settings.m_rfBandwidth = value * m_rfSliderDivisor * 1.0f;
|
||||||
setChannelMarkerBandwidth();
|
setChannelMarkerBandwidth();
|
||||||
applySettings();
|
applySettings();
|
||||||
@ -407,7 +408,7 @@ void ATVModGUI::on_rfBW_valueChanged(int value)
|
|||||||
|
|
||||||
void ATVModGUI::on_rfOppBW_valueChanged(int value)
|
void ATVModGUI::on_rfOppBW_valueChanged(int value)
|
||||||
{
|
{
|
||||||
ui->rfOppBWText->setText(QString("%1k").arg((value*m_rfSliderDivisor) / 1000.0, 0, 'f', 0));
|
ui->rfOppBWText->setText(QString("%1k").arg((value*m_rfSliderDivisor) / 1000.0, 0, 'f', 1));
|
||||||
m_settings.m_rfOppBandwidth = value * m_rfSliderDivisor * 1.0f;
|
m_settings.m_rfOppBandwidth = value * m_rfSliderDivisor * 1.0f;
|
||||||
setChannelMarkerBandwidth();
|
setChannelMarkerBandwidth();
|
||||||
applySettings();
|
applySettings();
|
||||||
@ -614,12 +615,23 @@ void ATVModGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
|||||||
void ATVModGUI::onMenuDialogCalled(const QPoint &p)
|
void ATVModGUI::onMenuDialogCalled(const QPoint &p)
|
||||||
{
|
{
|
||||||
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
|
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.move(p);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
|
|
||||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||||
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
|
||||||
m_settings.m_title = m_channelMarker.getTitle();
|
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);
|
setWindowTitle(m_settings.m_title);
|
||||||
setTitleColor(m_settings.m_rgbColor);
|
setTitleColor(m_settings.m_rgbColor);
|
||||||
@ -737,11 +749,10 @@ void ATVModGUI::displaySettings()
|
|||||||
setRFFiltersSlidersRange(m_atvMod->getEffectiveSampleRate());
|
setRFFiltersSlidersRange(m_atvMod->getEffectiveSampleRate());
|
||||||
|
|
||||||
ui->rfBW->setValue(roundf(m_settings.m_rfBandwidth / m_rfSliderDivisor));
|
ui->rfBW->setValue(roundf(m_settings.m_rfBandwidth / m_rfSliderDivisor));
|
||||||
ui->rfBWText->setText(QString("%1k").arg((ui->rfBW->value()*m_rfSliderDivisor) / 1000.0, 0, 'f', 0));
|
ui->rfBWText->setText(QString("%1k").arg((ui->rfBW->value()*m_rfSliderDivisor) / 1000.0, 0, 'f', 1));
|
||||||
|
|
||||||
ui->rfOppBW->setValue(roundf(m_settings.m_rfOppBandwidth / m_rfSliderDivisor));
|
ui->rfOppBW->setValue(roundf(m_settings.m_rfOppBandwidth / m_rfSliderDivisor));
|
||||||
ui->rfOppBWText->setText(QString("%1k").arg((ui->rfOppBW->value()*m_rfSliderDivisor) / 1000.0, 0, 'f', 0));
|
ui->rfOppBWText->setText(QString("%1k").arg((ui->rfOppBW->value()*m_rfSliderDivisor) / 1000.0, 0, 'f', 1));
|
||||||
|
|
||||||
|
|
||||||
ui->forceDecimator->setChecked(m_settings.m_forceDecimator);
|
ui->forceDecimator->setChecked(m_settings.m_forceDecimator);
|
||||||
ui->channelMute->setChecked(m_settings.m_channelMute);
|
ui->channelMute->setChecked(m_settings.m_channelMute);
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
const PluginDescriptor ATVModPlugin::m_pluginDescriptor = {
|
const PluginDescriptor ATVModPlugin::m_pluginDescriptor = {
|
||||||
QString("ATV Modulator"),
|
QString("ATV Modulator"),
|
||||||
QString("4.0.7"),
|
QString("4.3.2"),
|
||||||
QString("(c) Edouard Griffiths, F4EXB"),
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
QString("https://github.com/f4exb/sdrangel"),
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -50,6 +50,11 @@ void ATVModSettings::resetToDefaults()
|
|||||||
m_overlayText = "ATV";
|
m_overlayText = "ATV";
|
||||||
m_rgbColor = QColor(255, 255, 255).rgb();
|
m_rgbColor = QColor(255, 255, 255).rgb();
|
||||||
m_title = "ATV Modulator";
|
m_title = "ATV Modulator";
|
||||||
|
m_useReverseAPI = false;
|
||||||
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
m_reverseAPIDeviceIndex = 0;
|
||||||
|
m_reverseAPIChannelIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray ATVModSettings::serialize() const
|
QByteArray ATVModSettings::serialize() const
|
||||||
@ -76,6 +81,11 @@ QByteArray ATVModSettings::serialize() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.writeString(16, m_title);
|
s.writeString(16, m_title);
|
||||||
|
s.writeBool(17, m_useReverseAPI);
|
||||||
|
s.writeString(18, m_reverseAPIAddress);
|
||||||
|
s.writeU32(19, m_reverseAPIPort);
|
||||||
|
s.writeU32(20, m_reverseAPIDeviceIndex);
|
||||||
|
s.writeU32(21, m_reverseAPIChannelIndex);
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -94,6 +104,7 @@ bool ATVModSettings::deserialize(const QByteArray& data)
|
|||||||
{
|
{
|
||||||
QByteArray bytetmp;
|
QByteArray bytetmp;
|
||||||
qint32 tmp;
|
qint32 tmp;
|
||||||
|
uint32_t utmp;
|
||||||
|
|
||||||
d.readS32(1, &tmp, 0);
|
d.readS32(1, &tmp, 0);
|
||||||
m_inputFrequencyOffset = tmp;
|
m_inputFrequencyOffset = tmp;
|
||||||
@ -124,7 +135,20 @@ bool ATVModSettings::deserialize(const QByteArray& data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
d.readString(16, &m_title, "ATV Modulator");
|
d.readString(16, &m_title, "ATV Modulator");
|
||||||
|
d.readBool(17, &m_useReverseAPI, false);
|
||||||
|
d.readString(18, &m_reverseAPIAddress, "127.0.0.1");
|
||||||
|
d.readU32(19, &utmp, 0);
|
||||||
|
|
||||||
|
if ((utmp > 1023) && (utmp < 65535)) {
|
||||||
|
m_reverseAPIPort = utmp;
|
||||||
|
} else {
|
||||||
|
m_reverseAPIPort = 8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.readU32(20, &utmp, 0);
|
||||||
|
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||||
|
d.readU32(21, &utmp, 0);
|
||||||
|
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user