aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2023-07-20 18:14:51 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2023-07-20 18:14:51 +0200
commit0887d7e859605fad9617681695e70e3ef738a19c (patch)
tree0ac353c86a5315f2af18dd0d86fde6c51907b5c8
parent595606ca4ed3011af19c6d8a9f95519d84320120 (diff)
downloaddabmod-0887d7e859605fad9617681695e70e3ef738a19c.tar.gz
dabmod-0887d7e859605fad9617681695e70e3ef738a19c.tar.bz2
dabmod-0887d7e859605fad9617681695e70e3ef738a19c.zip
Add main loop RC metrics
-rw-r--r--lib/Socket.cpp2
-rw-r--r--src/DabMod.cpp165
-rw-r--r--src/DabModulator.h2
-rw-r--r--src/EtiReader.cpp2
-rw-r--r--src/GuardIntervalInserter.h2
-rw-r--r--src/InputTcpReader.cpp3
-rw-r--r--src/TII.h1
-rw-r--r--src/TimestampDecoder.h1
-rw-r--r--src/Utils.cpp82
-rw-r--r--src/Utils.h13
10 files changed, 169 insertions, 104 deletions
diff --git a/lib/Socket.cpp b/lib/Socket.cpp
index 10ec1ca..b71c01e 100644
--- a/lib/Socket.cpp
+++ b/lib/Socket.cpp
@@ -893,7 +893,7 @@ ssize_t TCPClient::recv(void *buffer, size_t length, int flags, int timeout_ms)
return 0;
}
- return 0;
+ throw std::logic_error("unreachable");
}
void TCPClient::reconnect()
diff --git a/src/DabMod.cpp b/src/DabMod.cpp
index fdd9e93..7daa72a 100644
--- a/src/DabMod.cpp
+++ b/src/DabMod.cpp
@@ -3,7 +3,7 @@
Her Majesty the Queen in Right of Canada (Communications Research
Center Canada)
- Copyright (C) 2019
+ Copyright (C) 2023
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -96,18 +96,58 @@ void signalHandler(int signalNb)
running = 0;
}
-struct modulator_data
-{
- // For ETI
- std::shared_ptr<InputReader> inputReader;
- std::shared_ptr<EtiReader> etiReader;
+class ModulatorData : public RemoteControllable {
+ public:
+ // For ETI
+ std::shared_ptr<InputReader> inputReader;
+ std::shared_ptr<EtiReader> etiReader;
+
+ // For EDI
+ std::shared_ptr<EdiInput> ediInput;
+
+ // Common to both EDI and EDI
+ uint64_t framecount = 0;
+ Flowgraph *flowgraph = nullptr;
+
+
+ // RC-related
+ ModulatorData() : RemoteControllable("mainloop") {
+ RC_ADD_PARAMETER(num_modulator_restarts, "(Read-only) Number of mod restarts");
+ RC_ADD_PARAMETER(most_recent_edi_decoded, "(Read-only) UNIX Timestamp of most recently decoded EDI frame");
+ }
+
+ virtual ~ModulatorData() {}
+
+ virtual void set_parameter(const std::string& parameter, const std::string& value) {
+ throw ParameterError("Parameter " + parameter + " is read-only");
+ }
+
+ virtual const std::string get_parameter(const std::string& parameter) const {
+ stringstream ss;
+ if (parameter == "num_modulator_restarts") {
+ ss << num_modulator_restarts;
+ }
+ else if (parameter == "most_recent_edi_decoded") {
+ ss << most_recent_edi_decoded;
+ }
+ else {
+ ss << "Parameter '" << parameter <<
+ "' is not exported by controllable " << get_rc_name();
+ throw ParameterError(ss.str());
+ }
+ return ss.str();
+ }
- // For EDI
- std::shared_ptr<EdiInput> ediInput;
+ virtual const json::map_t get_all_values() const
+ {
+ json::map_t map;
+ map["num_modulator_restarts"].v = num_modulator_restarts;
+ map["most_recent_edi_decoded"].v = most_recent_edi_decoded;
+ return map;
+ }
- // Common to both EDI and EDI
- uint64_t framecount = 0;
- Flowgraph *flowgraph = nullptr;
+ size_t num_modulator_restarts = 0;
+ time_t most_recent_edi_decoded = 0;
};
enum class run_modulator_state_t {
@@ -117,88 +157,8 @@ enum class run_modulator_state_t {
reconfigure // Some sort of change of configuration we cannot handle happened
};
-static run_modulator_state_t run_modulator(const mod_settings_t& mod_settings, modulator_data& m);
-
-static void printModSettings(const mod_settings_t& mod_settings)
-{
- stringstream ss;
- // Print settings
- ss << "Input\n";
- ss << " Type: " << mod_settings.inputTransport << "\n";
- ss << " Source: " << mod_settings.inputName << "\n";
-
- ss << "Output\n";
-
- if (mod_settings.useFileOutput) {
- ss << " Name: " << mod_settings.outputName << "\n";
- }
-#if defined(HAVE_OUTPUT_UHD)
- else if (mod_settings.useUHDOutput) {
- ss << " UHD\n" <<
- " Device: " << mod_settings.sdr_device_config.device << "\n" <<
- " Subdevice: " <<
- mod_settings.sdr_device_config.subDevice << "\n" <<
- " master_clock_rate: " <<
- mod_settings.sdr_device_config.masterClockRate << "\n" <<
- " refclk: " <<
- mod_settings.sdr_device_config.refclk_src << "\n" <<
- " pps source: " <<
- mod_settings.sdr_device_config.pps_src << "\n";
- }
-#endif
-#if defined(HAVE_SOAPYSDR)
- else if (mod_settings.useSoapyOutput) {
- ss << " SoapySDR\n"
- " Device: " << mod_settings.sdr_device_config.device << "\n" <<
- " master_clock_rate: " <<
- mod_settings.sdr_device_config.masterClockRate << "\n";
- }
-#endif
-#if defined(HAVE_DEXTER)
- else if (mod_settings.useDexterOutput) {
- ss << " PrecisionWave DEXTER\n";
- }
-#endif
-#if defined(HAVE_LIMESDR)
- else if (mod_settings.useLimeOutput) {
- ss << " LimeSDR\n"
- " Device: " << mod_settings.sdr_device_config.device << "\n" <<
- " master_clock_rate: " <<
- mod_settings.sdr_device_config.masterClockRate << "\n";
- }
-#endif
-#if defined(HAVE_BLADERF)
- else if (mod_settings.useBladeRFOutput) {
- ss << " BladeRF\n"
- " Device: " << mod_settings.sdr_device_config.device << "\n" <<
- " refclk: " << mod_settings.sdr_device_config.refclk_src << "\n";
- }
-#endif
- else if (mod_settings.useZeroMQOutput) {
- ss << " ZeroMQ\n" <<
- " Listening on: " << mod_settings.outputName << "\n" <<
- " Socket type : " << mod_settings.zmqOutputSocketType << "\n";
- }
+static run_modulator_state_t run_modulator(const mod_settings_t& mod_settings, ModulatorData& m);
- ss << " Sampling rate: ";
- if (mod_settings.outputRate > 1000) {
- if (mod_settings.outputRate > 1000000) {
- ss << std::fixed << std::setprecision(4) <<
- mod_settings.outputRate / 1000000.0 <<
- " MHz\n";
- }
- else {
- ss << std::fixed << std::setprecision(4) <<
- mod_settings.outputRate / 1000.0 <<
- " kHz\n";
- }
- }
- else {
- ss << std::fixed << std::setprecision(4) <<
- mod_settings.outputRate << " Hz\n";
- }
- fprintf(stderr, "%s", ss.str().c_str());
-}
static shared_ptr<ModOutput> prepare_output(mod_settings_t& s)
{
@@ -346,6 +306,9 @@ int launch_modulator(int argc, char* argv[])
printModSettings(mod_settings);
+ ModulatorData m;
+ rcs.enrol(&m);
+
{
// This is mostly useful on ARM systems where FFTW planning takes some time. If we do it here
// it will be done before the modulator starts up
@@ -422,14 +385,15 @@ int launch_modulator(int argc, char* argv[])
"invalid input transport " + mod_settings.inputTransport + " selected!");
}
+ m.ediInput = ediInput;
+ m.inputReader = inputReader;
+
bool run_again = true;
while (run_again) {
Flowgraph flowgraph(mod_settings.showProcessTime);
- modulator_data m;
- m.ediInput = ediInput;
- m.inputReader = inputReader;
+ m.framecount = 0;
m.flowgraph = &flowgraph;
shared_ptr<DabModulator> modulator;
@@ -493,13 +457,14 @@ int launch_modulator(int argc, char* argv[])
}
etiLog.level(info) << m.framecount << " DAB frames, " << ((float)m.framecount * 0.024f) << " seconds encoded";
+ m.num_modulator_restarts++;
}
etiLog.level(info) << "Terminating";
return ret;
}
-static run_modulator_state_t run_modulator(const mod_settings_t& mod_settings, modulator_data& m)
+static run_modulator_state_t run_modulator(const mod_settings_t& mod_settings, ModulatorData& m)
{
auto ret = run_modulator_state_t::failure;
try {
@@ -579,6 +544,12 @@ static run_modulator_state_t run_modulator(const mod_settings_t& mod_settings, m
break;
}
+ struct timespec t;
+ if (clock_gettime(CLOCK_REALTIME, &t) != 0) {
+ throw std::runtime_error(std::string("Failed to retrieve CLOCK_REALTIME") + strerror(errno));
+ }
+
+ m.most_recent_edi_decoded = t.tv_sec;
fct = m.ediInput->ediReader.getFct();
fp = m.ediInput->ediReader.getFp();
ts = m.ediInput->ediReader.getTimestamp();
@@ -611,7 +582,7 @@ static run_modulator_state_t run_modulator(const mod_settings_t& mod_settings, m
last_eti_fct = fct;
}
else {
- etiLog.level(info) << "ETI FCT discontinuity, expected " <<
+ etiLog.level(warn) << "ETI FCT discontinuity, expected " <<
expected_fct << " received " << fct;
if (m.ediInput) {
m.ediInput->ediReader.clearFrame();
diff --git a/src/DabModulator.h b/src/DabModulator.h
index 140f313..093a782 100644
--- a/src/DabModulator.h
+++ b/src/DabModulator.h
@@ -53,6 +53,8 @@ public:
DabModulator(EtiSource& etiSource, mod_settings_t& settings, const std::string& format);
// Allowed formats: s8, u8 and s16. Empty string means no conversion
+ virtual ~DabModulator() {}
+
int process(Buffer* dataOut) override;
const char* name() override { return "DabModulator"; }
diff --git a/src/EtiReader.cpp b/src/EtiReader.cpp
index e992e62..580088b 100644
--- a/src/EtiReader.cpp
+++ b/src/EtiReader.cpp
@@ -646,7 +646,7 @@ bool EdiTransport::rxPacket()
const int timeout_ms = 1000;
try {
ssize_t ret = m_tcpclient.recv(m_tcpbuffer.data(), m_tcpbuffer.size(), 0, timeout_ms);
- if (ret == 0 or ret == -1) {
+ if (ret <= 0) {
return false;
}
else if (ret > (ssize_t)m_tcpbuffer.size()) {
diff --git a/src/GuardIntervalInserter.h b/src/GuardIntervalInserter.h
index 5aaad2b..f78ac91 100644
--- a/src/GuardIntervalInserter.h
+++ b/src/GuardIntervalInserter.h
@@ -52,6 +52,8 @@ class GuardIntervalInserter : public ModCodec, public RemoteControllable
size_t symSize,
size_t& windowOverlap);
+ virtual ~GuardIntervalInserter() {}
+
int process(Buffer* const dataIn, Buffer* dataOut) override;
const char* name() override { return "GuardIntervalInserter"; }
diff --git a/src/InputTcpReader.cpp b/src/InputTcpReader.cpp
index 21f8496..8ba4d74 100644
--- a/src/InputTcpReader.cpp
+++ b/src/InputTcpReader.cpp
@@ -79,6 +79,9 @@ int InputTcpReader::GetNextFrame(void* buffer)
etiLog.level(debug) << "TCP input auto reconnect";
std::this_thread::sleep_for(std::chrono::seconds(1));
}
+ else if (ret == -2) {
+ etiLog.level(debug) << "TCP input timeout";
+ }
return ret;
}
diff --git a/src/TII.h b/src/TII.h
index a8d0ca9..f6de70b 100644
--- a/src/TII.h
+++ b/src/TII.h
@@ -82,6 +82,7 @@ class TII : public ModCodec, public RemoteControllable
{
public:
TII(unsigned int dabmode, tii_config_t& tii_config);
+ virtual ~TII() {}
int process(Buffer* dataIn, Buffer* dataOut) override;
const char* name() override;
diff --git a/src/TimestampDecoder.h b/src/TimestampDecoder.h
index b90c328..25796ca 100644
--- a/src/TimestampDecoder.h
+++ b/src/TimestampDecoder.h
@@ -98,6 +98,7 @@ class TimestampDecoder : public RemoteControllable
* frame transmission
*/
TimestampDecoder(double& offset_s);
+ virtual ~TimestampDecoder() {}
frame_timestamp getTimestamp(void);
diff --git a/src/Utils.cpp b/src/Utils.cpp
index 3f378a7..94f198c 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -25,6 +25,7 @@
along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "sstream"
#include "Utils.h"
#include "GainControl.h"
#if defined(HAVE_PRCTL)
@@ -144,6 +145,87 @@ void printStartupInfo()
printHeader();
}
+void printModSettings(const mod_settings_t& mod_settings)
+{
+ std::stringstream ss;
+ // Print settings
+ ss << "Input\n";
+ ss << " Type: " << mod_settings.inputTransport << "\n";
+ ss << " Source: " << mod_settings.inputName << "\n";
+
+ ss << "Output\n";
+
+ if (mod_settings.useFileOutput) {
+ ss << " Name: " << mod_settings.outputName << "\n";
+ }
+#if defined(HAVE_OUTPUT_UHD)
+ else if (mod_settings.useUHDOutput) {
+ ss << " UHD\n" <<
+ " Device: " << mod_settings.sdr_device_config.device << "\n" <<
+ " Subdevice: " <<
+ mod_settings.sdr_device_config.subDevice << "\n" <<
+ " master_clock_rate: " <<
+ mod_settings.sdr_device_config.masterClockRate << "\n" <<
+ " refclk: " <<
+ mod_settings.sdr_device_config.refclk_src << "\n" <<
+ " pps source: " <<
+ mod_settings.sdr_device_config.pps_src << "\n";
+ }
+#endif
+#if defined(HAVE_SOAPYSDR)
+ else if (mod_settings.useSoapyOutput) {
+ ss << " SoapySDR\n"
+ " Device: " << mod_settings.sdr_device_config.device << "\n" <<
+ " master_clock_rate: " <<
+ mod_settings.sdr_device_config.masterClockRate << "\n";
+ }
+#endif
+#if defined(HAVE_DEXTER)
+ else if (mod_settings.useDexterOutput) {
+ ss << " PrecisionWave DEXTER\n";
+ }
+#endif
+#if defined(HAVE_LIMESDR)
+ else if (mod_settings.useLimeOutput) {
+ ss << " LimeSDR\n"
+ " Device: " << mod_settings.sdr_device_config.device << "\n" <<
+ " master_clock_rate: " <<
+ mod_settings.sdr_device_config.masterClockRate << "\n";
+ }
+#endif
+#if defined(HAVE_BLADERF)
+ else if (mod_settings.useBladeRFOutput) {
+ ss << " BladeRF\n"
+ " Device: " << mod_settings.sdr_device_config.device << "\n" <<
+ " refclk: " << mod_settings.sdr_device_config.refclk_src << "\n";
+ }
+#endif
+ else if (mod_settings.useZeroMQOutput) {
+ ss << " ZeroMQ\n" <<
+ " Listening on: " << mod_settings.outputName << "\n" <<
+ " Socket type : " << mod_settings.zmqOutputSocketType << "\n";
+ }
+
+ ss << " Sampling rate: ";
+ if (mod_settings.outputRate > 1000) {
+ if (mod_settings.outputRate > 1000000) {
+ ss << std::fixed << std::setprecision(4) <<
+ mod_settings.outputRate / 1000000.0 <<
+ " MHz\n";
+ }
+ else {
+ ss << std::fixed << std::setprecision(4) <<
+ mod_settings.outputRate / 1000.0 <<
+ " kHz\n";
+ }
+ }
+ else {
+ ss << std::fixed << std::setprecision(4) <<
+ mod_settings.outputRate << " Hz\n";
+ }
+ fprintf(stderr, "%s", ss.str().c_str());
+}
+
int set_realtime_prio(int prio)
{
// Set thread priority to realtime
diff --git a/src/Utils.h b/src/Utils.h
index 9e88488..82728e9 100644
--- a/src/Utils.h
+++ b/src/Utils.h
@@ -3,7 +3,7 @@
Her Majesty the Queen in Right of Canada (Communications Research
Center Canada)
- Copyright (C) 2018
+ Copyright (C) 2023
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -31,12 +31,13 @@
# include "config.h"
#endif
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <time.h>
#include <string>
#include <chrono>
+#include <cstdio>
+#include <ctime>
+#include <cstdlib>
+#include <unistd.h>
+#include "ConfigParser.h"
void printUsage(const char* progName);
@@ -44,6 +45,8 @@ void printVersion(void);
void printStartupInfo(void);
+void printModSettings(const mod_settings_t& mod_settings);
+
// Set SCHED_RR with priority prio (0=lowest)
int set_realtime_prio(int prio);