1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-06-14 20:42:28 -04:00

Merge master

This commit is contained in:
srcejon 2025-06-02 12:10:21 +01:00
commit b897b2176d
108 changed files with 1148 additions and 593 deletions

View File

@ -41,6 +41,9 @@ jobs:
echo github.event_name: ${{ github.event_name }}
echo github.ref: ${{ github.ref }}
echo github.workspace: ${{ github.workspace }}
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install basic dependencies on Windows
if: startsWith(matrix.config.os, 'windows')
run: |

View File

@ -37,6 +37,9 @@ jobs:
echo github.event_name: ${{ github.event_name }}
echo github.ref: ${{ github.ref }}
echo github.workspace: ${{ github.workspace }}
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install basic dependencies on Windows
if: startsWith(matrix.config.os, 'windows')
run: |
@ -70,7 +73,7 @@ jobs:
version: '6.7.3'
dir: ${{matrix.config.QT_INST_DIR}}
arch: ${{matrix.config.QT_ARCH}}
setup-python: false
setup-python: 'false'
modules: 'qtcharts qtscxml qt5compat qtlocation qtmultimedia qtpositioning qtserialport qtspeech qtwebsockets qtwebengine qtshadertools qtwebchannel'
- name: build sdrangel on Windows
if: startsWith(matrix.config.os, 'windows')

View File

@ -1,3 +1,9 @@
sdrangel (7.22.7-1) unstable; urgency=medium
* See Github release
-- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Sun, 04 May 2025 17:58:14 +0200
sdrangel (7.22.6-1) unstable; urgency=medium
* See Github release

View File

@ -20,7 +20,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# configure version
set(sdrangel_VERSION_MAJOR "7")
set(sdrangel_VERSION_MINOR "22")
set(sdrangel_VERSION_PATCH "6")
set(sdrangel_VERSION_PATCH "7")
set(sdrangel_VERSION_SUFFIX "")
# SDRAngel cmake options

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
sdrangel (7.22.7-1) unstable; urgency=medium
* See Github release
-- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Sun, 04 May 2025 17:58:14 +0200
sdrangel (7.22.6-1) unstable; urgency=medium
* See Github release

View File

@ -11,7 +11,7 @@
set(CODEC2_TAG "v1.0.3")
set(CM256CC_TAG c0e92b92aca3d1d36c990b642b937c64d363c559)
set(MBELIB_TAG fe83b32c6a60cdd7bce8cecf3c7a0b9ec87a7667)
set(SERIALDV_TAG "v1.1.4")
set(SERIALDV_TAG "v1.1.5")
set(DSDCC_TAG "v1.9.5")
set(LIMESUITE_TAG b39cb61ed03d74c35a2de757d495e901acbb6404)
set(BLADERF_TAG "2021.02")
@ -54,6 +54,7 @@ if (WIN32)
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG=${SDRANGEL_BINARY_LIB_DIR}
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE=${SDRANGEL_BINARY_LIB_DIR}
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO=${SDRANGEL_BINARY_LIB_DIR}
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
)
elseif (LINUX)
set(COMMON_CMAKE_ARGS

View File

@ -82,7 +82,7 @@ std::string Packing::unpackcall(int x)
if (x <= 1002)
{
sprintf(tmp, "CQ %d", x - 3);
snprintf(tmp, sizeof(tmp), "CQ %d", x - 3);
return std::string(tmp);
}
@ -96,7 +96,7 @@ std::string Packing::unpackcall(int x)
int ci3 = x / 27;
x %= 27;
int ci4 = x;
sprintf(tmp, "CQ %c%c%c%c", c4[ci1], c4[ci2], c4[ci3], c4[ci4]);
snprintf(tmp, sizeof(tmp), "CQ %c%c%c%c", c4[ci1], c4[ci2], c4[ci3], c4[ci4]);
return std::string(tmp);
}
@ -193,9 +193,9 @@ std::string Packing::unpackgrid15(int ng, int ir)
char tmp[16];
if (db >= 0) {
sprintf(tmp, "%s+%02d", ir ? "R" : "", db);
snprintf(tmp, sizeof(tmp), "%s+%02d", ir ? "R" : "", db);
} else {
sprintf(tmp, "%s-%02d", ir ? "R" : "", 0 - db);
snprintf(tmp, sizeof(tmp), "%s-%02d", ir ? "R" : "", 0 - db);
}
return std::string(tmp);
@ -396,7 +396,7 @@ std::string Packing::unpack_5(int a77[], std::string& call1str, std::string& cal
i += 3;
int qsonb = un64(a77, i, 11);
char report[16];
sprintf(report, "%d%04d", rst, qsonb);
snprintf(report, sizeof(report), "%d%04d", rst, qsonb);
i += 11;
// g25
int ng = un64(a77, i, 25);
@ -467,9 +467,9 @@ std::string Packing::unpack_0_1(int a77[], std::string& call1str, std::string& c
char tmp[32];
if (r >= 0) {
sprintf(tmp, "+%02d", r);
snprintf(tmp, sizeof(tmp), "+%02d", r);
} else {
sprintf(tmp, "-%02d", -r);
snprintf(tmp, sizeof(tmp), "-%02d", -r);
}
locstr = std::string(tmp);
@ -553,7 +553,7 @@ std::string Packing::unpack_3(int a77[], std::string& call1str, std::string& cal
else
{
char tmp[32];
sprintf(tmp, "%04d", serial);
snprintf(tmp, sizeof(tmp), "%04d", serial);
serialstr = std::string(tmp);
}
@ -571,7 +571,7 @@ std::string Packing::unpack_3(int a77[], std::string& call1str, std::string& cal
}
{
char tmp[16];
sprintf(tmp, "%d ", rst);
snprintf(tmp, sizeof(tmp), "%d ", rst);
msg += std::string(tmp);
}
@ -634,7 +634,7 @@ std::string Packing::unpack_0_3(int a77[], int n3, std::string& call1str, std::s
{
char tmp[16];
sprintf(tmp, "%d%c ", n_transmitters + 1, clss + 'A');
snprintf(tmp, sizeof(tmp), "%d%c ", n_transmitters + 1, clss + 'A');
msg += std::string(tmp);
}
@ -658,9 +658,9 @@ std::string Packing::unpack(int a77[], std::string& call1, std::string& call2, s
char tmp[64];
if (i3 == 0) {
sprintf(tmp, "%d.%d", i3, n3);
snprintf(tmp, sizeof(tmp), "%d.%d", i3, n3);
} else {
sprintf(tmp, "%d", i3);
snprintf(tmp, sizeof(tmp), "%d", i3);
}
type = std::string(tmp);
@ -714,7 +714,7 @@ std::string Packing::unpack(int a77[], std::string& call1, std::string& call2, s
}
call1 = "UNK";
sprintf(tmp, "UNK i3=%d n3=%d", i3, n3);
snprintf(tmp, sizeof(tmp), "UNK i3=%d n3=%d", i3, n3);
return std::string(tmp);
}

View File

@ -5,6 +5,5 @@ for plugin in $PLUGINS
do
FILE=$(find $BASEDIR/plugins/$plugin -name "*plugin.cpp")
echo $FILE
sed -i -E "s/QStringLiteral\(\"7\.(.*)\"\)/QStringLiteral\(\"7\.22\.6\"\)/" $FILE
sed -i -E "s/QStringLiteral\(\"7\.(.*)\"\)/QStringLiteral\(\"7\.22\.7\"\)/" $FILE
done

View File

@ -211,6 +211,26 @@ else()
message(STATUS "Not building wdsprx (ENABLE_CHANNELRX_WDSPRX=${ENABLE_CHANNELRX_WDSPRX} WDSP_SUPPORT=${WDSP_SUPPORT})")
endif()
# need ffmpeg 3.1 that correstonds to
# libavutil 55.27.100
# libavcodec 57.48.101
# libavformat 57.40.101
find_package(FFmpeg COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
if (ENABLE_CHANNELRX_DEMODDATV AND FFMPEG_FOUND)
if(WIN32)
add_subdirectory(demoddatv)
else()
if(((AVUTIL_VERSION VERSION_GREATER "55.27.99") AND (AVCODEC_VERSION VERSION_GREATER "57.48.101")) OR FFMPEG_EXTERNAL OR FFMPEG_SKIP_CHECK)
message(STATUS "Include demoddatv")
add_subdirectory(demoddatv)
else()
message(STATUS "FFmpeg too old to compile demoddatv; needs at least avutil: 55.27.100, avcodec/avformat: 57.48.101")
endif()
endif()
else()
message(STATUS "Not building demoddatv (ENABLE_CHANNELRX_DEMODDATV=${ENABLE_CHANNELRX_DEMODDATV} FFMPEG_FOUND=${FFMPEG_FOUND})")
endif()
if(NOT SERVER_MODE)
if (ENABLE_CHANNELRX_HEATMAP)
@ -230,25 +250,4 @@ if(NOT SERVER_MODE)
else()
message(STATUS "Not building demodatv (ENABLE_CHANNELRX_DEMODATV=${ENABLE_CHANNELRX_DEMODATV})")
endif()
# need ffmpeg 3.1 that correstonds to
# libavutil 55.27.100
# libavcodec 57.48.101
# libavformat 57.40.101
find_package(FFmpeg COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
if (ENABLE_CHANNELRX_DEMODDATV AND FFMPEG_FOUND)
if(WIN32)
add_subdirectory(demoddatv)
else()
if(((AVUTIL_VERSION VERSION_GREATER "55.27.99") AND (AVCODEC_VERSION VERSION_GREATER "57.48.101")) OR FFMPEG_EXTERNAL OR FFMPEG_SKIP_CHECK)
message(STATUS "Include demoddatv")
add_subdirectory(demoddatv)
else()
message(STATUS "FFmpeg too old to compile demoddatv; needs at least avutil: 55.27.100, avcodec/avformat: 57.48.101")
endif()
endif()
else()
message(STATUS "Not building demoddatv (ENABLE_CHANNELRX_DEMODDATV=${ENABLE_CHANNELRX_DEMODDATV} FFMPEG_FOUND=${FFMPEG_FOUND})")
endif()
endif()

View File

@ -3,17 +3,14 @@ project(datv)
set(datv_SOURCES
datvdemod.cpp
datvdemodgui.cpp
datvdemodplugin.cpp
datvdemodsettings.cpp
datvdemodwebapiadapter.cpp
datvideostream.cpp
datvudpstream.cpp
datvideorender.cpp
datvdemodreport.cpp
datvdemodsink.cpp
datvdemodbaseband.cpp
datvdvbs2ldpcdialog.cpp
leansdr/dvb.cpp
leansdr/filtergen.cpp
leansdr/framework.cpp
@ -30,19 +27,14 @@ set(ldpc_SOURCES
set(datv_HEADERS
datvdemod.h
datvdemodgui.h
datvdemodplugin.h
datvdemodsettings.h
datvdemodwebapiadapter.h
datvideostream.h
datvudpstream.h
datvideorender.h
datvconstellation.h
datvdvbs2constellation.h
datvdemodreport.h
datvdemodsink.h
datvdemodbaseband.h
datvdvbs2ldpcdialog.h
leansdr/dvb.h
leansdr/dvbs2.h
leansdr/filtergen.h
@ -59,6 +51,33 @@ set(ldpc_HEADERS
ldpctool/ldpcworker.h
)
if(NOT SERVER_MODE)
set(datv_SOURCES
${datv_SOURCES}
datvdemodgui.ui
datvdvbs2ldpcdialog.ui
datvdemodgui.cpp
datvdvbs2ldpcdialog.cpp
datvideorender.cpp
)
set(datv_HEADERS ${datv_HEADERS}
datvdemodgui.h
datvdvbs2ldpcdialog.h
datvconstellation.h
datvdvbs2constellation.h
datvideorender.h
)
set(TARGET_NAME ${PLUGINS_PREFIX}demoddatv)
set(TARGET_LIB Qt::Widgets Qt::Multimedia Qt::MultimediaWidgets)
set(TARGET_LIB_GUI "sdrgui")
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
else()
set(TARGET_NAME ${PLUGINSSRV_PREFIX}demoddatvsrv)
set(TARGET_LIB "")
set(TARGET_LIB_GUI "")
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
include_directories(
${AVCODEC_INCLUDE_DIRS}
${AVFORMAT_INCLUDE_DIRS}
@ -68,10 +87,6 @@ include_directories(
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
set(TARGET_NAME ${PLUGINS_PREFIX}demoddatv)
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
if(NOT Qt6_FOUND)
add_library(${TARGET_NAME} ${datv_SOURCES} ${ldpc_SOURCES})
else()
@ -84,11 +99,9 @@ endif()
target_link_libraries(${TARGET_NAME} PRIVATE
Qt::Core
Qt::Widgets
Qt::Multimedia
Qt::MultimediaWidgets
${TARGET_LIB}
sdrbase
sdrgui
${TARGET_LIB_GUI}
${AVCODEC_LIBRARIES}
${AVFORMAT_LIBRARIES}
${AVUTIL_LIBRARIES}
@ -96,12 +109,6 @@ target_link_libraries(${TARGET_NAME} PRIVATE
${SWRESAMPLE_LIBRARIES}
)
add_executable(ldpctool
ldpctool/ldpc_tool.cpp
ldpctool/tables_handler.cpp
)
install(TARGETS ldpctool DESTINATION ${INSTALL_BIN_DIR})
if(DEFINED FFMPEG_DEPENDS)
add_dependencies(${TARGET_NAME} ${FFMPEG_DEPENDS})
endif()

View File

@ -31,84 +31,6 @@ namespace leansdr {
static const int DEFAULT_GUI_DECIMATION = 64;
static inline cstln_lut<eucl_ss, 256> * make_dvbs_constellation(cstln_lut<eucl_ss, 256>::predef c,
code_rate r)
{
float gamma1 = 1, gamma2 = 1, gamma3 = 1;
switch (c)
{
case cstln_lut<eucl_ss, 256>::APSK16:
// EN 302 307, section 5.4.3, Table 9
switch (r)
{
case FEC23:
case FEC46:
gamma1 = 3.15;
break;
case FEC34:
gamma1 = 2.85;
break;
case FEC45:
gamma1 = 2.75;
break;
case FEC56:
gamma1 = 2.70;
break;
case FEC89:
gamma1 = 2.60;
break;
case FEC910:
gamma1 = 2.57;
break;
default:
fail("cstln_lut<256>::make_dvbs_constellation: Code rate not supported with APSK16");
return 0;
}
break;
case cstln_lut<eucl_ss, 256>::APSK32:
// EN 302 307, section 5.4.4, Table 10
switch (r)
{
case FEC34:
gamma1 = 2.84;
gamma2 = 5.27;
break;
case FEC45:
gamma1 = 2.72;
gamma2 = 4.87;
break;
case FEC56:
gamma1 = 2.64;
gamma2 = 4.64;
break;
case FEC89:
gamma1 = 2.54;
gamma2 = 4.33;
break;
case FEC910:
gamma1 = 2.53;
gamma2 = 4.30;
break;
default:
fail("cstln_lut<eucl_ss, 256>::make_dvbs_constellation: Code rate not supported with APSK32");
return 0;
}
break;
case cstln_lut<eucl_ss, 256>::APSK64E:
// EN 302 307-2, section 5.4.5, Table 13f
gamma1 = 2.4;
gamma2 = 4.3;
gamma3 = 7;
break;
default:
break;
}
cstln_lut<eucl_ss, 256> *newCstln = new cstln_lut<eucl_ss, 256>(c, 10, gamma1, gamma2, gamma3);
newCstln->m_rateCode = (int) r;
newCstln->m_typeCode = (int) c;
newCstln->m_setByModcod = false;
return newCstln;
}
template<typename T> struct datvconstellation: runnable
{

View File

@ -0,0 +1,194 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2025 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// using LeanSDR Framework (C) 2016 F4DAV //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef DATV_CSTLN_LUT_H
#define DATV_CSTLN_LUT_H
#include "leansdr/dvb.h"
#include "leansdr/framework.h"
namespace leansdr {
static cstln_lut<eucl_ss, 256> * make_dvbs_constellation(
cstln_lut<eucl_ss, 256>::predef c,
code_rate r
)
{
float gamma1 = 1, gamma2 = 1, gamma3 = 1;
switch (c)
{
case cstln_lut<eucl_ss, 256>::APSK16:
// EN 302 307, section 5.4.3, Table 9
switch (r)
{
case FEC23:
case FEC46:
gamma1 = 3.15;
break;
case FEC34:
gamma1 = 2.85;
break;
case FEC45:
gamma1 = 2.75;
break;
case FEC56:
gamma1 = 2.70;
break;
case FEC89:
gamma1 = 2.60;
break;
case FEC910:
gamma1 = 2.57;
break;
default:
fail("cstln_lut<256>::make_dvbs_constellation: Code rate not supported with APSK16");
return 0;
}
break;
case cstln_lut<eucl_ss, 256>::APSK32:
// EN 302 307, section 5.4.4, Table 10
switch (r)
{
case FEC34:
gamma1 = 2.84;
gamma2 = 5.27;
break;
case FEC45:
gamma1 = 2.72;
gamma2 = 4.87;
break;
case FEC56:
gamma1 = 2.64;
gamma2 = 4.64;
break;
case FEC89:
gamma1 = 2.54;
gamma2 = 4.33;
break;
case FEC910:
gamma1 = 2.53;
gamma2 = 4.30;
break;
default:
fail("cstln_lut<eucl_ss, 256>::make_dvbs_constellation: Code rate not supported with APSK32");
return 0;
}
break;
case cstln_lut<eucl_ss, 256>::APSK64E:
// EN 302 307-2, section 5.4.5, Table 13f
gamma1 = 2.4;
gamma2 = 4.3;
gamma3 = 7;
break;
default:
break;
}
cstln_lut<eucl_ss, 256> *newCstln = new cstln_lut<eucl_ss, 256>(c, 10, gamma1, gamma2, gamma3);
newCstln->m_rateCode = (int) r;
newCstln->m_typeCode = (int) c;
newCstln->m_setByModcod = false;
return newCstln;
}
static cstln_lut<llr_ss, 256> * make_dvbs2_constellation(
cstln_lut<llr_ss, 256>::predef c,
code_rate r
)
{
float gamma1 = 1, gamma2 = 1, gamma3 = 1;
switch (c)
{
case cstln_lut<llr_ss, 256>::APSK16:
// EN 302 307, section 5.4.3, Table 9
switch (r)
{
case FEC23:
case FEC46:
gamma1 = 3.15;
break;
case FEC34:
gamma1 = 2.85;
break;
case FEC45:
gamma1 = 2.75;
break;
case FEC56:
gamma1 = 2.70;
break;
case FEC89:
gamma1 = 2.60;
break;
case FEC910:
gamma1 = 2.57;
break;
default:
fail("cstln_lut<256>::make_dvbs2_constellation: Code rate not supported with APSK16");
return 0;
}
break;
case cstln_lut<llr_ss, 256>::APSK32:
// EN 302 307, section 5.4.4, Table 10
switch (r)
{
case FEC34:
gamma1 = 2.84;
gamma2 = 5.27;
break;
case FEC45:
gamma1 = 2.72;
gamma2 = 4.87;
break;
case FEC56:
gamma1 = 2.64;
gamma2 = 4.64;
break;
case FEC89:
gamma1 = 2.54;
gamma2 = 4.33;
break;
case FEC910:
gamma1 = 2.53;
gamma2 = 4.30;
break;
default:
fail("cstln_lut<llr_ss, 256>::make_dvbs2_constellation: Code rate not supported with APSK32");
return 0;
}
break;
case cstln_lut<llr_ss, 256>::APSK64E:
// EN 302 307-2, section 5.4.5, Table 13f
gamma1 = 2.4;
gamma2 = 4.3;
gamma3 = 7;
break;
default:
break;
}
cstln_lut<llr_ss, 256> *newCstln = new cstln_lut<llr_ss, 256>(c, 10, gamma1, gamma2, gamma3);
newCstln->m_rateCode = r < code_rate::FEC_COUNT ? r : -1;
newCstln->m_typeCode = c < cstln_lut<llr_ss, 256>::predef::COUNT ? c : -1;
newCstln->m_setByModcod = false;
return newCstln;
}
}
#endif // DATV_CSTLN_LUT_H

View File

@ -212,9 +212,6 @@ void DATVDemod::applySettings(const DATVDemodSettings& settings, bool force)
if (settings.m_softLDPC != m_settings.m_softLDPC) {
reverseAPIKeys.append("softLDPC");
}
if (settings.m_softLDPCToolPath != m_settings.m_softLDPCToolPath) {
reverseAPIKeys.append("softLDPCToolPath");
}
if (settings.m_softLDPCMaxTrials != m_settings.m_softLDPCMaxTrials) {
reverseAPIKeys.append("softLDPCMaxTrials");
}
@ -401,9 +398,6 @@ void DATVDemod::webapiUpdateChannelSettings(
if (channelSettingsKeys.contains("softLDPC")) {
settings.m_softLDPC = response.getDatvDemodSettings()->getSoftLdpc() == 1;
}
if (channelSettingsKeys.contains("softLDPCToolPath")) {
settings.m_softLDPCToolPath = *response.getDatvDemodSettings()->getSoftLdpcToolPath();
}
if (channelSettingsKeys.contains("softLDPCMaxTrials")) {
settings.m_softLDPCMaxTrials = response.getDatvDemodSettings()->getSoftLdpcMaxTrials();
}
@ -503,13 +497,6 @@ void DATVDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& res
response.getDatvDemodSettings()->setModulation((int) settings.m_modulation);
response.getDatvDemodSettings()->setFec((int) settings.m_fec);
response.getDatvDemodSettings()->setSoftLdpc((int) settings.m_softLDPC ? 1 : 0);
if (response.getDatvDemodSettings()->getSoftLdpcToolPath()) {
*response.getDatvDemodSettings()->getSoftLdpcToolPath() = settings.m_softLDPCToolPath;
} else {
response.getDatvDemodSettings()->setSoftLdpcToolPath(new QString(settings.m_softLDPCToolPath));
}
response.getDatvDemodSettings()->setSoftLdpcMaxTrials(settings.m_softLDPCMaxTrials);
response.getDatvDemodSettings()->setMaxBitflips(settings.m_maxBitflips);
response.getDatvDemodSettings()->setAudioMute(settings.m_audioMute ? 1 : 0);
@ -589,6 +576,7 @@ void DATVDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respons
response.getDatvDemodReport()->setChannelPowerDb(CalcDb::dbPower(magsq));
response.getDatvDemodReport()->setAudioActive(audioActive() ? 1 : 0);
response.getDatvDemodReport()->setAudioDecodeOk(audioDecodeOK() ? 1 : 0);
response.getDatvDemodReport()->setSymbolRate(m_settings.m_symbolRate); // This is repeated from settings for convenience
response.getDatvDemodReport()->setModcodCodeRate(getModcodCodeRate());
response.getDatvDemodReport()->setModcodModulation(getModcodModulation());
response.getDatvDemodReport()->setSetByModcod(isCstlnSetByModcod() ? 1 : 0);
@ -664,9 +652,6 @@ void DATVDemod::webapiFormatChannelSettings(
if (channelSettingsKeys.contains("softLDPC") || force) {
swgDATVDemodSettings->setSoftLdpc(settings.m_softLDPC ? 1 : 0);
}
if (channelSettingsKeys.contains("softLDPCToolPath") || force) {
swgDATVDemodSettings->setSoftLdpcToolPath(new QString(settings.m_softLDPCToolPath));
}
if (channelSettingsKeys.contains("softLDPCMaxTrials") || force) {
swgDATVDemodSettings->setSoftLdpcMaxTrials(settings.m_softLDPCMaxTrials);
}

View File

@ -37,6 +37,7 @@
#include "maincore.h"
#include "ui_datvdemodgui.h"
#include "datvideorender.h"
#include "datvdemodreport.h"
#include "datvdvbs2ldpcdialog.h"
#include "datvdemodgui.h"
@ -531,14 +532,12 @@ void DATVDemodGUI::ldpcToolSelect(const QPoint& p)
{
qDebug("DATVDemodGUI::ldpcToolSelect");
DatvDvbS2LdpcDialog ldpcDialog;
ldpcDialog.setFileName(m_settings.m_softLDPCToolPath);
ldpcDialog.setMaxTrials(m_settings.m_softLDPCMaxTrials);
ldpcDialog.move(p);
if (ldpcDialog.exec() == QDialog::Accepted)
{
m_settings.m_softLDPCMaxTrials = ldpcDialog.getMaxTrials();
m_settings.m_softLDPCToolPath = ldpcDialog.getFileName();
applySettings();
}
}

View File

@ -32,6 +32,7 @@
#include <QTimer>
class DataTSMetaData2;
class PluginAPI;
class DeviceUISet;
class BasebandSampleSink;

View File

@ -20,10 +20,12 @@
#include <QtPlugin>
#include <QAction>
#include "plugin/pluginapi.h"
#ifndef SERVER_MODE
#include "datvdemodgui.h"
#endif
#include "datvdemod.h"
#include "datvdemodplugin.h"
#include "datvdemodwebapiadapter.h"
@ -31,7 +33,7 @@ const PluginDescriptor DATVDemodPlugin::m_ptrPluginDescriptor =
{
DATVDemod::m_channelId,
QStringLiteral("DATV Demodulator"),
QStringLiteral("7.22.5"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) F4HKW for SDRAngel using LeanSDR framework (c) F4DAV"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,
@ -75,10 +77,21 @@ void DATVDemodPlugin::createRxChannel(DeviceAPI *deviceAPI, BasebandSampleSink *
}
}
#ifdef SERVER_MODE
ChannelGUI* DATVDemodPlugin::createRxChannelGUI(
DeviceUISet *deviceUISet,
BasebandSampleSink *rxChannel) const
{
(void) deviceUISet;
(void) rxChannel;
return 0;
}
#else
ChannelGUI* DATVDemodPlugin::createRxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) const
{
return DATVDemodGUI::create(m_ptrPluginAPI, deviceUISet, rxChannel);
}
#endif
ChannelWebAPIAdapter* DATVDemodPlugin::createChannelWebAPIAdapter() const
{

View File

@ -28,12 +28,6 @@
#include "datvdemodsettings.h"
#ifdef _MSC_VER
#define DEFAULT_LDPCTOOLPATH "C:/Program Files/SDRangel/ldpctool.exe"
#else
#define DEFAULT_LDPCTOOLPATH "/opt/install/sdrangel/bin/ldpctool"
#endif
DATVDemodSettings::DATVDemodSettings() :
m_channelMarker(nullptr),
m_rollupState(nullptr)
@ -51,7 +45,6 @@ void DATVDemodSettings::resetToDefaults()
m_modulation = BPSK;
m_fec = FEC12;
m_softLDPC = false;
m_softLDPCToolPath = DEFAULT_LDPCTOOLPATH;
m_softLDPCMaxTrials = 8;
m_maxBitflips = 0;
m_symbolRate = 250000;
@ -120,7 +113,6 @@ QByteArray DATVDemodSettings::serialize() const
s.writeU32(31, m_reverseAPIChannelIndex);
s.writeBool(32, m_softLDPC);
s.writeS32(33, m_maxBitflips);
s.writeString(34, m_softLDPCToolPath);
s.writeS32(35, m_softLDPCMaxTrials);
s.writeBool(36, m_playerEnable);
@ -215,7 +207,6 @@ bool DATVDemodSettings::deserialize(const QByteArray& data)
d.readBool(32, &m_softLDPC, false);
d.readS32(33, &m_maxBitflips, 0);
d.readString(34, &m_softLDPCToolPath, DEFAULT_LDPCTOOLPATH);
d.readS32(35, &tmp, 8);
m_softLDPCMaxTrials = tmp < 1 ? 1 : tmp > m_softLDPCMaxMaxTrials ? m_softLDPCMaxMaxTrials : tmp;
d.readBool(36, &m_playerEnable, true);
@ -256,7 +247,6 @@ void DATVDemodSettings::debug(const QString& msg) const
<< " m_fec: " << m_fec
<< " m_softLDPC: " << m_softLDPC
<< " m_softLDPCMaxTrials: " << m_softLDPCMaxTrials
<< " m_softLDPCToolPath: " << m_softLDPCToolPath
<< " m_maxBitflips: " << m_maxBitflips
<< " m_modulation: " << m_modulation
<< " m_standard: " << m_standard
@ -284,7 +274,6 @@ bool DATVDemodSettings::isDifferent(const DATVDemodSettings& other)
|| (m_fec != other.m_fec)
|| (m_softLDPC != other.m_softLDPC)
|| (m_softLDPCMaxTrials != other.m_softLDPCMaxTrials)
|| (m_softLDPCToolPath != other.m_softLDPCToolPath)
|| (m_maxBitflips != other.m_maxBitflips)
|| (m_modulation != other.m_modulation)
|| (m_notchFilters != other.m_notchFilters)

View File

@ -84,7 +84,6 @@ struct DATVDemodSettings
DATVModulation m_modulation;
DATVCodeRate m_fec;
bool m_softLDPC;
QString m_softLDPCToolPath;
int m_softLDPCMaxTrials;
int m_maxBitflips;
bool m_audioMute;

View File

@ -17,6 +17,10 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SERVER_MODE
#include "datvideorender.h"
#endif
#include "datvcstlnlut.h"
#include "datvdemodsink.h"
#include "leansdr/dvbs2.h"
@ -33,7 +37,9 @@ const unsigned int DATVDemodSink::m_rfFilterFftLength = 512;
DATVDemodSink::DATVDemodSink() :
m_blnNeedConfigUpdate(false),
m_tvScreen(nullptr),
#ifndef SERVER_MODE
m_videoRender(nullptr),
#endif
m_videoStream(new DATVideostream()),
m_udpStream(leansdr::tspacket::SIZE),
m_videoThread(nullptr),
@ -69,6 +75,7 @@ DATVDemodSink::~DATVDemodSink()
void DATVDemodSink::stopVideo()
{
#ifndef SERVER_MODE
if (m_videoThread)
{
if (m_videoThread->isRunning())
@ -78,6 +85,7 @@ void DATVDemodSink::stopVideo()
m_videoThread->wait();
}
}
#endif
}
void DATVDemodSink::setTVScreen(TVScreen *tvScreen)
@ -87,46 +95,64 @@ void DATVDemodSink::setTVScreen(TVScreen *tvScreen)
void DATVDemodSink::SetVideoRender(DATVideoRender *screen)
{
#ifndef SERVER_MODE
m_videoRender = screen;
m_videoRender->setAudioFIFO(&m_audioFifo);
m_videoThread = new DATVideoRenderThread(m_videoRender, m_videoStream);
m_videoThread->setObjectName("vtDATVDemodSink");
#endif
}
bool DATVDemodSink::audioActive()
{
#ifndef SERVER_MODE
if (m_videoRender) {
return m_videoRender->getAudioStreamIndex() >= 0;
} else {
return false;
}
#else
return false;
#endif
}
bool DATVDemodSink::videoActive()
{
#ifndef SERVER_MODE
if (m_videoRender) {
return m_videoRender->getVideoStreamIndex() >= 0;
} else {
return false;
}
#else
return false;
#endif
}
bool DATVDemodSink::audioDecodeOK()
{
#ifndef SERVER_MODE
if (m_videoRender) {
return m_videoRender->getAudioDecodeOK();
} else {
return false;
}
#else
return false;
#endif
}
bool DATVDemodSink::videoDecodeOK()
{
#ifndef SERVER_MODE
if (m_videoRender) {
return m_videoRender->getVideoDecodeOK();
} else {
return false;
}
#else
return false;
#endif
}
bool DATVDemodSink::udpRunning()
@ -136,7 +162,6 @@ bool DATVDemodSink::udpRunning()
}
bool udpRunning = r_videoplayer->isUDPRunning();
r_videoplayer->resetUDPRunning();
return udpRunning;
}
@ -145,6 +170,7 @@ bool DATVDemodSink::playVideo()
{
QMutexLocker mlock(&m_mutex);
#ifndef SERVER_MODE
if (m_videoStream == nullptr) {
return false;
}
@ -167,7 +193,7 @@ bool DATVDemodSink::playVideo()
m_videoStream->setThreadTimeout(DATVideoRenderThread::videoThreadTimeoutMs);
m_videoThread->start();
}
#endif
return false;
}
@ -341,10 +367,11 @@ void DATVDemodSink::CleanUpDATVFramework()
}
//CONSTELLATION
#ifndef SERVER_MODE
if (r_scope_symbols != nullptr) {
delete r_scope_symbols;
}
#endif
// INPUT
if (p_rawiq != nullptr) {
delete p_rawiq;
@ -405,11 +432,11 @@ void DATVDemodSink::CleanUpDATVFramework()
if (p_deframer != nullptr) {
delete (leansdr::s2_deframer*) p_deframer;
}
#ifndef SERVER_MODE
if (r_scope_symbols_dvbs2 != nullptr) {
delete r_scope_symbols_dvbs2;
}
#endif
ResetDATVFrameworkPointers();
}
@ -498,7 +525,9 @@ void DATVDemodSink::ResetDATVFrameworkPointers()
r_videoplayer = nullptr;
//CONSTELLATION
#ifndef SERVER_MODE
r_scope_symbols = nullptr;
#endif
//DVB-S2
p_slots_dvbs2 = nullptr;
@ -513,7 +542,9 @@ void DATVDemodSink::ResetDATVFrameworkPointers()
r_fecdecsoft = nullptr;
r_fecdechelper = nullptr;
p_deframer = nullptr;
#ifndef SERVER_MODE
r_scope_symbols_dvbs2 = nullptr;
#endif
}
void DATVDemodSink::InitDATVFramework()
@ -761,7 +792,7 @@ void DATVDemodSink::InitDATVFramework()
}
//constellation
#ifndef SERVER_MODE
if (m_tvScreen)
{
qDebug("DATVDemodSink::InitDATVFramework: Register DVB constellation TV screen");
@ -771,7 +802,7 @@ void DATVDemodSink::InitDATVFramework()
r_scope_symbols->cstln = &m_objDemodulator->cstln;
r_scope_symbols->calculate_cstln_points();
}
#endif
r_merMeter = new leansdr::datvmeter(m_objScheduler, *p_mer);
r_cnrMeter = new leansdr::datvmeter(m_objScheduler, *p_cnr);
@ -847,6 +878,7 @@ void DATVDemodSink::InitDATVFramework()
r_videoplayer = new leansdr::datvvideoplayer<leansdr::tspacket>(m_objScheduler, *p_tspackets, nullptr, &m_udpStream);
}
r_videoplayer->setSymbolRate(m_settings.m_symbolRate);
m_blnDVBInitialized = true;
}
@ -873,8 +905,7 @@ void DATVDemodSink::InitDATVS2Framework()
<< " Excursion: " << m_settings.m_excursion
<< " Channel sample rate: " << m_channelSampleRate
<< " Input sample rate: " << 2 * m_settings.m_symbolRate
<< " m_softLDPCMaxTrials: " << m_settings.m_softLDPCMaxTrials
<< " m_softLDPCToolPath: " << m_settings.m_softLDPCToolPath;
<< " m_softLDPCMaxTrials: " << m_settings.m_softLDPCMaxTrials;
m_objCfg.standard = m_settings.m_standard;
@ -1067,7 +1098,7 @@ void DATVDemodSink::InitDATVS2Framework()
m_cstlnSetByModcod = false;
//constellation
#ifndef SERVER_MODE
if (m_tvScreen)
{
qDebug("DATVDemodSink::InitDATVS2Framework: Register DVBS 2 TVSCREEN");
@ -1076,7 +1107,7 @@ void DATVDemodSink::InitDATVS2Framework()
r_scope_symbols_dvbs2->cstln = (leansdr::cstln_base**) &objDemodulatorDVBS2->cstln;
r_scope_symbols_dvbs2->calculate_cstln_points();
}
#endif
r_merMeter = new leansdr::datvmeter(m_objScheduler, *p_mer);
r_cnrMeter = new leansdr::datvmeter(m_objScheduler, *p_cnr);
@ -1098,12 +1129,6 @@ void DATVDemodSink::InitDATVS2Framework()
// bool commandFileValid = false;
if (QFileInfo::exists(m_settings.m_softLDPCToolPath))
{
QFileInfo fileInfo = QFileInfo(m_settings.m_softLDPCToolPath);
// commandFileValid = fileInfo.isExecutable();
}
if (m_settings.m_softLDPC /*&& commandFileValid*/)
{
#if 0
@ -1128,8 +1153,6 @@ void DATVDemodSink::InitDATVS2Framework()
// External LDPC decoder mode.
// Deinterleave into soft bits.
// TBD Latency
QByteArray ba = m_settings.m_softLDPCToolPath.toLocal8Bit();
const char *c_str2 = ba.data();
p_fecframes = new leansdr::pipebuf<leansdr::fecframe<leansdr::llr_sb> >(m_objScheduler, "FEC frames", BUF_FRAMES);
p_s2_deinterleaver = new leansdr::s2_deinterleaver<leansdr::llr_ss, leansdr::llr_sb>(
m_objScheduler,
@ -1141,7 +1164,6 @@ void DATVDemodSink::InitDATVS2Framework()
m_objScheduler,
*(leansdr::pipebuf< leansdr::fecframe<leansdr::llr_sb> > *) p_fecframes,
*(leansdr::pipebuf<leansdr::bbframe> *) p_bbframes,
c_str2,
p_vbitcount,
p_verrcount)
;
@ -1190,6 +1212,7 @@ void DATVDemodSink::InitDATVS2Framework()
r_videoplayer = new leansdr::datvvideoplayer<leansdr::tspacket>(m_objScheduler, *p_tspackets, nullptr, &m_udpStream);
}
r_videoplayer->setSymbolRate(m_settings.m_symbolRate);
m_blnDVBInitialized = true;
}
@ -1205,10 +1228,12 @@ void DATVDemodSink::feed(const SampleVector::const_iterator& begin, const Sample
{
qDebug("DATVDemodSink::feed: change by MODCOD detected");
// Update constellation
#ifndef SERVER_MODE
if (r_scope_symbols_dvbs2) {
r_scope_symbols_dvbs2->calculate_cstln_points();
}
#endif
if (getMessageQueueToGUI())
{
DATVDemodReport::MsgReportModcodCstlnChange *msg = DATVDemodReport::MsgReportModcodCstlnChange::create(
@ -1362,6 +1387,7 @@ void DATVDemodSink::applySettings(const DATVDemodSettings& settings, bool force)
return;
}
#ifndef SERVER_MODE
if ((settings.m_audioVolume) != (m_settings.m_audioVolume) || force)
{
if (m_videoRender) {
@ -1382,6 +1408,7 @@ void DATVDemodSink::applySettings(const DATVDemodSettings& settings, bool force)
m_videoRender->setVideoMute(settings.m_videoMute);
}
}
#endif
if ((m_settings.m_rfBandwidth != settings.m_rfBandwidth)
|| (m_settings.m_symbolRate != settings.m_symbolRate)
@ -1393,8 +1420,19 @@ void DATVDemodSink::applySettings(const DATVDemodSettings& settings, bool force)
m_nco.setFreq(-(float) settings.m_centerFrequency, (float) m_channelSampleRate);
}
if ((m_settings.m_udpTS != settings.m_udpTS) || force) {
if ((m_settings.m_udpTS != settings.m_udpTS) || force)
{
m_udpStream.setActive(settings.m_udpTS);
if (r_videoplayer && !settings.m_udpTS) {
r_videoplayer->resetUDPRunning();
}
}
if ((m_settings.m_symbolRate != settings.m_symbolRate) || force) {
if (r_videoplayer) {
r_videoplayer->setSymbolRate(settings.m_symbolRate);
}
}
if ((m_settings.m_udpTSAddress != settings.m_udpTSAddress) || force) {

View File

@ -30,13 +30,14 @@
#include "leansdr/hdlc.h"
#include "leansdr/iess.h"
#ifndef SERVER_MODE
#include "datvconstellation.h"
#include "datvmeter.h"
#include "datvdvbs2constellation.h"
#endif
#include "datvmeter.h"
#include "datvvideoplayer.h"
#include "datvideostream.h"
#include "datvudpstream.h"
#include "datvideorender.h"
#include "datvdemodsettings.h"
#include "dsp/channelsamplesink.h"
@ -50,6 +51,7 @@
class TVScreen;
class DATVideoRender;
class DATVideoRenderThread;
class QLabel;
class DATVDemodSink : public ChannelSampleSink {
@ -314,8 +316,10 @@ private:
leansdr::datvvideoplayer<leansdr::tspacket> *r_videoplayer;
//CONSTELLATION
#ifndef SERVER_MODE
leansdr::datvconstellation<leansdr::f32> *r_scope_symbols;
leansdr::datvdvbs2constellation<leansdr::f32> *r_scope_symbols_dvbs2;
#endif
leansdr::datvmeter *r_merMeter;
leansdr::datvmeter *r_cnrMeter;

View File

@ -31,88 +31,6 @@ namespace leansdr {
static const int DEFAULT_GUI_DVBS2_DECIMATION = 64;
static inline cstln_lut<llr_ss, 256> * make_dvbs2_constellation(
cstln_lut<llr_ss, 256>::predef c,
code_rate r
)
{
float gamma1 = 1, gamma2 = 1, gamma3 = 1;
switch (c)
{
case cstln_lut<llr_ss, 256>::APSK16:
// EN 302 307, section 5.4.3, Table 9
switch (r)
{
case FEC23:
case FEC46:
gamma1 = 3.15;
break;
case FEC34:
gamma1 = 2.85;
break;
case FEC45:
gamma1 = 2.75;
break;
case FEC56:
gamma1 = 2.70;
break;
case FEC89:
gamma1 = 2.60;
break;
case FEC910:
gamma1 = 2.57;
break;
default:
fail("cstln_lut<256>::make_dvbs2_constellation: Code rate not supported with APSK16");
return 0;
}
break;
case cstln_lut<llr_ss, 256>::APSK32:
// EN 302 307, section 5.4.4, Table 10
switch (r)
{
case FEC34:
gamma1 = 2.84;
gamma2 = 5.27;
break;
case FEC45:
gamma1 = 2.72;
gamma2 = 4.87;
break;
case FEC56:
gamma1 = 2.64;
gamma2 = 4.64;
break;
case FEC89:
gamma1 = 2.54;
gamma2 = 4.33;
break;
case FEC910:
gamma1 = 2.53;
gamma2 = 4.30;
break;
default:
fail("cstln_lut<llr_ss, 256>::make_dvbs2_constellation: Code rate not supported with APSK32");
return 0;
}
break;
case cstln_lut<llr_ss, 256>::APSK64E:
// EN 302 307-2, section 5.4.5, Table 13f
gamma1 = 2.4;
gamma2 = 4.3;
gamma3 = 7;
break;
default:
break;
}
cstln_lut<llr_ss, 256> *newCstln = new cstln_lut<llr_ss, 256>(c, 10, gamma1, gamma2, gamma3);
newCstln->m_rateCode = r < code_rate::FEC_COUNT ? r : -1;
newCstln->m_typeCode = c < cstln_lut<llr_ss, 256>::predef::COUNT ? c : -1;
newCstln->m_setByModcod = false;
return newCstln;
}
template<typename T> struct datvdvbs2constellation: runnable
{

View File

@ -42,12 +42,6 @@ void DatvDvbS2LdpcDialog::accept()
QDialog::accept();
}
void DatvDvbS2LdpcDialog::setFileName(const QString& fileName)
{
m_fileName = fileName;
ui->ldpcToolText->setText(m_fileName);
}
void DatvDvbS2LdpcDialog::setMaxTrials(int maxTrials)
{
m_maxTrials = maxTrials < 1 ? 1 :
@ -55,31 +49,6 @@ void DatvDvbS2LdpcDialog::setMaxTrials(int maxTrials)
ui->maxTrials->setValue(m_maxTrials);
}
void DatvDvbS2LdpcDialog::on_showFileDialog_clicked(bool checked)
{
(void) checked;
QFileDialog fileDialog(this, "Select LDPC tool");
fileDialog.setOption(QFileDialog::DontUseNativeDialog, true);
#ifdef _MSC_VER
fileDialog.setNameFilter("*.exe");
#else
fileDialog.setFilter(QDir::Executable | QDir::Files);
#endif
fileDialog.selectFile(m_fileName);
if (fileDialog.exec() == QDialog::Accepted)
{
QStringList fileNames = fileDialog.selectedFiles();
if (fileNames.size() > 0)
{
m_fileName = fileNames[0];
ui->ldpcToolText->setText(m_fileName);
}
}
}
void DatvDvbS2LdpcDialog::on_maxTrials_valueChanged(int value)
{
m_maxTrials = value;

View File

@ -33,19 +33,15 @@ public:
explicit DatvDvbS2LdpcDialog(QWidget* parent = nullptr);
~DatvDvbS2LdpcDialog();
void setFileName(const QString& fileName);
void setMaxTrials(int maxTrials);
QString& getFileName() { return m_fileName; }
int getMaxTrials() { return m_maxTrials; }
private:
Ui::DatvDvbS2LdpcDialog* ui;
QString m_fileName;
int m_maxTrials;
private slots:
void accept();
void on_showFileDialog_clicked(bool checked);
void on_maxTrials_valueChanged(int value);
};

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>461</width>
<height>121</height>
<width>454</width>
<height>80</height>
</rect>
</property>
<property name="font">
@ -63,66 +63,6 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="logFileLayout">
<item>
<widget class="QLabel" name="ldpcToolLabel">
<property name="text">
<string>LDPC tool</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="showFileDialog">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Choose a log file</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/preset-load.png</normaloff>:/preset-load.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="ldpcToolText">
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Log file</string>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">

View File

@ -42,7 +42,9 @@ template<typename T> struct datvvideoplayer: runnable
in(_in),
m_videoStream(videoStream),
m_udpStream(udpStream),
m_atomicUDPRunning(0)
m_atomicUDPRunning(0),
m_count(0),
m_sr(1500000)
{
}
@ -50,7 +52,18 @@ template<typename T> struct datvvideoplayer: runnable
{
int size = in.readable() * sizeof(T);
if (!size) {
if (!size)
{
if (m_count == 0)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
m_atomicUDPRunning.storeRelaxed(0);
#else
m_atomicUDPRunning.store(0);
#endif
} else {
m_count--;
}
return;
}
@ -62,6 +75,8 @@ template<typename T> struct datvvideoplayer: runnable
#else
m_atomicUDPRunning.store(m_udpStream->isActive() && (size > 0) ? 1 : 0);
#endif
m_count = m_sr / 10000;
if (m_videoStream)
{
nw = m_videoStream->pushData((const char *) in.rd(), size);
@ -114,11 +129,18 @@ template<typename T> struct datvvideoplayer: runnable
#endif
}
void setSymbolRate(unsigned int sr)
{
m_sr = sr;
}
private:
pipereader<T> in;
DATVideostream *m_videoStream;
DATVUDPStream *m_udpStream;
QAtomicInt m_atomicUDPRunning;
unsigned int m_count;
unsigned int m_sr; // Symbol rate in S/s used for UDP running detection
};
}

View File

@ -700,8 +700,9 @@ struct s2_frame_receiver : runnable
char *format() {
static char buf[256];
sprintf(
snprintf(
buf,
sizeof(buf),
"%9.2lf %+6.0f ppm %+3.0f ° %f",
(double)((p-(std::complex<T>*)NULL)&262143)+mu, // Arbitrary wrap
fw16*1e6/65536,
@ -3516,11 +3517,11 @@ struct s2_fecdec_helper : runnable
close(rx[0]);
dup2(rx[1], 1);
char max_trials_arg[16];
sprintf(max_trials_arg, "%d", max_trials);
snprintf(max_trials_arg, sizeof(max_trial_args), "%d", max_trials);
char batch_size_arg[16];
sprintf(batch_size_arg, "%d", batch_size);
snprintf(batch_size_arg, sizeof(batch_size_args), "%d", batch_size);
char mc_arg[16];
sprintf(mc_arg, "%d", pls->modcod);
snprintf(mc_arg, sizeof(mc_arg), "%d", pls->modcod);
const char *sf_arg = pls->sf ? "--shortframes" : nullptr;
const char *argv[] = {
command,
@ -3643,7 +3644,6 @@ struct s2_fecdec_helper : runnable
scheduler *sch,
pipebuf<fecframe<SOFTBYTE>> &_in,
pipebuf<bbframe> &_out,
const char *_command,
pipebuf<int> *_bitcount = nullptr,
pipebuf<int> *_errcount = nullptr
) :
@ -3657,7 +3657,6 @@ struct s2_fecdec_helper : runnable
bitcount(opt_writer(_bitcount, 1)),
errcount(opt_writer(_errcount, 1))
{
command = strdup(_command);
for (int mc = 0; mc < 32; ++mc) {
for (int sf = 0; sf < 2; ++sf) {
@ -3668,7 +3667,6 @@ struct s2_fecdec_helper : runnable
~s2_fecdec_helper()
{
free(command);
killall(); // also deletes pools[mc][sf].procs if necessary
}

View File

@ -368,7 +368,7 @@ struct slowmultiscope : runnable
channel *c = &chans[i];
g.setfg(c->spec.rgb[0], c->spec.rgb[1], c->spec.rgb[2]);
char text[256];
sprintf(text, c->spec.format, c->print_val);
snprintf(text, sizeof(text), c->spec.format, c->print_val);
g.transient_text(5, 20 + 16 * i, text);
}
run_gui();
@ -445,7 +445,7 @@ struct slowmultiscope : runnable
float ct = g.mx * samples_per_pixel / sample_freq;
float tt = total_samples / sample_freq;
char text[256];
sprintf(text, "%.3f / %.3f s", ct, tt);
snprintf(text, sizeof(text), "%.3f / %.3f s", ct, tt);
g.setfg(255, 255, 255);
g.transient_text(g.w * 3 / 4, 20, text);
}
@ -529,7 +529,7 @@ struct spectrumscope : runnable
{
char s[256];
float f = 2.4e6 * (g.mx - g.w / 2) / g.w;
sprintf(s, "%f", f);
snprintf(s, sizeof(s), "%f", f);
g.text(16, 16, s);
}
g.show();
@ -637,7 +637,7 @@ struct rfscope : runnable
char s[256];
float freq = Fc + Fs * (g.mx - g.w / 2) / g.w / hzoom;
float val = db0 + (float)((g.h - 1) - g.my) * dbrange / g.h;
sprintf(s, "%f.3 Hz %f.2 dB", freq, val);
snprintf(s, sizeof(s), "%f.3 Hz %f.2 dB", freq, val);
g.setfg(255, 255, 255);
g.text(16, 16, s);
}
@ -726,7 +726,7 @@ struct genscope : runnable
g.line(pc->spec.r.x - dx, pc->spec.r.y - dy,
pc->spec.r.x + dx, pc->spec.r.y + dy);
char txt[16];
sprintf(txt, "%d", (int)last);
snprintf(txt, sizeof(txt), "%d", (int)last);
g.text(pc->spec.r.x + 5, pc->spec.r.y - 2, txt);
}
struct timeval newtv;

View File

@ -191,7 +191,7 @@ It can be used to decode signals lower that ~10 db MER which is the limit of LDP
Right clicking on this control opens a dialog where you can choose:
- The `ldpctool` executable. Obsolete.
- ~~The `ldpctool` executable.~~ Obsolete removed.
- The maximum of retries in LDPC decoding from 1 to 8.
<h5>B.2b.7: DVB-S2 specific - LDPC maximum number of bit flips allowed</h5>

View File

@ -33,7 +33,7 @@
const PluginDescriptor NavtexDemodPlugin::m_pluginDescriptor = {
NavtexDemod::m_channelId,
QStringLiteral("Navtex Demodulator"),
QStringLiteral("7.22.5"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Jon Beniston, M7RCE"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -354,7 +354,7 @@ void NavtexDemodSink::receiveBit(bool bit)
getMessageQueueToChannel()->push(msg);
}
// Add character to message buffer
m_messageBuffer.append(QChar(c));
m_messageBuffer.append(QChar((char) c));
}
else
{

View File

@ -34,7 +34,7 @@
const PluginDescriptor RemoteSinkPlugin::m_pluginDescriptor = {
RemoteSink::m_channelId,
QStringLiteral("Remote channel sink"),
QStringLiteral("7.22.5"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -17,6 +17,7 @@
#include <QMutexLocker>
#include <QThread>
#include <QDebug>
#include <boost/crc.hpp>
#include <boost/cstdint.hpp>

View File

@ -258,8 +258,8 @@ void PacketModGUI::on_insertPosition_clicked()
longFrac = round(longitude);
// Insert position with house symbol (-) in to data field
sprintf(latBuf, "%02d%02d.%02d%c", latDeg, latMin, latFrac, latNorth ? 'N' : 'S');
sprintf(longBuf, "%03d%02d.%02d%c", longDeg, longMin, longFrac, longEast ? 'E' : 'W');
snprintf(latBuf, sizeof(latBuf), "%02d%02d.%02d%c", latDeg, latMin, latFrac, latNorth ? 'N' : 'S');
snprintf(longBuf, sizeof(longBuf), "%03d%02d.%02d%c", longDeg, longMin, longFrac, longEast ? 'E' : 'W');
QString packet = QString("%1/%2-").arg(latBuf).arg(longBuf);
ui->packet->insert(packet);
}

View File

@ -33,7 +33,7 @@
const PluginDescriptor PacketModPlugin::m_pluginDescriptor = {
PacketMod::m_channelId,
QStringLiteral("Packet Modulator"),
QStringLiteral("7.22.5"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Jon Beniston, M7RCE"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -32,7 +32,7 @@
const PluginDescriptor RemoteSourcePlugin::m_pluginDescriptor = {
RemoteSource::m_channelId,
QStringLiteral("Remote channel source"),
QStringLiteral("7.22.5"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -15,6 +15,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include <boost/crc.hpp>
#include <boost/cstdint.hpp>

View File

@ -75,7 +75,7 @@ void AMBEEngine::getComList()
// Arbitrarily set the list to the 20 first COM ports
for (int i = 1; i <= 20; i++)
{
sprintf(comCStr, "COM%d", i);
snprintf(comCStr, sizeof(comCStr), "COM%d", i);
m_comList.push_back(std::string(comCStr));
}
}

View File

@ -31,7 +31,7 @@
const PluginDescriptor AMBEPlugin::m_pluginDescriptor = {
AMBE::m_featureId,
QStringLiteral("AMBE Controller"),
QStringLiteral("7.22.1"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -34,7 +34,7 @@
const PluginDescriptor GS232ControllerPlugin::m_pluginDescriptor = {
GS232Controller::m_featureId,
QStringLiteral("Rotator Controller"),
QStringLiteral("7.22.1"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Jon Beniston, M7RCE"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -54,23 +54,37 @@ void GS232Protocol::readData()
if (len != -1)
{
QString response = QString::fromUtf8(buf, len);
// MD-02 can return AZ=-00 EL=-00 and other negative angles
QRegularExpression re("AZ=([-\\d]\\d\\d) *EL=([-\\d]\\d\\d)");
QRegularExpressionMatch match = re.match(response);
if (match.hasMatch())
// Handle both formats:
// 1. AZ=XXX EL=XXX (MD-02 can return negative angles like AZ=-00 EL=-00)
// 2. +XXXX+YYYY (direct angle format)
QRegularExpression reAzEl("AZ=([-\\d]\\d\\d) *EL=([-\\d]\\d\\d)");
QRegularExpression reAngles("([+-]\\d{4})([+-]\\d{4})");
QRegularExpressionMatch matchAzEl = reAzEl.match(response);
QRegularExpressionMatch matchAngles = reAngles.match(response);
if (matchAzEl.hasMatch())
{
QString az = match.captured(1);
QString el = match.captured(2);
//qDebug() << "SPIDProtocol::readData read Az " << az << " El " << el;
QString az = matchAzEl.captured(1);
QString el = matchAzEl.captured(2);
//qDebug() << "GS232Protocol::readData read Az " << az << " El " << el;
reportAzEl(az.toFloat(), el.toFloat());
}
else if (matchAngles.hasMatch())
{
// Convert from +XXXX format to float
QString az = matchAngles.captured(1);
QString el = matchAngles.captured(2);
//qDebug() << "GS232Protocol::readData read direct angles Az " << az << " El " << el;
// The format gives angles in tenths of a degree, so divide by 10
reportAzEl(az.toFloat()/10.0f, el.toFloat()/10.0f);
}
else if (response == "\r\n")
{
// Ignore
}
else
{
qWarning() << "SPIDProtocol::readData - unexpected GS-232 response \"" << response << "\"";
qWarning() << "GS232Protocol::readData - unexpected GS-232 response \"" << response << "\"";
reportError(QString("Unexpected GS-232 response: %1").arg(response));
}
}

View File

@ -31,7 +31,7 @@
const PluginDescriptor RigCtlServerPlugin::m_pluginDescriptor = {
RigCtlServer::m_featureId,
QStringLiteral("RigCtl Server"),
QStringLiteral("7.22.1"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Jon Beniston, M7RCE and Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -203,7 +203,7 @@ void RigCtlServerWorker::getCommand()
// Set frequency
double targetFrequency = atof(cmd[0] == 'F' ? &cmd[2] : &cmd[9]);
setFrequency(targetFrequency, rigCtlRC);
sprintf(response, "RPRT %d\n", rigCtlRC);
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
else if (!strncmp(cmd, "f", 1) || !strncmp(cmd, "get_freq", 8))
{
@ -211,9 +211,9 @@ void RigCtlServerWorker::getCommand()
double frequency;
if (getFrequency(frequency, rigCtlRC)) {
sprintf(response, "%u\n", (unsigned int) frequency);
snprintf(response, sizeof(response), "%u\n", (unsigned int) frequency);
} else {
sprintf(response, "RPRT %d\n", rigCtlRC);
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
}
else if (!strncmp(cmd, "M ?", 3) || !(strncmp(cmd, "set_mode ?", 10)))
@ -263,11 +263,11 @@ void RigCtlServerWorker::getCommand()
if (m_modeMap[i].modem != nullptr)
{
changeModem(targetMode, targetModem, targetBW, rigCtlRC);
sprintf(response, "RPRT %d\n", rigCtlRC);
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
else
{
sprintf(response, "RPRT %d\n", RIG_EINVAL);
snprintf(response, sizeof(response), "RPRT %d\n", RIG_EINVAL);
m_clientConnection->write(response, strlen(response));
}
}
@ -280,27 +280,27 @@ void RigCtlServerWorker::getCommand()
if (getMode(&mode, passband, rigCtlRC))
{
if (passband < 0) {
sprintf(response, "%s\n", mode);
snprintf(response, sizeof(response), "%s\n", mode);
} else {
sprintf(response, "%s %u\n", mode, (unsigned int) passband);
snprintf(response, sizeof(response), "%s %u\n", mode, (unsigned int) passband);
}
}
else
{
sprintf(response, "RPRT %d\n", rigCtlRC);
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
}
else if (!strncmp(cmd, "set_powerstat 0", 15))
{
// Power off radio
setPowerOff(rigCtlRC);
sprintf(response, "RPRT %d\n", rigCtlRC);
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
else if (!strncmp(cmd, "set_powerstat 1", 15))
{
// Power on radio
setPowerOn(rigCtlRC);
sprintf(response, "RPRT %d\n", rigCtlRC);
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
else if (!strncmp(cmd, "get_powerstat", 13))
{
@ -309,20 +309,20 @@ void RigCtlServerWorker::getCommand()
if (getPower(power, rigCtlRC))
{
if (power) {
sprintf(response, "1\n");
snprintf(response, sizeof(response), "1\n");
} else {
sprintf(response, "0\n");
snprintf(response, sizeof(response), "0\n");
}
}
else
{
sprintf(response, "RPRT %d\n", rigCtlRC);
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
}
else
{
// Unimplemented command
sprintf(response, "RPRT %d\n", RIG_ENIMPL);
snprintf(response, sizeof(response), "RPRT %d\n", RIG_ENIMPL);
m_clientConnection->write(response, strlen(response));
}
}

View File

@ -34,7 +34,7 @@
const PluginDescriptor SatelliteTrackerPlugin::m_pluginDescriptor = {
SatelliteTracker::m_featureId,
QStringLiteral("Satellite Tracker"),
QStringLiteral("7.22.3"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Jon Beniston, M7RCE and Daniel Warner (SGP4 library)"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -826,9 +826,7 @@ void SatelliteTrackerWorker::enableDoppler(SatWorkerState *satWorkerState)
if (devSettings->m_doppler.size() > 0)
{
requiresDoppler = true;
for (int j = 0; j < devSettings->m_doppler.size(); j++) {
satWorkerState->m_doppler.append(0);
}
satWorkerState->m_doppler.append(0);
}
}
if (requiresDoppler)
@ -836,7 +834,8 @@ void SatelliteTrackerWorker::enableDoppler(SatWorkerState *satWorkerState)
qDebug() << "SatelliteTrackerWorker::applyDeviceAOSSettings: Enabling doppler for " << satWorkerState->m_name;
satWorkerState->m_dopplerTimer.setInterval(m_settings.m_dopplerPeriod * 1000);
satWorkerState->m_dopplerTimer.start();
connect(&satWorkerState->m_dopplerTimer, &QTimer::timeout, [this, satWorkerState]() {
disconnect(satWorkerState->m_connection);
satWorkerState->m_connection = connect(&satWorkerState->m_dopplerTimer, &QTimer::timeout, [this, satWorkerState]() {
doppler(satWorkerState);
});
}
@ -848,29 +847,46 @@ void SatelliteTrackerWorker::disableDoppler(SatWorkerState *satWorkerState)
// Stop Doppler timer, and set interval to 0, so we don't restart it in start()
satWorkerState->m_dopplerTimer.stop();
satWorkerState->m_dopplerTimer.setInterval(0);
disconnect(satWorkerState->m_connection);
// Remove doppler correction from any channel
QList<SatelliteTrackerSettings::SatelliteDeviceSettings *> *m_deviceSettingsList = m_settings.m_deviceSettings.value(satWorkerState->m_name);
if (m_deviceSettingsList)
if (satWorkerState->m_doppler.size() > 0)
{
for (int i = 0; i < m_deviceSettingsList->size(); i++)
QList<SatelliteTrackerSettings::SatelliteDeviceSettings *> *m_deviceSettingsList = m_settings.m_deviceSettings.value(satWorkerState->m_name);
if (m_deviceSettingsList)
{
SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = m_deviceSettingsList->at(i);
if (devSettings->m_doppler.size() > 0)
int idx = 0;
for (int i = 0; i < m_deviceSettingsList->size(); i++)
{
for (int j = 0; j < devSettings->m_doppler.size(); j++)
SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = m_deviceSettingsList->at(i);
if (devSettings->m_doppler.size() > 0)
{
int offset;
if (ChannelWebAPIUtils::getFrequencyOffset(devSettings->m_deviceSetIndex, devSettings->m_doppler[j], offset))
for (int j = 0; j < devSettings->m_doppler.size(); j++)
{
// Remove old doppler
offset += satWorkerState->m_doppler[i];
if (!ChannelWebAPIUtils::setFrequencyOffset(devSettings->m_deviceSetIndex, devSettings->m_doppler[j], offset))
qDebug() << "SatelliteTrackerWorker::doppler: Failed to set frequency offset";
int offset;
if (ChannelWebAPIUtils::getFrequencyOffset(devSettings->m_deviceSetIndex, devSettings->m_doppler[j], offset))
{
// Remove old doppler
std::vector<DeviceSet*>& deviceSets = MainCore::instance()->getDeviceSets();
ChannelAPI *channel = deviceSets[devSettings->m_deviceSetIndex]->getChannelAt(j);
int tx = false;
if (channel) {
tx = channel->getStreamType() == ChannelAPI::StreamSingleSource; // What if MIMO?
}
if (tx) {
offset -= satWorkerState->m_doppler[idx];
} else {
offset += satWorkerState->m_doppler[idx];
}
if (!ChannelWebAPIUtils::setFrequencyOffset(devSettings->m_deviceSetIndex, devSettings->m_doppler[j], offset))
qDebug() << "SatelliteTrackerWorker::disableDoppler: Failed to set frequency offset";
}
else
qDebug() << "SatelliteTrackerWorker::disableDoppler: Failed to get frequency offset";
}
else
qDebug() << "SatelliteTrackerWorker::doppler: Failed to get frequency offset";
satWorkerState->m_doppler[idx] = 0;
idx++;
}
satWorkerState->m_doppler[i] = 0;
}
}
}
@ -883,6 +899,8 @@ void SatelliteTrackerWorker::doppler(SatWorkerState *satWorkerState)
QList<SatelliteTrackerSettings::SatelliteDeviceSettings *> *m_deviceSettingsList = m_settings.m_deviceSettings.value(satWorkerState->m_name);
if (m_deviceSettingsList)
{
int idx = 0;
for (int i = 0; i < m_deviceSettingsList->size(); i++)
{
SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = m_deviceSettingsList->at(i);
@ -915,15 +933,14 @@ void SatelliteTrackerWorker::doppler(SatWorkerState *satWorkerState)
int initOffset;
if (tx)
{
initOffset = offset - satWorkerState->m_doppler[i];
initOffset = offset - satWorkerState->m_doppler[idx];
offset = initOffset + doppler;
}
else
{
initOffset = offset + satWorkerState->m_doppler[i];
initOffset = offset + satWorkerState->m_doppler[idx];
offset = initOffset - doppler;
}
if (!ChannelWebAPIUtils::setFrequencyOffset(devSettings->m_deviceSetIndex, devSettings->m_doppler[j], offset))
qDebug() << "SatelliteTrackerWorker::doppler: Failed to set frequency offset";
}
@ -931,10 +948,12 @@ void SatelliteTrackerWorker::doppler(SatWorkerState *satWorkerState)
qDebug() << "SatelliteTrackerWorker::doppler: Failed to get frequency offset";
}
satWorkerState->m_doppler[i] = doppler;
satWorkerState->m_doppler[idx] = doppler;
}
else
qDebug() << "SatelliteTrackerWorker::doppler: couldn't get centre frequency for device at " << devSettings->m_deviceSetIndex;
idx++;
}
}
}

View File

@ -65,6 +65,7 @@ protected:
QList<int> m_doppler; // How much doppler we've applied to a channel
SatelliteState m_satState;
bool m_hasSignalledAOS; // For pass specified by m_aos and m_los
QMetaObject::Connection m_connection;
friend SatelliteTrackerWorker;
};

View File

@ -627,7 +627,7 @@ void AudioCATSISO::listComPorts()
{
m_comPorts.clear();
std::vector<std::string> comPorts;
SerialUtil::getComPorts(comPorts, "tty(USB|ACM)[0-9]+"); // regex is for Linux only
SerialUtil::getComPorts(comPorts, "tty(S|USB|ACM)[0-9]+"); // regex is for Linux only
for (std::vector<std::string>::const_iterator it = comPorts.begin(); it != comPorts.end(); ++it) {
m_comPorts.push_back(QString(it->c_str()));

View File

@ -32,7 +32,7 @@
const PluginDescriptor AudioCATSISOPlugin::m_pluginDescriptor = {
QStringLiteral("AudioCATSISO"),
QStringLiteral("Audio CAT SISO"),
QStringLiteral("7.22.1"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -33,7 +33,7 @@
const PluginDescriptor MetisMISOPlugin::m_pluginDescriptor = {
QStringLiteral("MetisMISO"),
QStringLiteral("Metis MISO"),
QStringLiteral("7.22.1"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -16,6 +16,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include "dsp/samplemififo.h"
#include "dsp/samplemofifo.h"

View File

@ -807,7 +807,9 @@ bool LimeSDROutput::applySettings(const LimeSDROutputSettings& settings, const Q
if (settingsKeys.contains("devSampleRate")
|| settingsKeys.contains("log2HardInterp") || force)
{
forwardChangeAllDSP = true; //m_settings.m_devSampleRate != settings.m_devSampleRate;
//forwardChangeAllDSP = true; //m_settings.m_devSampleRate != settings.m_devSampleRate;
forwardChangeTxDSP = m_settings.m_log2HardInterp != settings.m_log2HardInterp;
forwardChangeAllDSP = m_settings.m_devSampleRate != settings.m_devSampleRate;
if (m_deviceShared.m_deviceParams->getDevice())
{

View File

@ -90,7 +90,7 @@ LimeSDROutputGUI::LimeSDROutputGUI(DeviceUISet *deviceUISet, QWidget* parent) :
displaySettings();
char recFileNameCStr[30];
sprintf(recFileNameCStr, "test_%d.sdriq", m_deviceUISet->m_deviceAPI->getDeviceUID());
snprintf(recFileNameCStr, sizeof(recFileNameCStr), "test_%d.sdriq", m_deviceUISet->m_deviceAPI->getDeviceUID());
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &)));

View File

@ -36,7 +36,7 @@
const PluginDescriptor LimeSDROutputPlugin::m_pluginDescriptor = {
QStringLiteral("LimeSDR"),
QStringLiteral("LimeSDR Output"),
QStringLiteral("7.22.1"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -82,7 +82,7 @@ USRPOutputGUI::USRPOutputGUI(DeviceUISet *deviceUISet, QWidget* parent) :
displaySettings();
char recFileNameCStr[30];
sprintf(recFileNameCStr, "test_%d.sdriq", m_deviceUISet->m_deviceAPI->getDeviceUID());
snprintf(recFileNameCStr, sizeof(recFileNameCStr), "test_%d.sdriq", m_deviceUISet->m_deviceAPI->getDeviceUID());
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &)));

View File

@ -36,7 +36,7 @@
const PluginDescriptor USRPOutputPlugin::m_pluginDescriptor = {
QStringLiteral("USRP"),
QStringLiteral("URSP Output"),
QStringLiteral("7.22.6"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Jon Beniston, M7RCE and Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -33,7 +33,7 @@
const PluginDescriptor HackRFInputPlugin::m_pluginDescriptor = {
QStringLiteral("HackRF"),
QStringLiteral("HackRF Input"),
QStringLiteral("7.22.1"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -969,8 +969,14 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, const QLi
if (settingsKeys.contains("devSampleRate")
|| settingsKeys.contains("log2HardDecim") || force)
{
forwardChangeAllDSP = true; //m_settings.m_devSampleRate != settings.m_devSampleRate;
if(!settings.m_splitFreq) {
forwardChangeAllDSP = true; //m_settings.m_devSampleRate != settings.m_devSampleRate;
qDebug() << "LimeSDRInput::applySettings: Split is false, val:" << settings.m_splitFreq;
}else{
forwardChangeRxDSP = m_settings.m_log2HardDecim != settings.m_log2HardDecim;
forwardChangeAllDSP = m_settings.m_devSampleRate != settings.m_devSampleRate;
}
if (m_deviceShared.m_deviceParams->getDevice() && m_channelAcquired)
{
if (LMS_SetSampleRateDir(m_deviceShared.m_deviceParams->getDevice(),
@ -1439,6 +1445,9 @@ void LimeSDRInput::webapiUpdateDeviceSettings(
if (deviceSettingsKeys.contains("dcBlock")) {
settings.m_dcBlock = response.getLimeSdrInputSettings()->getDcBlock() != 0;
}
if (deviceSettingsKeys.contains("splitFreq")) {
settings.m_splitFreq = response.getLimeSdrInputSettings()->getSplitFreq() != 0;
}
if (deviceSettingsKeys.contains("devSampleRate")) {
settings.m_devSampleRate = response.getLimeSdrInputSettings()->getDevSampleRate();
}
@ -1521,6 +1530,7 @@ void LimeSDRInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& re
response.getLimeSdrInputSettings()->setAntennaPath((int) settings.m_antennaPath);
response.getLimeSdrInputSettings()->setCenterFrequency(settings.m_centerFrequency);
response.getLimeSdrInputSettings()->setDcBlock(settings.m_dcBlock ? 1 : 0);
response.getLimeSdrInputSettings()->setSplitFreq(settings.m_splitFreq ? 1 : 0);
response.getLimeSdrInputSettings()->setDevSampleRate(settings.m_devSampleRate);
response.getLimeSdrInputSettings()->setExtClock(settings.m_extClock ? 1 : 0);
response.getLimeSdrInputSettings()->setExtClockFreq(settings.m_extClockFreq);
@ -1653,6 +1663,9 @@ void LimeSDRInput::webapiReverseSendSettings(const QList<QString>& deviceSetting
if (deviceSettingsKeys.contains("dcBlock") || force) {
swgLimeSdrInputSettings->setDcBlock(settings.m_dcBlock ? 1 : 0);
}
if (deviceSettingsKeys.contains("splitFreq") || force) {
swgLimeSdrInputSettings->setSplitFreq(settings.m_splitFreq ? 1 : 0);
}
if (deviceSettingsKeys.contains("devSampleRate") || force) {
swgLimeSdrInputSettings->setDevSampleRate(settings.m_devSampleRate);
}

View File

@ -428,6 +428,7 @@ void LimeSDRInputGUI::displaySettings()
displaySampleRate();
ui->dcOffset->setChecked(m_settings.m_dcBlock);
ui->splitFreq->setChecked(m_settings.m_splitFreq);
ui->iqImbalance->setChecked(m_settings.m_iqCorrection);
ui->hwDecim->setCurrentIndex(m_settings.m_log2HardDecim);
@ -635,6 +636,13 @@ void LimeSDRInputGUI::on_dcOffset_toggled(bool checked)
sendSettings();
}
void LimeSDRInputGUI::on_splitFreq_toggled(bool checked)
{
m_settings.m_splitFreq = checked;
m_settingsKeys.append("splitFreq");
sendSettings();
}
void LimeSDRInputGUI::on_iqImbalance_toggled(bool checked)
{
m_settings.m_iqCorrection = checked;
@ -939,6 +947,7 @@ void LimeSDRInputGUI::makeUIConnections()
QObject::connect(ui->ncoFrequency, &ValueDialZ::changed, this, &LimeSDRInputGUI::on_ncoFrequency_changed);
QObject::connect(ui->ncoEnable, &ButtonSwitch::toggled, this, &LimeSDRInputGUI::on_ncoEnable_toggled);
QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &LimeSDRInputGUI::on_dcOffset_toggled);
QObject::connect(ui->splitFreq, &ButtonSwitch::toggled, this, &LimeSDRInputGUI::on_splitFreq_toggled);
QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &LimeSDRInputGUI::on_iqImbalance_toggled);
QObject::connect(ui->sampleRate, &ValueDial::changed, this, &LimeSDRInputGUI::on_sampleRate_changed);
QObject::connect(ui->hwDecim, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LimeSDRInputGUI::on_hwDecim_currentIndexChanged);

View File

@ -89,6 +89,7 @@ private slots:
void on_ncoFrequency_changed(qint64 value);
void on_ncoEnable_toggled(bool checked);
void on_dcOffset_toggled(bool checked);
void on_splitFreq_toggled(bool checked);
void on_iqImbalance_toggled(bool checked);
void on_sampleRate_changed(quint64 value);
void on_hwDecim_currentIndexChanged(int index);

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>360</width>
<width>386</width>
<height>255</height>
</rect>
</property>
@ -312,6 +312,16 @@
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="splitFreq">
<property name="toolTip">
<string>Disable RX/TX frequency being locked</string>
</property>
<property name="text">
<string>Split</string>
</property>
</widget>
</item>
</layout>
</item>
<item>

View File

@ -36,7 +36,7 @@
const PluginDescriptor LimeSDRInputPlugin::m_pluginDescriptor = {
QStringLiteral("LimeSDR"),
QStringLiteral("LimeSDR Input"),
QStringLiteral("7.22.3"),
QStringLiteral("7.22.7"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -31,6 +31,7 @@ void LimeSDRInputSettings::resetToDefaults()
m_devSampleRate = 5000000;
m_log2HardDecim = 3;
m_dcBlock = false;
m_splitFreq = false;
m_iqCorrection = false;
m_log2SoftDecim = 0;
m_lpfBW = 4.5e6f;
@ -96,6 +97,7 @@ QByteArray LimeSDRInputSettings::serialize() const
s.writeFloat(30, m_replayLength);
s.writeFloat(31, m_replayStep);
s.writeBool(32, m_replayLoop);
s.writeBool(33, m_splitFreq);
return s.final();
}
@ -158,6 +160,7 @@ bool LimeSDRInputSettings::deserialize(const QByteArray& data)
d.readFloat(30, &m_replayLength, 20.0f);
d.readFloat(31, &m_replayStep, 5.0f);
d.readBool(32, &m_replayLoop, false);
d.readBool(33, &m_splitFreq, false);
return true;
}
@ -183,6 +186,9 @@ void LimeSDRInputSettings::applySettings(const QStringList& settingsKeys, const
if (settingsKeys.contains("dcBlock")) {
m_dcBlock = settings.m_dcBlock;
}
if (settingsKeys.contains("splitFreq")) {
m_splitFreq = settings.m_splitFreq;
}
if (settingsKeys.contains("iqCorrection")) {
m_iqCorrection = settings.m_iqCorrection;
}
@ -285,6 +291,9 @@ QString LimeSDRInputSettings::getDebugString(const QStringList& settingsKeys, bo
if (settingsKeys.contains("dcBlock") || force) {
ostr << " m_dcBlock: " << m_dcBlock;
}
if (settingsKeys.contains("splitFreq") || force) {
ostr << " m_splitFreq: " << m_splitFreq;
}
if (settingsKeys.contains("iqCorrection") || force) {
ostr << " m_iqCorrection: " << m_iqCorrection;
}

View File

@ -51,6 +51,7 @@ struct LimeSDRInputSettings
uint32_t m_log2HardDecim;
// channel settings
bool m_dcBlock;
bool m_splitFreq;
bool m_iqCorrection;
uint32_t m_log2SoftDecim;
float m_lpfBW; //!< LMS amalog lowpass filter bandwidth (Hz)

View File

@ -32,6 +32,23 @@ Normal sequence of operations:
- In SDRangel connect the Frequency Tracker plugin by clicking on the grey square at the left of the top bar of the Frequency Tracker GUI. It opens the channel settings dialog. Check the 'Reverse API' box. Next to this box is the address and port at which the channel will be connected. If you use the defaults for `freqtracking.py` you may leave it as it is else you have to adjust it to the address and port of `freqtracking.py` (options `-A` and `-P`).
- In the same manner connect the channel you want to be controlled by `freqtracking.py`. You may connect any number of channels like this. When a channel is removed `freqtracking.py` will automatically remove it from its list at the first attempt to synchronize that will fail.
<h2>plutodvbrpt.py</h2>
Control PlutoDVB2 Tx firmware from SDRangel DATV demod as Rx. This is to effectively implement a DATV repeater based on SDRangel (supposedly sdrangelsrv running on a RPi5 or mini PC) as the receiver and a Pluto equipped with F5OEO PlutoDVB2 firmware as the transmitter. PlutoDVB2 has not such a thing as a "vox" on its UDP TS input so it needs an external command (via MQTT) to switch on/off Tx when the UDP flux starts or stops.
This script polls the DATV Demod channel report every second via the REST API interface and sends appropriate command to the Pluto to switch Tx on or off according to the UDP status. In addition it can clone the DVBS2 essential parameters to the Tx to match exactly the input parameters on the Rx. These are symbol rate, modulation and FEC.
- `-h` or `--help` show help message and exit
- `-a` or `--sdr_address` SDRangel address and port. Default: `127.0.0.1:8091`
- `-d` or `--device` index of device set. Default `0`
- `-c` or `--channel` Index of DATV demod channel. Default `0`
- `-A` or `--pluto_address` Pluto MQTT address. Mandatory
- `-P` or `--pluto_port` Pluto MQTT port. Default `1883`
- `-C` or `--callsign` Amateur Radio callsign. Mandatory
- `-l` or `--clone` Clone symbol rate, constellation and fec to Pluto
The Pluto address and amateur radio callsign have to be specified. The rest have default values as mentioned.
<h2>ptt_feature.py</h2>
Control a PTT feature and optionally a LimeRFE feature in coordination.

304
scriptsapi/plutodvbrpt.py Executable file
View File

@ -0,0 +1,304 @@
#!/usr/bin/env python3
"""
Control PlutoDVB2 enabled Pluto Tx switchover watching UDP status of a DATV demodulator channel
This is a way to implement a DATV repeater system
Uses PlutoDVB2 MQTT "mute" command to switch on/off the Tx
"""
from optparse import OptionParser # pylint: disable=deprecated-module
import json
import os
import socket
import signal
import traceback
import sys
import time
import requests
import paho.mqtt.client as mqttclient
import logging
logger = logging.getLogger(__name__)
mqtt_client = None
pluto_state = {}
FEC_TABLE = {
0: "1/2",
1: "2/3",
2: "4/6",
3: "3/4",
4: "5/6",
5: "7/8",
6: "4/5",
7: "8/9",
8: "9/10",
9: "1/4",
10: "1/3",
11: "2/5",
12: "3/5"
}
CONSTEL_TABLE = {
0: "BPSK",
1: "QPSK",
2: "PSK8",
3: "APSK16",
4: "APSK32",
5: "APSK64E",
6: "QAM16",
7: "QAM64",
8: "QAM256"
}
# ======================================================================
def signal_handler(signum, frame):
""" Signal handler """
logger.info("Signal handler called with signal %d", signum)
# Clean up and exit
# Close MQTT connection
if mqtt_client:
mqtt_client.disconnect()
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
# ======================================================================
def get_input_options():
""" Parse options """
# ----------------------------------------------------------------------
parser = OptionParser(usage="usage: %%prog [-t]\n")
parser.add_option("-a", "--sdr_address", dest="sdr_address", help="SDRangel address and port. Default: 127.0.0.1:8091", metavar="ADDRESS:PORT", type="string")
parser.add_option("-d", "--device", dest="device_index", help="Index of device set. Default 0", metavar="INT", type="int")
parser.add_option("-c", "--channel", dest="channel_index", help="Index of DATV demod channel. Default 0", metavar="INT", type="int")
parser.add_option("-A", "--pluto_address", dest="pluto_address", help="Pluto MQTT address and port. Mandatory", metavar="ADDRESS", type="string")
parser.add_option("-P", "--pluto_port", dest="pluto_port", help="Pluto MQTT port. Default 1883", metavar="INT", type="int")
parser.add_option("-C", "--callsign", dest="callsign", help="Amateur Radio callsign", metavar="CALLSIGN", type="string")
parser.add_option("-l", "--clone", dest="clone", help="Clone symbol rate, constellation and fec to Pluto", metavar="BOOL", action="store_true", default=False)
(options, args) = parser.parse_args()
if options.sdr_address is None:
options.sdr_address = "127.0.0.1:8091"
if options.device_index is None:
options.device_index = 0
if options.channel_index is None:
options.channel_index = 0
if options.pluto_port is None:
options.pluto_port = 1883
if options.pluto_address is None:
raise RuntimeError("Pluto address (-A or --pluto_address) is mandatory")
if options.callsign is None:
raise RuntimeError("Callsign (-C or --callsign) is mandatory")
return options
# ======================================================================
def pluto_state_change(state, value):
""" Change Pluto state """
# ----------------------------------------------------------------------
global pluto_state
if state not in pluto_state:
pluto_state[state] = value
else:
pluto_state[state] = value
logger.debug("Pluto state changed: %s = %s", state, value)
return
# ======================================================================
def connect_mqtt(options):
""" Connect to Pluto MQTT broker """
# ----------------------------------------------------------------------
global mqtt_client
mqtt_client = mqttclient.Client()
mqtt_client.enable_logger(logger)
mqtt_client.on_connect = on_connect
mqtt_client.on_message = on_message
mqtt_client.on_subscribe = on_subscribe
# Connect to the MQTT broker
logger.info("Connecting to Pluto MQTT broker at %s:%d", options.pluto_address, options.pluto_port)
try:
mqtt_client.connect(options.pluto_address, options.pluto_port, 60)
mqtt_client.loop_start()
except Exception as ex:
raise RuntimeError(f"Failed to connect to Pluto MQTT broker: {ex}")
logger.info("Connected to Pluto MQTT broker at %s:%d", options.pluto_address, options.pluto_port)
return mqtt_client
# ======================================================================
def on_connect(client, userdata, flags, rc):
""" Callback for MQTT connection """
# ----------------------------------------------------------------------
logger.info("Connected to MQTT broker with result code %d", rc)
return
# ======================================================================
def on_message(client, userdata, msg):
""" Callback for MQTT message """
# ----------------------------------------------------------------------
logger.debug("Received message on topic %s: %s", msg.topic, msg.payload)
# Parse the message
try:
if msg.topic.endswith("/mute"):
logger.debug("Tx mute message received")
pluto_state_change("muted", msg.payload == b'1')
elif msg.topic.endswith("/sr"):
logger.debug("Tx symbol rate message received: %d", int(msg.payload))
pluto_state_change("symbol_rate", int(msg.payload))
elif msg.topic.endswith("/constel"):
logger.debug("Tx constellation message received: %s", msg.payload.decode('utf-8'))
pluto_state_change("constellation", msg.payload.decode('utf-8'))
elif msg.topic.endswith("/fec"):
logger.debug("Tx fec message received: %s", msg.payload.decode('utf-8'))
pluto_state_change("fec", msg.payload.decode('utf-8'))
else:
message = json.loads(msg.payload)
logger.debug("Message payload is JSON: %s", message)
except json.JSONDecodeError as ex:
logger.error("Failed to decode JSON message: %s", ex)
except Exception as ex:
logger.error("Failed to handle message: %s", ex)
return
# ======================================================================
def on_subscribe(client, userdata, mid, granted_qos):
""" Callback for MQTT subscription """
# ----------------------------------------------------------------------
logger.info("Subscribed to topic with mid %d and granted QoS %s", mid, granted_qos)
return
# ======================================================================
def subscribe_to_pluto(options, mqtt_client):
""" Subscribe to Pluto MQTT broker """
# ----------------------------------------------------------------------
if mqtt_client is None:
raise RuntimeError("MQTT client is not connected")
tx_base_topic = f"dt/pluto/{options.callsign.upper()}/tx"
mute_dt_topic = f"{tx_base_topic}/mute"
logger.info("Subscribing to topic %s", mute_dt_topic)
mqtt_client.subscribe(mute_dt_topic)
logger.info("Subscribed to topic %s", mute_dt_topic)
if options.clone:
# Subscribe to Pluto Tx symbol rate
symbol_rate_topic = f"{tx_base_topic}/dvbs2/sr"
logger.info("Subscribing to topic %s", symbol_rate_topic)
mqtt_client.subscribe(symbol_rate_topic)
# Subscribe to Pluto Tx constellation
constellation_topic = f"{tx_base_topic}/dvbs2/constel"
logger.info("Subscribing to topic %s", constellation_topic)
mqtt_client.subscribe(constellation_topic)
# Subscribe to Pluto Tx fec
fec_topic = f"{tx_base_topic}/dvbs2/fec"
logger.info("Subscribing to topic %s", fec_topic)
mqtt_client.subscribe(fec_topic)
return
# ======================================================================
def mute_pluto_tx(options, mute):
""" Mute or unmute Pluto Tx """
# ----------------------------------------------------------------------
global mqtt_client
if mqtt_client is None:
raise RuntimeError("MQTT client is not connected")
topic = f"cmd/pluto/{options.callsign.upper()}/tx/mute"
message = b'1' if mute else b'0'
logger.info("Publishing message to topic %s: %s", topic, message)
mqtt_client.publish(topic, message)
logger.info("Published message to topic %s", topic)
# Update Pluto state
pluto_state_change("muted", mute)
return
# ======================================================================
def set_pluto_tx_dvbs2(options, symbol_rate, constellation, fec):
""" Set Pluto Tx DVBS2 parameters """
# ----------------------------------------------------------------------
global mqtt_client
if mqtt_client is None:
raise RuntimeError("MQTT client is not connected")
topic_dvbs2 = f"cmd/pluto/{options.callsign.upper()}/tx/dvbs2"
topic_sr = f"{topic_dvbs2}/sr"
topic_constel = f"{topic_dvbs2}/constel"
topic_fec = f"{topic_dvbs2}/fec"
logger.info("Publishing message to topic %s: %d", topic_sr, symbol_rate)
mqtt_client.publish(topic_sr, symbol_rate)
logger.info("Published message to topic %s", topic_sr)
logger.info("Publishing message to topic %s: %s", topic_constel, constellation)
mqtt_client.publish(topic_constel, constellation)
logger.info("Published message to topic %s", topic_constel)
logger.info("Publishing message to topic %s: %s", topic_fec, fec)
mqtt_client.publish(topic_fec, fec)
logger.info("Published message to topic %s", topic_fec)
# Update Pluto state
pluto_state_change("symbol_rate", symbol_rate)
pluto_state_change("constellation", constellation)
pluto_state_change("fec", fec)
return
# ======================================================================
def monitor_datv_demod(options):
""" Monitor DATV demodulator channel and control Pluto Tx """
# ----------------------------------------------------------------------
# Check DATV demodulator channel status
sdrangel_url = f"http://{options.sdr_address}/sdrangel"
report_url = f"{sdrangel_url}/deviceset/{options.device_index}/channel/{options.channel_index}/report"
response = requests.get(report_url)
if response.status_code != 200:
raise RuntimeError(f"Failed to read report at {report_url}")
datv_channel_report = response.json().get("DATVDemodReport", None)
if not datv_channel_report:
raise RuntimeError(f"Failed to read DATV demodulator report at {report_url}")
udp_running = datv_channel_report.get("udpRunning", None)
if udp_running is None:
raise RuntimeError(f"Failed to read udpRunning in {datv_channel_report}")
logger.debug("DATV UDP: %d", udp_running)
if "muted" in pluto_state and pluto_state["muted"] == udp_running or "muted" not in pluto_state:
logger.info("Pluto Tx %s", "muted" if not udp_running else "unmuted")
mute_pluto_tx(options, not udp_running)
logger.info("Pluto state: %s", pluto_state)
if options.clone and datv_channel_report.get("setByModcod", None):
mod = datv_channel_report.get("modcodModulation", -1)
logger.debug("DATV Modulation: %s", CONSTEL_TABLE.get(mod, "Unknown"))
fec = datv_channel_report.get("modcodCodeRate", -1)
logger.debug("DATV FEC: %s", FEC_TABLE.get(fec, "Unknown"))
symbol_rate = datv_channel_report.get("symbolRate", 0)
logger.debug("DATV Symbol Rate: %d", symbol_rate)
if "symbol_rate" in pluto_state and pluto_state["symbol_rate"] == symbol_rate and \
"constellation" in pluto_state and pluto_state["constellation"].upper() == CONSTEL_TABLE.get(mod, "Unknown") and \
"fec" in pluto_state and pluto_state["fec"] == FEC_TABLE.get(fec, "Unknown"):
logger.debug("Pluto Tx parameters unchanged")
else:
logger.info("Pluto Tx parameters changed")
set_pluto_tx_dvbs2(options, symbol_rate, CONSTEL_TABLE.get(mod, "Unknown").lower(), FEC_TABLE.get(fec, "Unknown"))
logger.info("Pluto state: %s", pluto_state)
return
# ======================================================================
def main():
""" Main program """
# ----------------------------------------------------------------------
try:
FORMAT = '%(asctime)s %(levelname)s %(message)s'
logging.basicConfig(format=FORMAT, level=logging.INFO)
options = get_input_options()
connect_mqtt(options)
subscribe_to_pluto(options, mqtt_client)
# Run forever
logger.info("Start monitoring SDRangel channel %d:%d at %s", options.device_index, options.channel_index, options.sdr_address)
while True:
# Monitor DATV demodulator channel
monitor_datv_demod(options)
# Sleep for a while before checking again
time.sleep(1)
except Exception as ex: # pylint: disable=broad-except
tb = traceback.format_exc()
print(f"Exception caught {ex}")
print(tb, file=sys.stderr)
sys.exit(1)
# ======================================================================
if __name__ == "__main__":
main()

View File

@ -1354,6 +1354,63 @@ bool ChannelWebAPIUtils::patchDeviceSetting(unsigned int deviceIndex, const QStr
}
}
bool ChannelWebAPIUtils::patchDeviceSetting(unsigned int deviceIndex, const QString &setting, double value)
{
SWGSDRangel::SWGDeviceSettings deviceSettingsResponse;
QString errorResponse;
int httpRC;
DeviceSet *deviceSet;
if (getDeviceSettings(deviceIndex, deviceSettingsResponse, deviceSet))
{
// Patch setting
QJsonObject *jsonObj = deviceSettingsResponse.asJsonObject();
double oldValue;
if (WebAPIUtils::getSubObjectDouble(*jsonObj, setting, oldValue))
{
WebAPIUtils::setSubObjectDouble(*jsonObj, setting, value);
QStringList deviceSettingsKeys;
deviceSettingsKeys.append(setting);
deviceSettingsResponse.init();
deviceSettingsResponse.fromJsonObject(*jsonObj);
SWGSDRangel::SWGErrorResponse errorResponse2;
delete jsonObj;
if (DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource()) {
httpRC = source->webapiSettingsPutPatch(false, deviceSettingsKeys, deviceSettingsResponse, *errorResponse2.getMessage());
} else if (DeviceSampleSink *sink = deviceSet->m_deviceAPI->getSampleSink()) {
httpRC = sink->webapiSettingsPutPatch(false, deviceSettingsKeys, deviceSettingsResponse, *errorResponse2.getMessage());
} else if (DeviceSampleMIMO *mimo = deviceSet->m_deviceAPI->getSampleMIMO()) {
httpRC = mimo->webapiSettingsPutPatch(false, deviceSettingsKeys, deviceSettingsResponse, *errorResponse2.getMessage());
} else {
httpRC = 404;
}
if (httpRC/100 == 2)
{
qDebug("ChannelWebAPIUtils::patchDeviceSetting: set device setting %s OK", qPrintable(setting));
return true;
}
else
{
qWarning("ChannelWebAPIUtils::patchDeviceSetting: set device setting error %d: %s",
httpRC, qPrintable(*errorResponse2.getMessage()));
return false;
}
}
else
{
delete jsonObj;
qWarning("ChannelWebAPIUtils::patchDeviceSetting: no key %s in device settings", qPrintable(setting));
return false;
}
}
else
{
return false;
}
}
// Set feature setting
bool ChannelWebAPIUtils::patchFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, const QString &value)
{

View File

@ -96,6 +96,7 @@ public:
static bool getDeviceReportList(unsigned int deviceIndex, const QString &key, const QString &subKey, QList<int> &values);
static bool getDevicePosition(unsigned int deviceIndex, float& latitude, float& longitude, float& altitude);
static bool patchDeviceSetting(unsigned int deviceIndex, const QString &setting, int value);
static bool patchDeviceSetting(unsigned int deviceIndex, const QString &setting, double value);
static bool runFeature(unsigned int featureSetIndex, unsigned int featureIndex);
static bool stopFeature(unsigned int featureSetIndex, unsigned int featureIndex);
static bool patchFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, const QString &value);

View File

@ -135,10 +135,12 @@
<file>webapi/doc/swagger/include/VORLocalizer.yaml</file>
<file>webapi/doc/swagger/include/WFMDemod.yaml</file>
<file>webapi/doc/swagger/include/WFMMod.yaml</file>
<file>webapi/doc/swagger/include/WDSPRx.yaml</file>
<file>webapi/doc/swagger/include/Xtrx.yaml</file>
<file>webapi/doc/swagger-ui/favicon-16x16.png</file>
<file>webapi/doc/swagger-ui/favicon-32x32.png</file>
<file>webapi/doc/swagger-ui/index.html</file>
<file>webapi/doc/swagger-ui/index.css</file>
<file>webapi/doc/swagger-ui/oauth2-redirect.html</file>
<file>webapi/doc/swagger-ui/swagger-ui-bundle.js</file>
<file>webapi/doc/swagger-ui/swagger-ui-bundle.js.map</file>
@ -148,6 +150,7 @@
<file>webapi/doc/swagger-ui/swagger-ui-es-bundle.js.map</file>
<file>webapi/doc/swagger-ui/swagger-ui-standalone-preset.js.map</file>
<file>webapi/doc/swagger-ui/swagger-ui-standalone-preset.js</file>
<file>webapi/doc/swagger-ui/swagger-initializer.js</file>
<file>webapi/doc/swagger-ui/swagger-ui.css</file>
<file>webapi/doc/swagger-ui/swagger-ui.css.map</file>
<file>webapi/doc/swagger-ui/swagger-ui.js</file>

View File

@ -4877,6 +4877,10 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "UDP thread (1 running, 0 idle)"
},
"symbolRate" : {
"type" : "integer",
"description" : "Symbol rate in symbols per second - repeated from settings for convenience\n"
},
"modcodModulation" : {
"type" : "integer",
"description" : "Modulation set by DVB-S2 MODCOD\n * -1: Unset\n * 0: BPSK\n * 1: QPSK\n * 2: PSK8\n * 3: APSK16\n * 4: APSK32\n * 5: APSK64E\n * 6: QAM16\n * 7: QAM64\n * 8: QAM256\n"
@ -4930,10 +4934,6 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "(boolean) engage sodt LDPC with LDPC tool sub processes (Linux only)"
},
"softLDPCToolPath" : {
"type" : "string",
"description" : "O/S path to the LDPC tool binary"
},
"softLDPCMaxTrials" : {
"type" : "integer",
"description" : "maximum number of trials in the soft LDPC algorithm (LDPC tool parameter)"
@ -5530,6 +5530,7 @@ margin-bottom: 20px;
"description" : "List of DV serial devices available in the system"
};
defs.DemodAnalyzerActions = {
"required" : [ "channelId", "deviceId" ],
"properties" : {
"deviceId" : {
"type" : "integer",
@ -8962,6 +8963,9 @@ margin-bottom: 20px;
"dcBlock" : {
"type" : "integer"
},
"splitFreq" : {
"type" : "integer"
},
"iqCorrection" : {
"type" : "integer"
},
@ -10716,6 +10720,7 @@ margin-bottom: 20px;
"description" : "MetisMISOSettings"
};
defs.MorseDecoderActions = {
"required" : [ "channelId", "deviceId" ],
"properties" : {
"deviceId" : {
"type" : "integer",
@ -13386,10 +13391,12 @@ margin-bottom: 20px;
"type" : "integer"
},
"deviceIndex" : {
"type" : "integer"
"type" : "integer",
"description" : "remote SDRangel instance deviceset index"
},
"channelIndex" : {
"type" : "integer"
"type" : "integer",
"description" : "remote SDRangel instance channel index"
},
"useReverseAPI" : {
"type" : "integer",
@ -17359,7 +17366,8 @@ margin-bottom: 20px;
},
"nbLeadTime" : {
"type" : "number",
"format" : "float"
"format" : "float",
"description" : "Advance time (s)"
},
"nbLagTime" : {
"type" : "number",
@ -59601,7 +59609,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2025-03-06T14:54:56.926+01:00
Generated 2025-06-02T13:08:26.366+02:00
</div>
</div>
</div>

View File

@ -0,0 +1,16 @@
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}

View File

@ -4,35 +4,14 @@
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="index.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>

View File

@ -4,8 +4,6 @@
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
</body>
</html>
<script>
'use strict';
function run () {
@ -15,31 +13,32 @@
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
qp = window.location.hash.substring(1).replace('?', '&');
} else {
qp = location.search.substring(1);
}
arr = qp.split("&")
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
return key === "" ? value : decodeURIComponent(value);
}
) : {}
) : {};
isValid = qp.state === sentState
isValid = qp.state === sentState;
if ((
oauth2.auth.schema.get("flow") === "accessCode"||
oauth2.auth.schema.get("flow") === "authorizationCode"
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
});
}
@ -48,7 +47,7 @@
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
@ -59,7 +58,7 @@
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
});
}
} else {
@ -68,7 +67,13 @@
window.close();
}
window.addEventListener('DOMContentLoaded', function () {
run();
});
if (document.readyState !== 'loading') {
run();
} else {
document.addEventListener('DOMContentLoaded', function () {
run();
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,20 @@
window.onload = function() {
//<editor-fold desc="Changeable Configuration Block">
// the following lines will be replaced by docker/configurator, when it runs in a docker-container
window.ui = SwaggerUIBundle({
url: "https://petstore.swagger.io/v2/swagger.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});
//</editor-fold>
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -48,9 +48,6 @@ DATVDemodSettings:
softLDPC:
description: (boolean) engage sodt LDPC with LDPC tool sub processes (Linux only)
type: integer
softLDPCToolPath:
description: O/S path to the LDPC tool binary
type: string
softLDPCMaxTrials:
description: maximum number of trials in the soft LDPC algorithm (LDPC tool parameter)
type: integer
@ -148,6 +145,10 @@ DATVDemodReport:
udpRunning:
description: UDP thread (1 running, 0 idle)
type: integer
symbolRate:
type: integer
description: >
Symbol rate in symbols per second - repeated from settings for convenience
modcodModulation:
type: integer
description: >

View File

@ -42,12 +42,13 @@ DemodAnalyzerSettings:
DemodAnalyzerActions:
description: "Demod Analyzer actions"
required:
- deviceId
- channelId
properties:
deviceId:
type: integer
required: true
description: "Device Id/Number that channel belongs to"
channelId:
type: integer
required: true
description: "Channel Id/Number of the channel within the device"

View File

@ -10,6 +10,8 @@ LimeSdrInputSettings:
type: integer
dcBlock:
type: integer
splitFreq:
type: integer
iqCorrection:
type: integer
log2SoftDecim:

View File

@ -59,12 +59,13 @@ MorseDecoderSettings:
MorseDecoderActions:
description: "Morse Decoder actions"
required:
- deviceId
- channelId
properties:
deviceId:
type: integer
required: true
description: "Device Id/Number that channel belongs to"
channelId:
type: integer
required: true
description: "Channel Id/Number of the channel within the device"

View File

@ -19,10 +19,10 @@ RemoteOutputSettings:
dataPort:
type: integer
deviceIndex:
device: remote SDRangel instance deviceset index
description: remote SDRangel instance deviceset index
type: integer
channelIndex:
device: remote SDRangel instance channel index
description: remote SDRangel instance channel index
type: integer
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)

View File

@ -76,7 +76,7 @@ WDSPRxSettings:
nbLeadTime:
type: number
format: float
descriuption: Advance time (s)
description: Advance time (s)
nbLagTime:
type: number
format: float

View File

@ -2973,7 +2973,6 @@ definitions:
FeatureSet:
description: "Grouping of features"
required:
- index
- featurecount
properties:
featurecount:
@ -3018,7 +3017,6 @@ definitions:
required:
- index
- hwType
- streamIndex
- sequence
- serial
- centerFrequency
@ -3422,7 +3420,6 @@ definitions:
description: "Group of configuration"
required:
- groupName
- nbPresets
properties:
groupName:
description: "Name of the configuration group"
@ -3530,4 +3527,3 @@ responses:
description: Function not implemented
schema:
$ref: "#/definitions/ErrorResponse"

View File

@ -44,7 +44,7 @@ void SerialUtil::getComPorts(std::vector<std::string>& comPorts, const std::stri
for (int i = 0; i<255; i++) // checking ports from COM0 to COM255
{
sprintf(portName, "COM%d", i);
snprintf(portName, sizeof(portName), "COM%d", i);
test = QueryDosDeviceA((LPCSTR)portName, (LPSTR)lpTargetPath, 5000);

View File

@ -22,6 +22,18 @@ services:
networks:
default:
ipv4_address: 172.20.0.3
swaggerclient:
image: "jeanberu/swagger-cli"
user: "1000:1000"
entrypoint: "/bin/sh"
container_name: "sdrangel_swaggerclient"
volumes:
- "${SDRANGEL_BASE}:/opt/build/sdrangel:rw"
stdin_open: true
tty: true
networks:
default:
ipv4_address: 172.20.0.4
networks:
default:
driver: bridge

View File

@ -41,8 +41,14 @@ Use `run.sh` to create or delete the Docker compose stack. It takes the followin
- `-b`: SDRangel source code root path (default `/opt/build/sdrangel`)
- `-c`: Compose stack name (default `sdrangelswg`)
The stack is composed of two containers sharing the `172.20.0.0/16` network internally.
The stack is composed of three containers sharing the `172.20.0.0/16` network internally.
- `sdrangel_swgserver`: The http server that listens on port `8081` serving files in `/opt/build/sdrangel/swagger/sdrangel`
- `sdrangel_swgcodegen`: The container with the Swagger code generator. The working directory is `/opt/build/sdrangel/swagger/sdrangel`.
- `sdrangel_swgcodegen`: The container with the Swagger code generator. The working directory is `/opt/build/sdrangel/swagger/sdrangel`
- `sdrangel_swaggerclient`: based on the `jeanberu/swagger-cli` image it can be used to validate the swagger schema (see next).
Use `login.sh` to start a shell in the `sdrangel_swgcodegen` container. At the prompt run `generate.sh` to generate the code from the Swagger definition files.
To validate the swagger schema:
- Enter the `sdrangel_swaggerclient` container with: `docker exec -it sdrangel_swaggerclient /bin/sh`
- Validate the schema with the command: `swagger-cli validate /opt/build/sdrangel/swagger/sdrangel/api/swagger/swagger.yaml`
- Correct errors from the most inner ones (maximum tabs). Top level errors usually result from low level errors and are therefore quite cryptic.

View File

@ -48,9 +48,6 @@ DATVDemodSettings:
softLDPC:
description: (boolean) engage sodt LDPC with LDPC tool sub processes (Linux only)
type: integer
softLDPCToolPath:
description: O/S path to the LDPC tool binary
type: string
softLDPCMaxTrials:
description: maximum number of trials in the soft LDPC algorithm (LDPC tool parameter)
type: integer
@ -148,6 +145,10 @@ DATVDemodReport:
udpRunning:
description: UDP thread (1 running, 0 idle)
type: integer
symbolRate:
type: integer
description: >
Symbol rate in symbols per second - repeated from settings for convenience
modcodModulation:
type: integer
description: >

View File

@ -42,12 +42,13 @@ DemodAnalyzerSettings:
DemodAnalyzerActions:
description: "Demod Analyzer actions"
required:
- deviceId
- channelId
properties:
deviceId:
type: integer
required: true
description: "Device Id/Number that channel belongs to"
channelId:
type: integer
required: true
description: "Channel Id/Number of the channel within the device"

View File

@ -10,6 +10,8 @@ LimeSdrInputSettings:
type: integer
dcBlock:
type: integer
splitFreq:
type: integer
iqCorrection:
type: integer
log2SoftDecim:

View File

@ -59,12 +59,13 @@ MorseDecoderSettings:
MorseDecoderActions:
description: "Morse Decoder actions"
required:
- deviceId
- channelId
properties:
deviceId:
type: integer
required: true
description: "Device Id/Number that channel belongs to"
channelId:
type: integer
required: true
description: "Channel Id/Number of the channel within the device"

View File

@ -19,10 +19,10 @@ RemoteOutputSettings:
dataPort:
type: integer
deviceIndex:
device: remote SDRangel instance deviceset index
description: remote SDRangel instance deviceset index
type: integer
channelIndex:
device: remote SDRangel instance channel index
description: remote SDRangel instance channel index
type: integer
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)

View File

@ -76,7 +76,7 @@ WDSPRxSettings:
nbLeadTime:
type: number
format: float
descriuption: Advance time (s)
description: Advance time (s)
nbLagTime:
type: number
format: float

Some files were not shown because too many files have changed in this diff Show More