aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--configure.ac4
-rw-r--r--lib/Json.cpp4
-rw-r--r--lib/Json.h4
-rw-r--r--lib/Socket.cpp22
-rw-r--r--lib/Socket.h10
-rw-r--r--lib/ThreadsafeQueue.h38
-rw-r--r--lib/fec/decode_rs.h12
-rw-r--r--src/Buffer.h3
-rw-r--r--src/GainControl.cpp24
-rw-r--r--src/Utils.cpp4
11 files changed, 88 insertions, 42 deletions
diff --git a/ChangeLog b/ChangeLog
index e49c9c0..6266e8c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,8 @@
This file contains information about the changes done to
ODR-DabMod in this repository
-2023-11-21: Matthias P. Braendli <matthias@mpb.li>
- (upcoming release):
+2025-02-26: Matthias P. Braendli <matthias@mpb.li>
+ (v3.0.0):
Add support for the PrecisionWave DEXTER Modulator.
Improve timestamp decoding and handling.
Fix TII carrier levels.
@@ -11,6 +11,7 @@ ODR-DabMod in this repository
Remove EasyDABv3 support.
Remove ZeroMQ input.
Require C++17.
+ v2.7.0 retracted.
2022-04-20: Matthias P. Braendli <matthias@mpb.li>
(v2.6.0):
diff --git a/configure.ac b/configure.ac
index 5c3de90..46bbaf1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Her Majesty the
# Queen in Right of Canada (Communications Research Center Canada)
-# Copyright (C) 2023 Matthias P. Braendli, http://opendigitalradio.org
+# Copyright (C) 2025 Matthias P. Braendli, http://opendigitalradio.org
# This file is part of ODR-DabMod.
#
@@ -19,7 +19,7 @@
# along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>.
AC_PREREQ([2.69])
-AC_INIT([ODR-DabMod],[2.6.0],[matthias.braendli@mpb.li])
+AC_INIT([ODR-DabMod],[3.0.0],[matthias.braendli@mpb.li])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_TARGET
diff --git a/lib/Json.cpp b/lib/Json.cpp
index 361a149..ee33671 100644
--- a/lib/Json.cpp
+++ b/lib/Json.cpp
@@ -3,7 +3,7 @@
Her Majesty the Queen in Right of Canada (Communications Research
Center Canada)
- Copyright (C) 2023
+ Copyright (C) 2025
Matthias P. Braendli, matthias.braendli@mpb.li
http://www.opendigitalradio.org
@@ -27,7 +27,7 @@
#include <sstream>
#include <iomanip>
#include <string>
-#include <algorithm>
+#include <stdexcept>
#include "Json.h"
diff --git a/lib/Json.h b/lib/Json.h
index b082f92..0168583 100644
--- a/lib/Json.h
+++ b/lib/Json.h
@@ -3,7 +3,7 @@
Her Majesty the Queen in Right of Canada (Communications Research
Center Canada)
- Copyright (C) 2023
+ Copyright (C) 2025
Matthias P. Braendli, matthias.braendli@mpb.li
http://www.opendigitalradio.org
@@ -34,10 +34,10 @@
#include <vector>
#include <memory>
#include <optional>
-#include <stdexcept>
#include <string>
#include <unordered_map>
#include <variant>
+#include <cstdint>
namespace json {
diff --git a/lib/Socket.cpp b/lib/Socket.cpp
index 938b573..5c920d7 100644
--- a/lib/Socket.cpp
+++ b/lib/Socket.cpp
@@ -24,6 +24,7 @@
#include "Socket.h"
+#include <numeric>
#include <stdexcept>
#include <cstdio>
#include <cstring>
@@ -1063,6 +1064,17 @@ void TCPConnection::process()
#endif
}
+TCPConnection::stats_t TCPConnection::get_stats() const
+{
+ TCPConnection::stats_t s;
+ const vector<size_t> buffer_sizes = queue.map<size_t>(
+ [](const vector<uint8_t>& vec) { return vec.size(); }
+ );
+
+ s.buffer_fullness = std::accumulate(buffer_sizes.cbegin(), buffer_sizes.cend(), 0);
+ s.remote_address = m_sock.get_remote_address();
+ return s;
+}
TCPDataDispatcher::TCPDataDispatcher(size_t max_queue_size, size_t buffers_to_preroll) :
m_max_queue_size(max_queue_size),
@@ -1136,6 +1148,16 @@ void TCPDataDispatcher::process()
}
}
+
+std::vector<TCPConnection::stats_t> TCPDataDispatcher::get_stats() const
+{
+ std::vector<TCPConnection::stats_t> s;
+ for (const auto& conn : m_connections) {
+ s.push_back(conn.get_stats());
+ }
+ return s;
+}
+
TCPReceiveServer::TCPReceiveServer(size_t blocksize) :
m_blocksize(blocksize)
{
diff --git a/lib/Socket.h b/lib/Socket.h
index 7709145..29b618a 100644
--- a/lib/Socket.h
+++ b/lib/Socket.h
@@ -213,6 +213,8 @@ class TCPSocket {
SOCKET get_sockfd() const { return m_sock; }
+ InetAddress get_remote_address() const { return m_remote_address; }
+
private:
explicit TCPSocket(int sockfd);
explicit TCPSocket(int sockfd, InetAddress remote_address);
@@ -254,6 +256,12 @@ class TCPConnection
ThreadsafeQueue<std::vector<uint8_t> > queue;
+ struct stats_t {
+ size_t buffer_fullness = 0;
+ InetAddress remote_address;
+ };
+ stats_t get_stats() const;
+
private:
std::atomic<bool> m_running;
std::thread m_sender_thread;
@@ -276,6 +284,8 @@ class TCPDataDispatcher
void start(int port, const std::string& address);
void write(const std::vector<uint8_t>& data);
+ std::vector<TCPConnection::stats_t> get_stats() const;
+
private:
void process();
diff --git a/lib/ThreadsafeQueue.h b/lib/ThreadsafeQueue.h
index 8b385d6..13bc19e 100644
--- a/lib/ThreadsafeQueue.h
+++ b/lib/ThreadsafeQueue.h
@@ -2,7 +2,7 @@
Copyright (C) 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in
Right of Canada (Communications Research Center Canada)
- Copyright (C) 2023
+ Copyright (C) 2025
Matthias P. Braendli, matthias.braendli@mpb.li
An implementation for a threadsafe queue, depends on C++11
@@ -28,6 +28,7 @@
#pragma once
+#include <functional>
#include <mutex>
#include <condition_variable>
#include <queue>
@@ -63,10 +64,10 @@ public:
std::unique_lock<std::mutex> lock(the_mutex);
size_t queue_size_before = the_queue.size();
if (max_size == 0) {
- the_queue.push(val);
+ the_queue.push_back(val);
}
else if (queue_size_before < max_size) {
- the_queue.push(val);
+ the_queue.push_back(val);
}
size_t queue_size = the_queue.size();
lock.unlock();
@@ -80,10 +81,10 @@ public:
std::unique_lock<std::mutex> lock(the_mutex);
size_t queue_size_before = the_queue.size();
if (max_size == 0) {
- the_queue.emplace(std::move(val));
+ the_queue.emplace_back(std::move(val));
}
else if (queue_size_before < max_size) {
- the_queue.emplace(std::move(val));
+ the_queue.emplace_back(std::move(val));
}
size_t queue_size = the_queue.size();
lock.unlock();
@@ -110,9 +111,9 @@ public:
bool overflow = false;
while (the_queue.size() >= max_size) {
overflow = true;
- the_queue.pop();
+ the_queue.pop_front();
}
- the_queue.push(val);
+ the_queue.push_back(val);
const size_t queue_size = the_queue.size();
lock.unlock();
@@ -129,9 +130,9 @@ public:
bool overflow = false;
while (the_queue.size() >= max_size) {
overflow = true;
- the_queue.pop();
+ the_queue.pop_front();
}
- the_queue.emplace(std::move(val));
+ the_queue.emplace_back(std::move(val));
const size_t queue_size = the_queue.size();
lock.unlock();
@@ -152,7 +153,7 @@ public:
while (the_queue.size() >= threshold) {
the_tx_notification.wait(lock);
}
- the_queue.push(val);
+ the_queue.push_back(val);
size_t queue_size = the_queue.size();
lock.unlock();
@@ -198,7 +199,7 @@ public:
}
popped_value = the_queue.front();
- the_queue.pop();
+ the_queue.pop_front();
lock.unlock();
the_tx_notification.notify_one();
@@ -220,15 +221,26 @@ public:
}
else {
std::swap(popped_value, the_queue.front());
- the_queue.pop();
+ the_queue.pop_front();
lock.unlock();
the_tx_notification.notify_one();
}
}
+ template<typename R>
+ std::vector<R> map(std::function<R(const T&)> func) const
+ {
+ std::vector<R> result;
+ std::unique_lock<std::mutex> lock(the_mutex);
+ for (const T& elem : the_queue) {
+ result.push_back(func(elem));
+ }
+ return result;
+ }
+
private:
- std::queue<T> the_queue;
+ std::deque<T> the_queue;
mutable std::mutex the_mutex;
std::condition_variable the_rx_notification;
std::condition_variable the_tx_notification;
diff --git a/lib/fec/decode_rs.h b/lib/fec/decode_rs.h
index c165cf3..647b885 100644
--- a/lib/fec/decode_rs.h
+++ b/lib/fec/decode_rs.h
@@ -145,15 +145,15 @@
count++;
}
if (count != no_eras) {
- printf("count = %d no_eras = %d\n lambda(x) is WRONG\n",count,no_eras);
+ fprintf(stderr, "count = %d no_eras = %d\n lambda(x) is WRONG\n",count,no_eras);
count = -1;
goto finish;
}
#if DEBUG >= 2
- printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
+ fprintf(stderr, "\n Erasure positions as determined by roots of Eras Loc Poly:\n");
for (i = 0; i < count; i++)
- printf("%d ", loc[i]);
- printf("\n");
+ fprintf(stderr, "%d ", loc[i]);
+ fprintf(stderr, "\n");
#endif
#endif
}
@@ -227,7 +227,7 @@
continue; /* Not a root */
/* store root (index-form) and error location number */
#if DEBUG>=2
- printf("count %d root %d loc %d\n",count,i,k);
+ fprintf(stderr, "count %d root %d loc %d\n",count,i,k);
#endif
root[count] = i;
loc[count] = k;
@@ -279,7 +279,7 @@
}
#if DEBUG >= 1
if (den == 0) {
- printf("\n ERROR: denominator = 0\n");
+ fprintf(stderr, "\n ERROR: denominator = 0\n");
count = -1;
goto finish;
}
diff --git a/src/Buffer.h b/src/Buffer.h
index 2c2a65e..a8130ed 100644
--- a/src/Buffer.h
+++ b/src/Buffer.h
@@ -34,11 +34,12 @@
#include <vector>
#include <memory>
#include <complex>
+#include <cstdint>
#include "fpm/fixed.hpp"
typedef std::complex<float> complexf;
-using fixed_16 = fpm::fixed<std::int16_t, std::int32_t, 14>;
+using fixed_16 = fpm::fixed<int16_t, int32_t, 14>;
typedef std::complex<fixed_16> complexfix;
typedef std::complex<fpm::fixed_16_16> complexfix_wide;
diff --git a/src/GainControl.cpp b/src/GainControl.cpp
index 84cf065..e3e280f 100644
--- a/src/GainControl.cpp
+++ b/src/GainControl.cpp
@@ -35,7 +35,7 @@
#ifdef __SSE__
# include <xmmintrin.h>
-union __u128 {
+union u128_union_t {
__m128 m;
float f[4];
};
@@ -122,7 +122,7 @@ int GainControl::internal_process(Buffer* const dataIn, Buffer* dataOut)
__m128* out = reinterpret_cast<__m128*>(dataOut->getData());
size_t sizeIn = dataIn->getLength() / sizeof(__m128);
size_t sizeOut = dataOut->getLength() / sizeof(__m128);
- __u128 gain128;
+ u128_union_t gain128;
if ((sizeIn % m_frameSize) != 0) {
@@ -200,10 +200,10 @@ __m128 GainControl::computeGainFix(const __m128* in, size_t sizeIn)
__m128 GainControl::computeGainMax(const __m128* in, size_t sizeIn)
{
- __u128 gain128;
- __u128 min128;
- __u128 max128;
- __u128 tmp128;
+ u128_union_t gain128;
+ u128_union_t min128;
+ u128_union_t max128;
+ u128_union_t tmp128;
static const __m128 factor128 = _mm_set1_ps(0x7fff);
////////////////////////////////////////////////////////////////////////
@@ -250,10 +250,10 @@ __m128 GainControl::computeGainMax(const __m128* in, size_t sizeIn)
__m128 GainControl::computeGainVar(const __m128* in, size_t sizeIn)
{
- __u128 gain128;
- __u128 mean128;
- __u128 var128;
- __u128 tmp128;
+ u128_union_t gain128;
+ u128_union_t mean128;
+ u128_union_t var128;
+ u128_union_t tmp128;
static const __m128 factor128 = _mm_set1_ps(0x7fff);
mean128.m = _mm_setzero_ps();
@@ -297,8 +297,8 @@ __m128 GainControl::computeGainVar(const __m128* in, size_t sizeIn)
var128.m = _mm_add_ps(var128.m, q128);
/*
- __u128 udiff128; udiff128.m = diff128;
- __u128 udelta128; udelta128.m = delta128;
+ u128_union_t udiff128; udiff128.m = diff128;
+ u128_union_t udelta128; udelta128.m = delta128;
for (int off=0; off<4; off+=2) {
printf("S %zu, %.2f+%.2fj\t",
sample,
diff --git a/src/Utils.cpp b/src/Utils.cpp
index 78f36f0..23e0aa5 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -89,8 +89,8 @@ void printUsage(const char* progName)
"\n\t"
#if defined(HAVE_OUTPUT_UHD)
" [-G txgain]"
- " [-T filter_taps_file]"
#endif // defined(HAVE_OUTPUT_UHD)
+ " [-T filter_taps_file]"
" [-a gain]"
" [-c clockrate]"
"\n\t"
@@ -114,9 +114,9 @@ void printUsage(const char* progName)
fprintf(out, "-u device: Use UHD output with given device string. (use "" for default device)\n");
fprintf(out, "-F frequency: Set the transmit frequency when using UHD output. (mandatory option when using UHD)\n");
fprintf(out, "-G txgain: Set the transmit gain for the UHD driver (default: 0)\n");
+#endif // defined(HAVE_OUTPUT_UHD)
fprintf(out, "-T taps_file: Enable filtering before the output, using the specified file containing the filter taps.\n");
fprintf(out, " Use 'default' as taps_file to use the internal taps.\n");
-#endif // defined(HAVE_OUTPUT_UHD)
fprintf(out, "-a gain: Apply digital amplitude gain.\n");
fprintf(out, "-c rate: Set the DAC clock rate and enable Cic Equalisation.\n");
fprintf(out, "-g gainmode: Set computation gain mode: fix, max or var\n");