aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/example.ini6
-rw-r--r--src/MemlessPoly.cpp4
-rw-r--r--src/output/Dexter.cpp71
-rw-r--r--src/output/Dexter.h14
-rw-r--r--src/output/SDRDevice.h4
5 files changed, 95 insertions, 4 deletions
diff --git a/doc/example.ini b/doc/example.ini
index cd48ef4..4cc6d26 100644
--- a/doc/example.ini
+++ b/doc/example.ini
@@ -320,6 +320,12 @@ txgain=32768
;frequency=234208000
channel=13C
+pacontrol_config_endpoint=tcp://localhost:5558
+
+; TargetPower in dBm
+; Runtime-changes to this setting are directly sent to pacontrol
+pacontrol_targetpower=33
+
[limeoutput]
; Lime output directly runs against the LMS device driver. It does not support SFN nor predistortion.
device=
diff --git a/src/MemlessPoly.cpp b/src/MemlessPoly.cpp
index 4801ba0..a2b0082 100644
--- a/src/MemlessPoly.cpp
+++ b/src/MemlessPoly.cpp
@@ -314,7 +314,7 @@ void MemlessPoly::worker_thread(MemlessPoly::worker_t *workerdata)
set_thread_name("MemlessPoly");
while (true) {
- worker_t::input_data_t in_data;
+ worker_t::input_data_t in_data = {};
try {
workerdata->in_queue.wait_and_pop(in_data);
}
@@ -386,7 +386,7 @@ int MemlessPoly::internal_process(Buffer* const dataIn, Buffer* dataOut)
// Wait for completion of the tasks
for (auto& worker : m_workers) {
- int ret;
+ int ret = 0;
worker.out_queue.wait_and_pop(ret);
}
}
diff --git a/src/output/Dexter.cpp b/src/output/Dexter.cpp
index c1d8d2f..dd51517 100644
--- a/src/output/Dexter.cpp
+++ b/src/output/Dexter.cpp
@@ -66,9 +66,35 @@ static void fill_time(struct timespec *t)
}
}
+static void pacontrol_set_targetpower(zmq::socket_t& sock, int targetpower_dBm)
+{
+ stringstream message_builder;
+ message_builder << "{'PA0' : {'TargetPower': ";
+ message_builder << targetpower_dBm;
+ message_builder << "}}";
+ const auto message = message_builder.str();
+
+ try {
+ const auto r = sock.send(zmq::const_buffer{message.data(), message.size()});
+ if (r.has_value()) {
+ etiLog.level(debug) << "Sent TargetPower=" << targetpower_dBm << " to pacontrol";
+ }
+ else {
+ // zmq_send returned EAGAIN
+ etiLog.level(info) << "Send TargetPower=" << targetpower_dBm << " failed";
+ }
+ }
+ catch (const zmq::error_t& err) {
+ etiLog.level(warn) << "Failed to send TargetPower=" << targetpower_dBm << ": " << err.what();
+ }
+}
+
+
Dexter::Dexter(SDRDeviceConfig& config) :
SDRDevice(),
- m_conf(config)
+ m_conf(config),
+ m_zmq_context(1),
+ m_zmq_sock(m_zmq_context, ZMQ_PUSH)
{
etiLog.level(info) << "Dexter:Creating the device";
@@ -166,6 +192,41 @@ Dexter::Dexter(SDRDeviceConfig& config) :
m_running = true;
m_underflow_read_thread = std::thread(&Dexter::underflow_read_process, this);
+
+ m_zmq_sock.setsockopt(ZMQ_SNDTIMEO, 0);
+ if (not m_conf.pacontrol_config_endpoint.empty()) {
+ etiLog.level(debug) << "Creating pacontrol connection to " <<
+ m_conf.pacontrol_config_endpoint;
+ m_zmq_sock.connect(m_conf.pacontrol_config_endpoint.c_str());
+ }
+
+ if (m_conf.pacontrol_targetpower.has_value()) {
+ pacontrol_set_targetpower(m_zmq_sock, *m_conf.pacontrol_targetpower);
+ }
+ else {
+ etiLog.level(warn) << "Config does not defined PA target power";
+ }
+}
+
+static void pacontrol_set_mute(zmq::socket_t& sock, bool mute)
+{
+ string message = "{'PA0' : {'Mute': ";
+ message += (mute ? "True" : "False");
+ message += "}}";
+
+ try {
+ const auto r = sock.send(zmq::const_buffer{message.data(), message.size()});
+ if (r.has_value()) {
+ etiLog.level(debug) << "Sent mute=" << mute << " to pacontrol";
+ }
+ else {
+ // zmq_send returned EAGAIN
+ etiLog.level(info) << "Send mute=" << mute << " failed";
+ }
+ }
+ catch (const zmq::error_t& err) {
+ etiLog.level(warn) << "Failed to send mute=" << mute << ": " << err.what();
+ }
}
void Dexter::channel_up()
@@ -178,6 +239,10 @@ void Dexter::channel_up()
m_channel_is_up = true;
etiLog.level(debug) << "DEXTER CHANNEL_UP";
+
+ if (m_zmq_sock.connected()) {
+ pacontrol_set_mute(m_zmq_sock, false);
+ }
}
void Dexter::channel_down()
@@ -194,6 +259,10 @@ void Dexter::channel_down()
m_channel_is_up = false;
etiLog.level(debug) << "DEXTER CHANNEL_DOWN";
+
+ if (m_zmq_sock.connected()) {
+ pacontrol_set_mute(m_zmq_sock, true);
+ }
}
void Dexter::handle_hw_time()
diff --git a/src/output/Dexter.h b/src/output/Dexter.h
index d4f425f..57b9798 100644
--- a/src/output/Dexter.h
+++ b/src/output/Dexter.h
@@ -34,8 +34,14 @@ DESCRIPTION:
# include <config.h>
#endif
-#ifdef HAVE_DEXTER
+#if defined(HAVE_DEXTER)
+
+#if !defined(HAVE_ZEROMQ)
+#error "ZeroMQ is mandatory for DEXTER"
+#endif
+
#include "iio.h"
+#include "zmq.hpp"
#include <string>
#include <memory>
@@ -120,6 +126,12 @@ class Dexter : public Output::SDRDevice
size_t num_buffers_pushed = 0;
+ /* Communication with pacontrol */
+ zmq::context_t m_zmq_context;
+ zmq::socket_t m_zmq_sock;
+ std::string m_pacontrol_endpoint;
+
+ /* Clock State */
DexterClockState m_clock_state = DexterClockState::Startup;
// Only valid when m_clock_state is not Startup
diff --git a/src/output/SDRDevice.h b/src/output/SDRDevice.h
index 26272be..f84b340 100644
--- a/src/output/SDRDevice.h
+++ b/src/output/SDRDevice.h
@@ -94,6 +94,10 @@ struct SDRDeviceConfig {
// TCP port on which to serve TX and RX samples for the
// digital pre distortion learning tool
uint16_t dpdFeedbackServerPort = 0;
+
+ // DEXTER-specific
+ std::string pacontrol_config_endpoint;
+ std::optional<int> pacontrol_targetpower; // dBm
};
// Each frame contains one OFDM frame, and its