From 685095418bc8fd27dcd0b1d73ad1741114aeda6a Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 14 Sep 2014 00:08:53 +0200 Subject: SFN: carry FCT along with timestamps This is the first step to fix issue #6. The goal is to enable the OutputUHD to check for FCT consistency. Once it can do that, it will also be able to reset the UHD streamer if necessary. --- src/EtiReader.cpp | 19 +++++++--------- src/EtiReader.h | 9 ++++---- src/InputZeroMQReader.cpp | 4 +++- src/OutputUHD.cpp | 56 ++++++++++++++++++++++++++++++++++++++--------- src/OutputUHD.h | 14 ++++++++---- src/TimestampDecoder.cpp | 16 ++++++++++---- src/TimestampDecoder.h | 22 ++++++++++++++----- 7 files changed, 100 insertions(+), 40 deletions(-) diff --git a/src/EtiReader.cpp b/src/EtiReader.cpp index b61481c..f7376cc 100644 --- a/src/EtiReader.cpp +++ b/src/EtiReader.cpp @@ -2,8 +2,10 @@ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Includes modifications for which no copyright is claimed - 2012, Matthias P. Braendli, matthias.braendli@mpb.li + Copyright (C) 2014 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org */ /* This file is part of ODR-DabMod. @@ -269,18 +271,17 @@ int EtiReader::process(Buffer* dataIn) } break; default: - // throw std::runtime_error("Invalid state!"); + // throw std::runtime_error("Invalid state!"); PDEBUG("Invalid state (%i)!", state); input_size = 0; } } - + // Update timestamps myTimestampDecoder.updateTimestampEti(eti_fc.FP & 0x3, - eti_eoh.MNSC, - getPPSOffset()); + eti_eoh.MNSC, getPPSOffset(), eti_fc.FCT); - if (getFCT() % 125 == 0) //every 3 seconds is fine enough + if (eti_fc.FCT % 125 == 0) //every 3 seconds is fine enough { myTimestampDecoder.updateModulatorOffset(); } @@ -306,7 +307,3 @@ double EtiReader::getPPSOffset() return pps; } -uint32_t EtiReader::getFCT() -{ - return eti_fc.FCT; -} diff --git a/src/EtiReader.h b/src/EtiReader.h index be12075..209b208 100644 --- a/src/EtiReader.h +++ b/src/EtiReader.h @@ -2,8 +2,10 @@ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Includes modifications for which no copyright is claimed - 2012, Matthias P. Braendli, matthias.braendli@mpb.li + Copyright (C) 2014 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org */ /* This file is part of ODR-DabMod. @@ -60,9 +62,6 @@ public: myTimestampDecoder.calculateTimestamp(ts); } - /* Return the frame counter */ - uint32_t getFCT(); - /* Returns true if we have valid time stamps in the ETI*/ bool sourceContainsTimestamp(); diff --git a/src/InputZeroMQReader.cpp b/src/InputZeroMQReader.cpp index cf3f7aa..cfb56b2 100644 --- a/src/InputZeroMQReader.cpp +++ b/src/InputZeroMQReader.cpp @@ -3,8 +3,10 @@ Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyrigth (C) 2013, 2014 + Copyright (C) 2013, 2014 Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org */ /* This file is part of ODR-DabMod. diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index b44cd3f..927d2e6 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -58,6 +58,9 @@ OutputUHD::OutputUHD( { myMuting = 0; // is remote-controllable +#if FAKE_UHD + MDEBUG("OutputUHD:Using fake UHD output"); +#else std::stringstream device; device << myConf.device; @@ -198,6 +201,7 @@ OutputUHD::OutputUHD( // preparing output thread worker data uwd.myUsrp = myUsrp; +#endif uwd.frame0.ts.timestamp_valid = false; uwd.frame1.ts.timestamp_valid = false; @@ -257,7 +261,15 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) myEtiReader->calculateTimestamp(ts); uwd.frame0.ts = ts; - uwd.frame0.fct = myEtiReader->getFCT(); + + switch (myEtiReader->getMode()) { + case 1: uwd.fct_increment = 4; break; + case 2: + case 3: uwd.fct_increment = 1; break; + case 4: uwd.fct_increment = 2; break; + default: break; + } + activebuffer = 1; @@ -287,13 +299,11 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) memcpy(uwd.frame0.buf, dataIn->getData(), uwd.bufsize); uwd.frame0.ts = ts; - uwd.frame0.fct = myEtiReader->getFCT(); } else if (activebuffer == 1) { memcpy(uwd.frame1.buf, dataIn->getData(), uwd.bufsize); uwd.frame1.ts = ts; - uwd.frame1.fct = myEtiReader->getFCT(); } activebuffer = (activebuffer + 1) % 2; @@ -322,9 +332,13 @@ void UHDWorker::process() // Transmit timeout const double timeout = 0.2; +#if FAKE_UHD == 0 uhd::stream_args_t stream_args("fc32"); //complex floats uhd::tx_streamer::sptr myTxStream = uwd->myUsrp->get_tx_stream(stream_args); size_t usrp_max_num_samps = myTxStream->get_max_num_samps(); +#else + size_t usrp_max_num_samps = 2048; // arbitrarily chosen +#endif const complexf* in; @@ -362,6 +376,19 @@ void UHDWorker::process() sizeIn = uwd->bufsize / sizeof(complexf); +#if FAKE_UHD + if (expected_next_fct != -1) { + if (expected_next_fct != frame->ts.fct) { + uwd->logger->level(warn) << + "OutputUHD: Incorrect expect fct " << frame->ts.fct; + + // TODO here we should disrupt the UHD streamer so that + // it resyncs to the correct timestamps + } + } + + expected_next_fct = (frame->ts.fct + uwd->fct_increment) % 250; +#else // Check for ref_lock if (uwd->check_refclk_loss) { @@ -392,7 +419,7 @@ void UHDWorker::process() * MNSC. We sleep through the frame. */ uwd->logger->level(info) << - "OutputUHD: Throwing sample " << frame->fct << + "OutputUHD: Throwing sample " << frame->ts.fct << " away: incomplete timestamp " << tx_second << " + " << pps_offset; usleep(20000); //TODO should this be TM-dependant ? @@ -408,7 +435,7 @@ void UHDWorker::process() "OutputUHD: Timestamp in the past! offset: " << md.time_spec.get_real_secs() - usrp_time << " (" << usrp_time << ")" - " frame " << frame->fct << + " frame " << frame->ts.fct << ", tx_second " << tx_second << ", pps " << pps_offset; goto loopend; //skip the frame @@ -433,7 +460,7 @@ void UHDWorker::process() "OutputUHD (usrp time: %f): frame %d;" " tx_second %zu; pps %.9f\n", usrp_time, - frame->fct, tx_second, pps_offset); + frame->ts.fct, tx_second, pps_offset); } } @@ -444,20 +471,21 @@ void UHDWorker::process() if (uwd->muting) { uwd->logger->log(info, "OutputUHD: Muting sample %d requested\n", - frame->fct); + frame->ts.fct); } else { uwd->logger->log(info, "OutputUHD: Muting sample %d : no timestamp\n", - frame->fct); + frame->ts.fct); } usleep(20000); goto loopend; } } +#endif PDEBUG("UHDWorker::process:max_num_samps: %zu.\n", - myTxStream->get_max_num_samps()); + usrp_max_num_samps); while (running && !uwd->muting && (num_acc_samps < sizeIn)) { size_t samps_to_send = std::min(sizeIn - num_acc_samps, usrp_max_num_samps); @@ -467,10 +495,16 @@ void UHDWorker::process() md.end_of_burst = (frame->ts.timestamp_refresh && (samps_to_send <= usrp_max_num_samps)); +#if FAKE_UHD + // This is probably very approximate + usleep( (1000000 / uwd->sampleRate) * samps_to_send); + size_t num_tx_samps = samps_to_send; +#else //send a single packet size_t num_tx_samps = myTxStream->send( &in[num_acc_samps], samps_to_send, md, timeout); +#endif num_acc_samps += num_tx_samps; @@ -515,6 +549,7 @@ void UHDWorker::process() #endif } +#if FAKE_UHD == 0 uhd::async_metadata_t async_md; if (uwd->myUsrp->get_device()->recv_async_msg(async_md, 0)) { const char* uhd_async_message = ""; @@ -545,11 +580,12 @@ void UHDWorker::process() if (failure) { uwd->logger->level(alert) << "Near frame " << - frame->fct << ": Received Async UHD Message '" << + frame->ts.fct << ": Received Async UHD Message '" << uhd_async_message << "'"; } } +#endif /* bool got_async_burst_ack = false; diff --git a/src/OutputUHD.h b/src/OutputUHD.h index 69e5b20..3a047bf 100644 --- a/src/OutputUHD.h +++ b/src/OutputUHD.h @@ -36,6 +36,8 @@ DESCRIPTION: #ifndef OUTPUT_UHD_H #define OUTPUT_UHD_H +#define FAKE_UHD 0 + #ifdef HAVE_CONFIG_H # include #endif @@ -77,15 +79,14 @@ struct UHDWorkerFrameData { // Full timestamp struct frame_timestamp ts; - - // Frame counter - uint32_t fct; }; enum refclk_lock_loss_behaviour_t { CRASH, IGNORE }; struct UHDWorkerData { +#if FAKE_UHD == 0 uhd::usrp::multi_usrp::sptr myUsrp; +#endif unsigned sampleRate; // Double buffering between the two threads @@ -117,7 +118,12 @@ struct UHDWorkerData { // The common logger Logger* logger; -}; + + // What transmission mode we're using defines by how + // much the FCT should increment for each + // transmission frame. + int fct_increment; +}; class UHDWorker { diff --git a/src/TimestampDecoder.cpp b/src/TimestampDecoder.cpp index d6c627f..1bb4dd2 100644 --- a/src/TimestampDecoder.cpp +++ b/src/TimestampDecoder.cpp @@ -2,8 +2,10 @@ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Includes modifications for which no copyright is claimed - 2012, Matthias P. Braendli, matthias.braendli@mpb.li + Copyright (C) 2014 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org */ /* This file is part of ODR-DabMod. @@ -45,6 +47,7 @@ void TimestampDecoder::calculateTimestamp(struct frame_timestamp& ts) ts_queued->timestamp_valid = full_timestamp_received_mnsc; ts_queued->timestamp_sec = time_secs; ts_queued->timestamp_pps_offset = time_pps; + ts_queued->fct = latestFCT; ts_queued->timestamp_refresh = offset_changed; offset_changed = false; @@ -65,6 +68,7 @@ void TimestampDecoder::calculateTimestamp(struct frame_timestamp& ts) ts.timestamp_sec = 0; ts.timestamp_pps_offset = 0; ts.timestamp_refresh = false; + ts.fct = 0; } else { //fprintf(stderr, ". %zu ", queue_timestamps.size()); @@ -179,13 +183,17 @@ void TimestampDecoder::updateTimestampPPS(double pps) } time_pps = pps; - } -void TimestampDecoder::updateTimestampEti(int framephase, uint16_t mnsc, double pps) +void TimestampDecoder::updateTimestampEti( + int framephase, + uint16_t mnsc, + double pps, + uint32_t fct) { updateTimestampPPS(pps); pushMNSCData(framephase, mnsc); + latestFCT = fct; } diff --git a/src/TimestampDecoder.h b/src/TimestampDecoder.h index 52290ac..0c393e4 100644 --- a/src/TimestampDecoder.h +++ b/src/TimestampDecoder.h @@ -2,8 +2,10 @@ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Includes modifications for which no copyright is claimed - 2012, Matthias P. Braendli, matthias.braendli@mpb.li + Copyright (C) 2014 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org */ /* This file is part of ODR-DabMod. @@ -52,6 +54,9 @@ struct modulator_offset_config struct frame_timestamp { + // Which frame count does this timestamp apply to + uint32_t fct; + uint32_t timestamp_sec; double timestamp_pps_offset; bool timestamp_valid; @@ -64,6 +69,7 @@ struct frame_timestamp this->timestamp_pps_offset = rhs.timestamp_pps_offset; this->timestamp_valid = rhs.timestamp_valid; this->timestamp_refresh = rhs.timestamp_refresh; + this->fct = rhs.fct; } return *this; @@ -104,7 +110,7 @@ struct frame_timestamp /* This module decodes MNSC time information */ class TimestampDecoder { - public: + public: TimestampDecoder( struct modulator_offset_config& config, Logger& logger): @@ -113,6 +119,7 @@ class TimestampDecoder inhibit_second_update = 0; time_pps = 0.0; time_secs = 0; + latestFCT = 0; enableDecode = false; full_timestamp_received_mnsc = false; gmtime_r(0, &temp_time); @@ -129,7 +136,11 @@ class TimestampDecoder void calculateTimestamp(struct frame_timestamp& ts); /* Update timestamp data from data in ETI */ - void updateTimestampEti(int framephase, uint16_t mnsc, double pps); + void updateTimestampEti( + int framephase, + uint16_t mnsc, + double pps, + uint32_t fct); /* Update the modulator timestamp offset according to the modconf */ @@ -147,7 +158,7 @@ class TimestampDecoder * the timestamp */ void updateTimestampPPS(double pps); - + /* Update the timestamp when a full set of MNSC data is * known. This function can be called at most every four * frames when the data is transferred using the MNSC. @@ -156,6 +167,7 @@ class TimestampDecoder struct tm temp_time; uint32_t time_secs; + uint32_t latestFCT; double time_pps; double timestamp_offset; int inhibit_second_update; -- cgit v1.2.3