summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2017-08-30 19:06:51 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2017-08-30 19:06:51 +0200
commit65afcb59dd63e22e8c7877228e21ed321a49312b (patch)
tree4a7ce46c7f96459bddf9e0b45305195e49be28be /src
parent728a120df27d5f27a477f1faae0059a5fcab150c (diff)
downloaddabmod-65afcb59dd63e22e8c7877228e21ed321a49312b.tar.gz
dabmod-65afcb59dd63e22e8c7877228e21ed321a49312b.tar.bz2
dabmod-65afcb59dd63e22e8c7877228e21ed321a49312b.zip
Rework UHD output and add underrun and frame counters to RC
This makes it easier for users to monitor underruns if parsing the syslog is not possible.
Diffstat (limited to 'src')
-rw-r--r--src/OutputUHD.cpp243
-rw-r--r--src/OutputUHD.h160
2 files changed, 195 insertions, 208 deletions
diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp
index c2f985b..10e605f 100644
--- a/src/OutputUHD.cpp
+++ b/src/OutputUHD.cpp
@@ -49,7 +49,7 @@
using namespace std;
-// Maximum number of frames that can wait in uwd.frames
+// Maximum number of frames that can wait in frames
static const size_t FRAMES_MAX_SIZE = 8;
typedef std::complex<float> complexf;
@@ -158,16 +158,13 @@ OutputUHD::OutputUHD(
myConf(config),
// Since we don't know the buffer size, we cannot initialise
// the buffers at object initialisation.
- first_run(true),
- gps_fix_verified(false),
- worker(&uwd),
- myDelayBuf(0)
+ myDelayBuf(0),
+ running(false)
{
myConf.muting = true; // is remote-controllable, and reset by the GPS fix check
myConf.staticDelayUs = 0; // is remote-controllable
// Variables needed for GPS fix check
- num_checks_without_gps_fix = 1;
first_gps_fix_check.tv_sec = 0;
last_gps_fix_check.tv_sec = 0;
time_last_frame.tv_sec = 0;
@@ -196,25 +193,29 @@ OutputUHD::OutputUHD(
/* register the parameters that can be remote controlled */
RC_ADD_PARAMETER(txgain, "UHD analog daughterboard TX gain");
RC_ADD_PARAMETER(rxgain, "UHD analog daughterboard RX gain for DPD feedback");
- RC_ADD_PARAMETER(freq, "UHD transmission frequency");
+ RC_ADD_PARAMETER(freq, "UHD transmission frequency");
RC_ADD_PARAMETER(muting, "Mute the output by stopping the transmitter");
RC_ADD_PARAMETER(staticdelay, "Set static delay (uS) between 0 and 96000");
+ RC_ADD_PARAMETER(underruns, "Read-only counter of number of underruns");
+ RC_ADD_PARAMETER(latepackets, "Read-only counter of number of late packets");
+ RC_ADD_PARAMETER(frames, "Read-only counter of number of frames modulated");
uhd::msg::register_handler(uhd_msg_handler);
uhd::set_thread_priority_safe();
- //create a usrp device
- MDEBUG("OutputUHD:Creating the usrp device with: %s...\n",
+ etiLog.log(info, "OutputUHD:Creating the usrp device with: %s...",
device.str().c_str());
myUsrp = uhd::usrp::multi_usrp::make(device.str());
- MDEBUG("OutputUHD:Using device: %s...\n", myUsrp->get_pp_string().c_str());
+ etiLog.log(info, "OutputUHD:Using device: %s...",
+ myUsrp->get_pp_string().c_str());
if (myConf.masterClockRate != 0.0) {
double master_clk_rate = myUsrp->get_master_clock_rate();
- MDEBUG("OutputUHD:Checking master clock rate: %f...\n", master_clk_rate);
+ etiLog.log(debug, "OutputUHD:Checking master clock rate: %f...",
+ master_clk_rate);
if (fabs(master_clk_rate - myConf.masterClockRate) >
(myConf.masterClockRate * 1e-6)) {
@@ -237,20 +238,16 @@ OutputUHD::OutputUHD(
uhd::usrp::multi_usrp::ALL_MBOARDS);
}
- std::cerr << "UHD clock source is " <<
- myUsrp->get_clock_source(0) << std::endl;
+ etiLog.level(debug) << "UHD clock source is " << myUsrp->get_clock_source(0);
- std::cerr << "UHD time source is " <<
- myUsrp->get_time_source(0) << std::endl;
+ etiLog.level(debug) << "UHD time source is " << myUsrp->get_time_source(0);
- //set the tx sample rate
- MDEBUG("OutputUHD:Setting rate to %d...\n", myConf.sampleRate);
myUsrp->set_tx_rate(myConf.sampleRate);
- MDEBUG("OutputUHD:Actual TX Rate: %f sps...\n", myUsrp->get_tx_rate());
+ etiLog.log(debug, "OutputUHD:Set rate to %d. Actual TX Rate: %f sps...",
+ myConf.sampleRate, myUsrp->get_tx_rate());
if (fabs(myUsrp->get_tx_rate() / myConf.sampleRate) >
myConf.sampleRate * 1e-6) {
- MDEBUG("OutputUHD: Cannot set sample\n");
throw std::runtime_error("Cannot set USRP sample rate. Aborted.");
}
@@ -264,52 +261,71 @@ OutputUHD::OutputUHD(
"OutputUHD:Actual RX frequency: " << myUsrp->get_tx_freq();
myUsrp->set_tx_gain(myConf.txgain);
- MDEBUG("OutputUHD:Actual TX Gain: %f ...\n", myUsrp->get_tx_gain());
+ etiLog.log(debug, "OutputUHD:Actual TX Gain: %f", myUsrp->get_tx_gain());
- MDEBUG("OutputUHD:Mute on missing timestamps: %s ...\n",
+ etiLog.log(debug, "OutputUHD:Mute on missing timestamps: %s",
myConf.muteNoTimestamps ? "enabled" : "disabled");
// preparing output thread worker data
- uwd.myUsrp = myUsrp;
+ sourceContainsTimestamp = false;
- uwd.sampleRate = myConf.sampleRate;
- uwd.sourceContainsTimestamp = false;
- uwd.muteNoTimestamps = myConf.muteNoTimestamps;
- uwd.refclk_lock_loss_behaviour = myConf.refclk_lock_loss_behaviour;
- uwd.gpsdo_is_ettus = false;
+ SetDelayBuffer(myConf.dabMode);
+
+ myUsrp->set_rx_rate(myConf.sampleRate);
+ etiLog.log(debug, "OutputUHD:Actual RX Rate: %f sps.", myUsrp->get_rx_rate());
+
+ myUsrp->set_rx_antenna("RX2");
+ etiLog.log(debug, "OutputUHD:Set RX Antenna: %s",
+ myUsrp->get_rx_antenna().c_str());
+
+ myUsrp->set_rx_gain(myConf.rxgain);
+ etiLog.log(debug, "OutputUHD:Actual RX Gain: %f", myUsrp->get_rx_gain());
+
+ uhdFeedback.setup(myUsrp, myConf.dpdFeedbackServerPort, myConf.sampleRate);
+
+ MDEBUG("OutputUHD:UHD ready.\n");
+}
+
+bool OutputUHD::refclk_loss_needs_check() const
+{
+ if (suppress_refclk_loss_check) {
+ return false;
+ }
+ return myConf.refclk_src != "internal";
+}
+bool OutputUHD::gpsfix_needs_check() const
+{
if (myConf.refclk_src == "internal") {
- uwd.check_refclk_loss = false;
- uwd.check_gpsfix = false;
+ return false;
}
else if (myConf.refclk_src == "gpsdo") {
- uwd.check_refclk_loss = true;
- uwd.check_gpsfix = (myConf.maxGPSHoldoverTime != 0);
+ return (myConf.maxGPSHoldoverTime != 0);
}
else if (myConf.refclk_src == "gpsdo-ettus") {
- uwd.check_refclk_loss = true;
- uwd.check_gpsfix = (myConf.maxGPSHoldoverTime != 0);
- uwd.gpsdo_is_ettus = true;
+ return (myConf.maxGPSHoldoverTime != 0);
}
else {
- uwd.check_refclk_loss = true;
- uwd.check_gpsfix = false;
+ return false;
}
+}
- SetDelayBuffer(myConf.dabMode);
-
- myUsrp->set_rx_rate(myConf.sampleRate);
- MDEBUG("OutputUHD:Actual RX Rate: %f sps...\n", myUsrp->get_rx_rate());
-
- myUsrp->set_rx_antenna("RX2");
- MDEBUG("OutputUHD:Set RX Antenna: %s ...\n", myUsrp->get_rx_antenna().c_str());
-
- myUsrp->set_rx_gain(myConf.rxgain);
- MDEBUG("OutputUHD:Actual RX Gain: %f ...\n", myUsrp->get_rx_gain());
+bool OutputUHD::gpsdo_is_ettus() const
+{
+ return (myConf.refclk_src == "gpsdo-ettus");
+}
- uhdFeedback.setup(myUsrp, myConf.dpdFeedbackServerPort, myConf.sampleRate);
+OutputUHD::~OutputUHD()
+{
+ stop_threads();
+}
- MDEBUG("OutputUHD:UHD ready.\n");
+void OutputUHD::stop_threads()
+{
+ running.store(false);
+ uhd_thread.interrupt();
+ uhd_thread.join();
+ async_rx_thread.join();
}
@@ -346,10 +362,8 @@ void OutputUHD::SetDelayBuffer(unsigned int dabMode)
int OutputUHD::process(Buffer* dataIn)
{
- uwd.muting = myConf.muting;
-
if (not gps_fix_verified) {
- if (uwd.check_gpsfix) {
+ if (gpsfix_needs_check()) {
initial_gps_check();
if (num_checks_without_gps_fix == 0) {
@@ -374,7 +388,10 @@ int OutputUHD::process(Buffer* dataIn)
SetDelayBuffer(myEtiSource->getMode());
}
- worker.start(&uwd);
+ running.store(true);
+ uhd_thread = boost::thread(&OutputUHD::workerthread, this);
+ async_rx_thread = boost::thread(
+ &OutputUHD::print_async_thread, this);
lastLen = dataIn->getLength();
first_run = false;
@@ -389,16 +406,15 @@ int OutputUHD::process(Buffer* dataIn)
throw std::runtime_error("Non-constant input length!");
}
- uwd.sourceContainsTimestamp = myConf.enableSync &&
+ sourceContainsTimestamp = myConf.enableSync and
myEtiSource->sourceContainsTimestamp();
-
- if (uwd.check_gpsfix) {
+ if (gpsfix_needs_check()) {
try {
check_gps();
}
catch (std::runtime_error& e) {
- uwd.running = false;
+ running.store(false);
etiLog.level(error) << e.what();
}
}
@@ -429,12 +445,13 @@ int OutputUHD::process(Buffer* dataIn)
myEtiSource->calculateTimestamp(frame.ts);
- if (!uwd.running) {
- worker.stop();
+ if (not running.load()) {
+ uhd_thread.interrupt();
+ uhd_thread.join();
+ async_rx_thread.join();
first_run = true;
- etiLog.level(error) <<
- "OutputUHD: Error, UHD worker failed";
+ etiLog.level(error) << "OutputUHD: Error, UHD worker failed";
throw std::runtime_error("UHD worker failed");
}
@@ -445,7 +462,7 @@ int OutputUHD::process(Buffer* dataIn)
else {
uhdFeedback.set_tx_frame(frame.buf, frame.ts);
- size_t num_frames = uwd.frames.push_wait_if_full(frame,
+ size_t num_frames = frames.push_wait_if_full(frame,
FRAMES_MAX_SIZE);
etiLog.log(trace, "UHD,push %zu", num_frames);
}
@@ -457,7 +474,7 @@ int OutputUHD::process(Buffer* dataIn)
void OutputUHD::set_usrp_time()
{
- if (myConf.enableSync && (myConf.pps_src == "none")) {
+ if (myConf.enableSync and (myConf.pps_src == "none")) {
etiLog.level(warn) <<
"OutputUHD: WARNING:"
" you are using synchronous transmission without PPS input!";
@@ -574,7 +591,7 @@ void OutputUHD::check_gps()
// Divide interval by two because we alternate between
// launch and check
- if (uwd.check_gpsfix and
+ if (gpsfix_needs_check() and
last_gps_fix_check.tv_sec + gps_fix_check_interval/2.0 <
time_now.tv_sec) {
last_gps_fix_check = time_now;
@@ -615,7 +632,7 @@ void OutputUHD::check_gps()
else {
// Checking the sensor here takes too much
// time, it has to be done in a separate thread.
- if (uwd.gpsdo_is_ettus) {
+ if (gpsdo_is_ettus()) {
gps_fix_pt = boost::packaged_task<bool>(
boost::bind(check_gps_locked, myUsrp) );
}
@@ -630,9 +647,7 @@ void OutputUHD::check_gps()
}
}
-//============================ UHD Worker ========================
-
-void UHDWorker::process_errhandler()
+void OutputUHD::workerthread()
{
// Set thread priority to realtime
if (int ret = set_realtime_prio(1)) {
@@ -641,17 +656,10 @@ void UHDWorker::process_errhandler()
set_thread_name("uhdworker");
- process();
- uwd->running = false;
- etiLog.level(warn) << "UHD worker terminated";
-}
-
-void UHDWorker::process()
-{
last_tx_time_initialised = false;
uhd::stream_args_t stream_args("fc32"); //complex floats
- myTxStream = uwd->myUsrp->get_tx_stream(stream_args);
+ myTxStream = myUsrp->get_tx_stream(stream_args);
md.start_of_burst = false;
md.end_of_burst = false;
@@ -659,21 +667,22 @@ void UHDWorker::process()
num_underflows = 0;
num_late_packets = 0;
- int last_num_underflows = 0;
+ size_t last_num_underflows = 0;
size_t pop_prebuffering = FRAMES_MAX_SIZE;
- while (uwd->running) {
+ while (running.load()) {
md.has_time_spec = false;
md.time_spec = uhd::time_spec_t(0.0);
struct UHDWorkerFrameData frame;
etiLog.log(trace, "UHD,wait");
- uwd->frames.wait_and_pop(frame, pop_prebuffering);
+ frames.wait_and_pop(frame, pop_prebuffering);
etiLog.log(trace, "UHD,pop");
handle_frame(&frame);
+ num_frames_modulated++;
- /* Ensure we fill uwd->frames after every underrun and
+ /* Ensure we fill frames after every underrun and
* at startup to reduce underrun likelihood. */
if (last_num_underflows < num_underflows) {
pop_prebuffering = FRAMES_MAX_SIZE;
@@ -683,38 +692,38 @@ void UHDWorker::process()
}
last_num_underflows = num_underflows;
}
+ running.store(false);
+ etiLog.level(warn) << "UHD worker terminated";
}
-void UHDWorker::handle_frame(const struct UHDWorkerFrameData *frame)
+void OutputUHD::handle_frame(const struct UHDWorkerFrameData *frame)
{
// Transmit timeout
static const double tx_timeout = 20.0;
// Check for ref_lock
- if (uwd->check_refclk_loss) {
+ if (refclk_loss_needs_check()) {
try {
- // TODO: Is this check specific to the B100 and USRP2 ?
- if (! uwd->myUsrp->get_mboard_sensor("ref_locked", 0).to_bool()) {
+ if (not myUsrp->get_mboard_sensor("ref_locked", 0).to_bool()) {
etiLog.log(alert,
"OutputUHD: External reference clock lock lost !");
- if (uwd->refclk_lock_loss_behaviour == CRASH) {
+ if (myConf.refclk_lock_loss_behaviour == CRASH) {
throw std::runtime_error(
"OutputUHD: External reference clock lock lost.");
}
}
}
catch (uhd::lookup_error &e) {
- uwd->check_refclk_loss = false;
- etiLog.log(warn,
- "OutputUHD: This USRP does not have mboard sensor for ext clock loss."
- " Check disabled.");
+ suppress_refclk_loss_check = true;
+ etiLog.log(warn, "OutputUHD: This USRP does not have mboard "
+ "sensor for ext clock loss. Check disabled.");
}
}
- double usrp_time = uwd->myUsrp->get_time_now().get_real_secs();
+ double usrp_time = myUsrp->get_time_now().get_real_secs();
bool timestamp_discontinuity = false;
- if (uwd->sourceContainsTimestamp) {
+ if (sourceContainsTimestamp) {
// Tx time from MNSC and TIST
uint32_t tx_second = frame->ts.timestamp_sec;
uint32_t tx_pps = frame->ts.timestamp_pps;
@@ -734,7 +743,7 @@ void UHDWorker::handle_frame(const struct UHDWorkerFrameData *frame)
if (last_tx_time_initialised) {
const size_t sizeIn = frame->buf.size() / sizeof(complexf);
uint64_t increment = (uint64_t)sizeIn * 16384000ul /
- (uint64_t)uwd->sampleRate;
+ (uint64_t)myConf.sampleRate;
// samps * ticks/s / (samps/s)
// (samps * ticks * s) / (s * samps)
// ticks
@@ -793,11 +802,10 @@ void UHDWorker::handle_frame(const struct UHDWorkerFrameData *frame)
throw std::runtime_error("Timestamp error. Aborted.");
}
}
- else { // !uwd->sourceContainsTimestamp
- if (uwd->muting || uwd->muteNoTimestamps) {
- /* There was some error decoding the timestamp
- */
- if (uwd->muting) {
+ else { // !sourceContainsTimestamp
+ if (myConf.muting or myConf.muteNoTimestamps) {
+ /* There was some error decoding the timestamp */
+ if (myConf.muting) {
etiLog.log(info,
"OutputUHD: Muting sample %d requested\n",
frame->ts.fct);
@@ -815,7 +823,7 @@ void UHDWorker::handle_frame(const struct UHDWorkerFrameData *frame)
tx_frame(frame, timestamp_discontinuity);
}
-void UHDWorker::tx_frame(const struct UHDWorkerFrameData *frame, bool ts_update)
+void OutputUHD::tx_frame(const struct UHDWorkerFrameData *frame, bool ts_update)
{
const double tx_timeout = 20.0;
const size_t sizeIn = frame->buf.size() / sizeof(complexf);
@@ -823,7 +831,7 @@ void UHDWorker::tx_frame(const struct UHDWorkerFrameData *frame, bool ts_update)
size_t usrp_max_num_samps = myTxStream->get_max_num_samps();
size_t num_acc_samps = 0; //number of accumulated samples
- while (uwd->running && !uwd->muting && (num_acc_samps < sizeIn)) {
+ while (running.load() and (not myConf.muting) and (num_acc_samps < sizeIn)) {
size_t samps_to_send = std::min(sizeIn - num_acc_samps, usrp_max_num_samps);
uhd::tx_metadata_t md_tx = md;
@@ -831,8 +839,8 @@ void UHDWorker::tx_frame(const struct UHDWorkerFrameData *frame, bool ts_update)
//ensure the the last packet has EOB set if the timestamps has been
//refreshed and need to be reconsidered.
md_tx.end_of_burst = (
- uwd->sourceContainsTimestamp &&
- (frame->ts.timestamp_refresh or ts_update) &&
+ sourceContainsTimestamp and
+ (frame->ts.timestamp_refresh or ts_update) and
samps_to_send <= usrp_max_num_samps );
@@ -845,21 +853,21 @@ void UHDWorker::tx_frame(const struct UHDWorkerFrameData *frame, bool ts_update)
num_acc_samps += num_tx_samps;
md_tx.time_spec = md.time_spec +
- uhd::time_spec_t(0, num_tx_samps/uwd->sampleRate);
+ uhd::time_spec_t(0, num_tx_samps/myConf.sampleRate);
if (num_tx_samps == 0) {
etiLog.log(warn,
- "UHDWorker::process() unable to write to device, skipping frame!\n");
+ "OutputUHD::workerthread() unable to write to device, skipping frame!\n");
break;
}
}
}
-void UHDWorker::print_async_metadata()
+void OutputUHD::print_async_thread()
{
- while (uwd->running) {
+ while (running.load()) {
uhd::async_metadata_t async_md;
- if (uwd->myUsrp->get_device()->recv_async_msg(async_md, 1)) {
+ if (myUsrp->get_device()->recv_async_msg(async_md, 1)) {
const char* uhd_async_message = "";
bool failure = false;
switch (async_md.event_code) {
@@ -903,17 +911,19 @@ void UHDWorker::print_async_metadata()
auto time_now = std::chrono::steady_clock::now();
if (last_print_time + std::chrono::seconds(1) < time_now) {
const double usrp_time =
- uwd->myUsrp->get_time_now().get_real_secs();
+ myUsrp->get_time_now().get_real_secs();
- if (num_underflows or num_late_packets) {
+ if ( (num_underflows > num_underflows_previous) or
+ (num_late_packets > num_late_packets_previous)) {
etiLog.log(info,
"OutputUHD status (usrp time: %f): "
"%d underruns and %d late packets since last status.\n",
usrp_time,
num_underflows, num_late_packets);
}
- num_underflows = 0;
- num_late_packets = 0;
+
+ num_underflows_previous = num_underflows;
+ num_late_packets_previous = num_late_packets;
last_print_time = time_now;
}
@@ -923,7 +933,6 @@ void UHDWorker::print_async_metadata()
// =======================================
// Remote Control for UHD
// =======================================
-
void OutputUHD::set_parameter(const string& parameter, const string& value)
{
stringstream ss(value);
@@ -964,6 +973,11 @@ void OutputUHD::set_parameter(const string& parameter, const string& value)
myConf.staticDelayUs = newStaticDelayUs;
}
}
+ else if (parameter == "underruns" or
+ parameter == "latepackets" or
+ parameter == "frames") {
+ throw ParameterError("Parameter " + parameter + " is read-only.");
+ }
else {
stringstream ss;
ss << "Parameter '" << parameter
@@ -990,6 +1004,15 @@ const string OutputUHD::get_parameter(const string& parameter) const
else if (parameter == "staticdelay") {
ss << myConf.staticDelayUs;
}
+ else if (parameter == "underruns") {
+ ss << num_underflows;
+ }
+ else if (parameter == "latepackets") {
+ ss << num_late_packets;
+ }
+ else if (parameter == "frames") {
+ ss << num_frames_modulated;
+ }
else {
ss << "Parameter '" << parameter <<
"' is not exported by controllable " << get_rc_name();
diff --git a/src/OutputUHD.h b/src/OutputUHD.h
index c966c7e..f1ae09c 100644
--- a/src/OutputUHD.h
+++ b/src/OutputUHD.h
@@ -12,8 +12,8 @@ DESCRIPTION:
library. This version is multi-threaded. A separate thread sends the data to
the device.
- Data between the modulator and the UHD thread is exchanged by swapping
- buffers at a synchronisation barrier.
+ Data between the modulator and the UHD thread are exchanged through a
+ threadsafe queue.
*/
/*
@@ -49,6 +49,7 @@ DESCRIPTION:
#include <chrono>
#include <memory>
#include <string>
+#include <atomic>
#include "Log.h"
#include "ModPlugin.h"
@@ -61,8 +62,8 @@ DESCRIPTION:
#include <stdio.h>
#include <sys/types.h>
-#define MDEBUG(fmt, args...) fprintf (LOG, fmt , ## args)
-//#define MDEBUG(fmt, args...)
+//#define MDEBUG(fmt, args...) fprintf(LOG, fmt , ## args)
+#define MDEBUG(fmt, args...)
// If the timestamp is further in the future than
// 100 seconds, abort
@@ -87,93 +88,6 @@ struct UHDWorkerFrameData {
enum refclk_lock_loss_behaviour_t { CRASH, IGNORE };
-struct UHDWorkerData {
- bool running;
-
- uhd::usrp::multi_usrp::sptr myUsrp;
- unsigned sampleRate;
-
- bool sourceContainsTimestamp;
-
- // When working with timestamps, mute the frames that
- // do not have a timestamp
- bool muteNoTimestamps;
-
- ThreadsafeQueue<UHDWorkerFrameData> frames;
-
- // If we want to verify loss of refclk
- bool check_refclk_loss;
-
- // If we want to check for the gps_timelock sensor
- bool check_gpsfix;
-
- bool gpsdo_is_ettus; // Set to false in case the ODR LEA-M8F board is used
-
- // muting set by remote control
- bool muting;
-
- // What to do when the reference clock PLL loses lock
- refclk_lock_loss_behaviour_t refclk_lock_loss_behaviour;
-};
-
-
-class UHDWorker {
- public:
- UHDWorker(struct UHDWorkerData *uhdworkerdata) {
- uwd = uhdworkerdata;
- }
-
- void start(struct UHDWorkerData *uhdworkerdata) {
- uwd->running = true;
- uhd_thread = boost::thread(&UHDWorker::process_errhandler, this);
- async_rx_thread = boost::thread(
- &UHDWorker::print_async_metadata, this);
- }
-
- void stop() {
- if (uwd) {
- uwd->running = false;
- }
- uhd_thread.interrupt();
- uhd_thread.join();
- async_rx_thread.join();
- }
-
- ~UHDWorker() {
- stop();
- }
-
- UHDWorker(const UHDWorker& other) = delete;
- UHDWorker& operator=(const UHDWorker& other) = delete;
-
- private:
- // Asynchronous message statistics
- int num_underflows;
- int num_late_packets;
-
- uhd::tx_metadata_t md;
- bool last_tx_time_initialised;
- uint32_t last_tx_second;
- uint32_t last_tx_pps;
-
- // Used to print statistics once a second
- std::chrono::steady_clock::time_point last_print_time;
-
- void print_async_metadata(void);
-
- void handle_frame(const struct UHDWorkerFrameData *frame);
- void tx_frame(const struct UHDWorkerFrameData *frame, bool ts_update);
-
- struct UHDWorkerData *uwd;
- boost::thread uhd_thread;
- boost::thread async_rx_thread;
-
- uhd::tx_streamer::sptr myTxStream;
-
- void process();
- void process_errhandler();
-};
-
/* This structure is used as initial configuration for OutputUHD.
* It must also contain all remote-controllable settings, otherwise
* they will get lost on a modulator restart. */
@@ -191,6 +105,9 @@ struct OutputUHDConfig {
double txgain = 0.0;
double rxgain = 0.0;
bool enableSync = false;
+
+ // When working with timestamps, mute the frames that
+ // do not have a timestamp
bool muteNoTimestamps = false;
unsigned dabMode = 0;
unsigned maxGPSHoldoverTime = 0;
@@ -221,6 +138,9 @@ struct OutputUHDConfig {
class OutputUHD: public ModOutput, public RemoteControllable {
public:
OutputUHD(OutputUHDConfig& config);
+ OutputUHD(const OutputUHD& other) = delete;
+ OutputUHD operator=(const OutputUHD& other) = delete;
+ ~OutputUHD();
int process(Buffer* dataIn);
@@ -239,14 +159,12 @@ class OutputUHD: public ModOutput, public RemoteControllable {
const std::string& parameter) const;
protected:
- EtiSource *myEtiSource;
+ EtiSource *myEtiSource = nullptr;
OutputUHDConfig& myConf;
uhd::usrp::multi_usrp::sptr myUsrp;
std::shared_ptr<boost::barrier> mySyncBarrier;
- bool first_run;
- bool gps_fix_verified;
- struct UHDWorkerData uwd;
- UHDWorker worker;
+ bool first_run = true;
+ bool gps_fix_verified = false;
OutputUHDFeedback uhdFeedback;
private:
@@ -258,10 +176,10 @@ class OutputUHD: public ModOutput, public RemoteControllable {
// The remote-controllable static delay is in the OutputUHDConfig
int myTFDurationMs; // TF duration in milliseconds
std::vector<complexf> myDelayBuf;
- size_t lastLen;
+ size_t lastLen = 0;
// GPS Fix check variables
- int num_checks_without_gps_fix;
+ int num_checks_without_gps_fix = 1;
struct timespec first_gps_fix_check;
struct timespec last_gps_fix_check;
struct timespec time_last_frame;
@@ -275,6 +193,52 @@ class OutputUHD: public ModOutput, public RemoteControllable {
// Interval for checking the GPS at runtime
static constexpr double gps_fix_check_interval = 10.0; // seconds
+ // Asynchronous message statistics
+ size_t num_underflows = 0;
+ size_t num_late_packets = 0;
+ size_t num_underflows_previous = 0;
+ size_t num_late_packets_previous = 0;
+
+ size_t num_frames_modulated = 0;
+
+ uhd::tx_metadata_t md;
+ bool last_tx_time_initialised = false;
+ uint32_t last_tx_second = 0;
+ uint32_t last_tx_pps = 0;
+
+ // Used to print statistics once a second
+ std::chrono::steady_clock::time_point last_print_time;
+
+ bool sourceContainsTimestamp = false;
+
+ ThreadsafeQueue<UHDWorkerFrameData> frames;
+
+ // Returns true if we want to verify loss of refclk
+ bool refclk_loss_needs_check(void) const;
+ bool suppress_refclk_loss_check = false;
+
+ // Returns true if we want to check for the gps_timelock sensor
+ bool gpsfix_needs_check(void) const;
+
+ // Return true if the gpsdo is from ettus, false if it is the ODR
+ // LEA-M8F board is used
+ bool gpsdo_is_ettus(void) const;
+
+ std::atomic<bool> running;
+ boost::thread uhd_thread;
+ boost::thread async_rx_thread;
+ void stop_threads(void);
+
+ uhd::tx_streamer::sptr myTxStream;
+
+ // The worker thread decouples the modulator from UHD
+ void workerthread();
+ void handle_frame(const struct UHDWorkerFrameData *frame);
+ void tx_frame(const struct UHDWorkerFrameData *frame, bool ts_update);
+
+ // Poll asynchronous metadata from UHD
+ void print_async_thread(void);
+
void check_gps();
void set_usrp_time();