From d4a1f755a9e5426187fe6e80eb32c299f81104dd Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli (think)" Date: Fri, 17 Aug 2012 11:33:02 +0200 Subject: crc-dabmod: remote control for FIRFilter --- src/DabMod.cpp | 10 +-- src/DabModulator.cpp | 14 +++-- src/DabModulator.h | 8 ++- src/FIRFilter.cpp | 174 ++++++++++++++++++++++++++++++++++++--------------- src/FIRFilter.h | 25 +++++++- src/OutputUHD.cpp | 3 +- src/RemoteControl.h | 3 + 7 files changed, 173 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 83fb210..1de320d 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -49,7 +50,6 @@ #include #include #include -#include #ifdef HAVE_NETINET_IN_H # include @@ -174,7 +174,7 @@ int main(int argc, char* argv[]) GainMode gainMode = GAIN_VAR; Buffer data; - const char* filterTapsFilename = NULL; + std::string filterTapsFilename = ""; // Two configuration sources exist: command line and (new) INI file bool use_configuration_cmdline = false; @@ -368,7 +368,7 @@ int main(int argc, char* argv[]) // FIR Filter parameters: if (pt.get("firfilter.enabled", 0) == 1) { try { - filterTapsFilename = pt.get("firfilter.enabled").c_str(); + filterTapsFilename = pt.get("firfilter.filtertapsfile"); } catch (std::exception &e) { std::cerr << "Error: " << e.what() << "\n"; @@ -455,7 +455,7 @@ int main(int argc, char* argv[]) // When using the FIRFilter, increase the modulator offset pipelining delay // by the correct amount - if (filterTapsFilename != NULL) { + if (filterTapsFilename != "") { modconf.delay_calculation_pipeline_stages += FIRFILTER_PIPELINE_DELAY; } @@ -543,7 +543,7 @@ int main(int argc, char* argv[]) flowgraph = new Flowgraph(); data.setLength(6144); input = new InputMemory(&data); - modulator = new DabModulator(modconf, outputRate, clockRate, + modulator = new DabModulator(modconf, rc, outputRate, clockRate, dabMode, gainMode, amplitude, filterTapsFilename); flowgraph->connect(input, modulator); flowgraph->connect(modulator, output); diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp index d89716b..14c6d3d 100644 --- a/src/DabModulator.cpp +++ b/src/DabModulator.cpp @@ -23,6 +23,8 @@ along with CRC-DADMOD. If not, see . */ +#include + #include "DabModulator.h" #include "PcDebug.h" @@ -45,13 +47,15 @@ #include "PuncturingEncoder.h" #include "TimeInterleaver.h" #include "TimestampDecoder.h" +#include "RemoteControl.h" DabModulator::DabModulator( struct modulator_offset_config& modconf, + BaseRemoteController* rc, unsigned outputRate, unsigned clockRate, unsigned dabMode, GainMode gainMode, float factor, - const char* filterTapsFilename + std::string filterTapsFilename ) : ModCodec(ModFormat(1), ModFormat(0)), myOutputRate(outputRate), @@ -61,7 +65,8 @@ DabModulator::DabModulator( myFactor(factor), myEtiReader(EtiReader(modconf)), myFlowgraph(NULL), - myFilterTapsFilename(filterTapsFilename) + myFilterTapsFilename(filterTapsFilename), + myRC(rc) { PDEBUG("DabModulator::DabModulator(%u, %u, %u, %u) @ %p\n", outputRate, clockRate, dabMode, gainMode, this); @@ -193,8 +198,9 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) cifGain = new GainControl(mySpacing, myGainMode, myFactor); cifGuard = new GuardIntervalInserter(myNbSymbols, mySpacing, myNullSize, mySymSize); - if (myFilterTapsFilename != NULL) { + if (myFilterTapsFilename != "") { cifFilter = new FIRFilter(myFilterTapsFilename); + cifFilter->enrol_at(*myRC); } myOutput = new OutputMemory(); @@ -338,7 +344,7 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) myFlowgraph->connect(cifOfdm, cifGain); myFlowgraph->connect(cifGain, cifGuard); - if (myFilterTapsFilename != NULL) { + if (myFilterTapsFilename != "") { myFlowgraph->connect(cifGuard, cifFilter); if (cifRes != NULL) { myFlowgraph->connect(cifFilter, cifRes); diff --git a/src/DabModulator.h b/src/DabModulator.h index 72fee41..e91507c 100644 --- a/src/DabModulator.h +++ b/src/DabModulator.h @@ -31,12 +31,14 @@ #endif #include +#include #include "ModCodec.h" #include "EtiReader.h" #include "Flowgraph.h" #include "GainControl.h" #include "OutputMemory.h" +#include "RemoteControl.h" class DabModulator : public ModCodec @@ -44,9 +46,10 @@ class DabModulator : public ModCodec public: DabModulator( struct modulator_offset_config& modconf, + BaseRemoteController* rc, unsigned outputRate = 2048000, unsigned clockRate = 0, unsigned dabMode = 0, GainMode gainMode = GAIN_VAR, - float factor = 1.0, const char* filterTapsFilename = NULL); + float factor = 1.0, std::string filterTapsFilename = ""); DabModulator(const DabModulator& copy); virtual ~DabModulator(); @@ -67,7 +70,8 @@ protected: EtiReader myEtiReader; Flowgraph* myFlowgraph; OutputMemory* myOutput; - const char* myFilterTapsFilename; + std::string myFilterTapsFilename; + BaseRemoteController* myRC; size_t myNbSymbols; size_t myNbCarriers; diff --git a/src/FIRFilter.cpp b/src/FIRFilter.cpp index 540e015..c6a2350 100644 --- a/src/FIRFilter.cpp +++ b/src/FIRFilter.cpp @@ -82,28 +82,32 @@ void FIRFilterWorker::process(struct FIRFilterWorkerData *fwd) __m128 SSEout; __m128 SSEtaps; __m128 SSEin; - for (i = 0; i < sizeIn - 2*fwd->n_taps; i += 4) { - SSEout = _mm_setr_ps(0,0,0,0); + { + boost::mutex::scoped_lock lock(fwd->taps_mutex); - for (int j = 0; j < fwd->n_taps; j++) { - if ((uintptr_t)(&in[i+2*j]) % 16 == 0) { - SSEin = _mm_load_ps(&in[i+2*j]); //faster when aligned - } - else { - SSEin = _mm_loadu_ps(&in[i+2*j]); - } + for (i = 0; i < sizeIn - 2*fwd->n_taps; i += 4) { + SSEout = _mm_setr_ps(0,0,0,0); + + for (int j = 0; j < fwd->n_taps; j++) { + if ((uintptr_t)(&in[i+2*j]) % 16 == 0) { + SSEin = _mm_load_ps(&in[i+2*j]); //faster when aligned + } + else { + SSEin = _mm_loadu_ps(&in[i+2*j]); + } - SSEtaps = _mm_load1_ps(&fwd->taps[j]); + SSEtaps = _mm_load1_ps(&fwd->taps[j]); - SSEout = _mm_add_ps(SSEout, _mm_mul_ps(SSEin, SSEtaps)); + SSEout = _mm_add_ps(SSEout, _mm_mul_ps(SSEin, SSEtaps)); + } + _mm_store_ps(&out[i], SSEout); } - _mm_store_ps(&out[i], SSEout); - } - for (; i < sizeIn; i++) { - out[i] = 0.0; - for (int j = 0; i+2*j < sizeIn; j++) { - out[i] += in[i+2*j] * fwd->taps[j]; + for (; i < sizeIn; i++) { + out[i] = 0.0; + for (int j = 0; i+2*j < sizeIn; j++) { + out[i] += in[i+2*j] * fwd->taps[j]; + } } } clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time_end); @@ -117,28 +121,31 @@ void FIRFilterWorker::process(struct FIRFilterWorkerData *fwd) clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time_start); - // Convolve by aligning both frame and taps at zero. - for (i = 0; i < sizeIn - 2*fwd->n_taps; i += 4) { - out[i] = 0.0; - out[i+1] = 0.0; - out[i+2] = 0.0; - out[i+3] = 0.0; - - for (int j = 0; j < fwd->n_taps; j++) { - out[i] += in[i + 2*j] * fwd->taps[j]; - out[i+1] += in[i+1 + 2*j] * fwd->taps[j]; - out[i+2] += in[i+2 + 2*j] * fwd->taps[j]; - out[i+3] += in[i+3 + 2*j] * fwd->taps[j]; + { + boost::mutex::scoped_lock lock(fwd->taps_mutex); + // Convolve by aligning both frame and taps at zero. + for (i = 0; i < sizeIn - 2*fwd->n_taps; i += 4) { + out[i] = 0.0; + out[i+1] = 0.0; + out[i+2] = 0.0; + out[i+3] = 0.0; + + for (int j = 0; j < fwd->n_taps; j++) { + out[i] += in[i + 2*j] * fwd->taps[j]; + out[i+1] += in[i+1 + 2*j] * fwd->taps[j]; + out[i+2] += in[i+2 + 2*j] * fwd->taps[j]; + out[i+3] += in[i+3 + 2*j] * fwd->taps[j]; + } } - } - // At the end of the frame, we cut the convolution off. - // The beginning of the next frame starts with a NULL symbol - // anyway. - for (; i < sizeIn; i++) { - out[i] = 0.0; - for (int j = 0; i+2*j < sizeIn; j++) { - out[i] += in[i+2*j] * fwd->taps[j]; + // At the end of the frame, we cut the convolution off. + // The beginning of the next frame starts with a NULL symbol + // anyway. + for (; i < sizeIn; i++) { + out[i] = 0.0; + for (int j = 0; i+2*j < sizeIn; j++) { + out[i] += in[i+2*j] * fwd->taps[j]; + } } } @@ -227,27 +234,50 @@ void FIRFilterWorker::process(struct FIRFilterWorkerData *fwd) } -FIRFilter::FIRFilter(const char* taps_file) : - ModCodec(ModFormat(sizeof(complexf)), ModFormat(sizeof(complexf))) +FIRFilter::FIRFilter(std::string taps_file) : + ModCodec(ModFormat(sizeof(complexf)), ModFormat(sizeof(complexf))), + RemoteControllable("firfilter"), + myTapsFile(taps_file) { PDEBUG("FIRFilter::FIRFilter(%s) @ %p\n", taps_file, this); + RC_ADD_PARAMETER(ntaps, "(Read-only) number of filter taps."); + RC_ADD_PARAMETER(tapsfile, "Filename containing filter taps. When written to, the new file gets automatically loaded."); + number_of_runs = 0; - std::ifstream taps_fstream(taps_file); + load_filter_taps(); + + PDEBUG("FIRFilter: Starting worker\n" ); + worker.start(&firwd); +} + +void +FIRFilter::load_filter_taps() +{ + std::ifstream taps_fstream(myTapsFile.c_str()); if(!taps_fstream) { - fprintf(stderr, "FIRFilter: file %s could not be opened !\n", taps_file); + fprintf(stderr, "FIRFilter: file %s could not be opened !\n", myTapsFile.c_str()); throw std::runtime_error("FIRFilter: Could not open file with taps! "); } int n_taps; taps_fstream >> n_taps; - my_Ntaps = n_taps; + if (n_taps <= 0) { + fprintf(stderr, "FIRFilter: warning: taps file has invalid format\n"); + throw std::runtime_error("FIRFilter: taps file has invalid format."); + } + + if (n_taps > 100) { + fprintf(stderr, "FIRFilter: warning: taps file has more than 100 taps\n"); + } + + myNtaps = n_taps; - fprintf(stderr, "FIRFilter: Reading %d taps...\n", my_Ntaps); + fprintf(stderr, "FIRFilter: Reading %d taps...\n", myNtaps); - myFilter = new float[my_Ntaps]; + myFilter = new float[myNtaps]; int n; for (n = 0; n < n_taps; n++) { @@ -255,16 +285,20 @@ FIRFilter::FIRFilter(const char* taps_file) : PDEBUG("FIRFilter: tap: %f\n", myFilter[n] ); if (taps_fstream.eof()) { fprintf(stderr, "FIRFilter: file %s should contains %d taps, but EOF reached "\ - "after %d taps !\n", taps_file, n_taps, n); + "after %d taps !\n", myTapsFile.c_str(), n_taps, n); + delete myFilter; throw std::runtime_error("FIRFilter: filtertaps file invalid ! "); } } - firwd.taps = myFilter; - firwd.n_taps = my_Ntaps; + { + boost::mutex::scoped_lock lock(firwd.taps_mutex); - PDEBUG("FIRFilter: Starting worker\n" ); - worker.start(&firwd); + delete firwd.taps; + + firwd.taps = myFilter; + firwd.n_taps = myNtaps; + } } @@ -309,3 +343,45 @@ int FIRFilter::process(Buffer* const dataIn, Buffer* dataOut) return dataOut->getLength(); } + +void FIRFilter::set_parameter(string parameter, string value) +{ + stringstream ss(value); + ss.exceptions ( stringstream::failbit | stringstream::badbit ); + + if (parameter == "ntaps") { + throw ParameterError("Parameter 'ntaps' is read-only"); + } + else if (parameter == "tapsfile") { + myTapsFile = value; + try { + load_filter_taps(); + } + catch (std::runtime_error &e) { + throw ParameterError(e.what()); + } + } + else { + stringstream ss; + ss << "Parameter '" << parameter << "' is not exported by controllable " << get_rc_name(); + throw ParameterError(ss.str()); + } +} + +string FIRFilter::get_parameter(string parameter) +{ + stringstream ss; + if (parameter == "ntaps") { + ss << myNtaps; + } + else if (parameter == "tapsfile") { + ss << myTapsFile; + } + else { + ss << "Parameter '" << parameter << "' is not exported by controllable " << get_rc_name(); + throw ParameterError(ss.str()); + } + return ss.str(); + +} + diff --git a/src/FIRFilter.h b/src/FIRFilter.h index 0c06930..b9abb3e 100644 --- a/src/FIRFilter.h +++ b/src/FIRFilter.h @@ -32,6 +32,7 @@ #include #include +#include "RemoteControl.h" #include "ModCodec.h" #include "PcDebug.h" @@ -40,6 +41,7 @@ #include #include +#include #define FIRFILTER_PIPELINE_DELAY 1 @@ -94,8 +96,17 @@ public: }; struct FIRFilterWorkerData { + /* Thread-safe queues to give data to and get data from + * the worker + */ ThreadsafeQueue input_queue; ThreadsafeQueue output_queue; + + /* Remote-control can change the taps while the filter + * runs. This lock makes sure nothing bad happens when + * the taps are being modified + */ + mutable boost::mutex taps_mutex; float* taps; int n_taps; }; @@ -133,10 +144,10 @@ class FIRFilterWorker { }; -class FIRFilter : public ModCodec +class FIRFilter : public ModCodec, public RemoteControllable { public: - FIRFilter(const char* taps_file); + FIRFilter(std::string taps_file); virtual ~FIRFilter(); FIRFilter(const FIRFilter&); FIRFilter& operator=(const FIRFilter&); @@ -144,8 +155,16 @@ public: int process(Buffer* const dataIn, Buffer* dataOut); const char* name() { return "FIRFilter"; } + /******* REMOTE CONTROL ********/ + void set_parameter(string parameter, string value); + string get_parameter(string parameter); + + protected: - int my_Ntaps; + void load_filter_taps(); + + std::string myTapsFile; + int myNtaps; float* myFilter; FIRFilterWorker worker; diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index a852c10..eb55c0d 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -332,7 +332,7 @@ void UHDWorker::process(struct UHDWorkerData *uwd) frame->fct, tx_second, pps_offset); uwd->logger->log(info, "OutputUHD: Throwing sample %d away: incomplete timestamp %zu + %f\n", frame->fct, tx_second, pps_offset); - usleep(20000); + usleep(20000); //TODO should this be TM-dependant ? goto loopend; } @@ -500,6 +500,7 @@ void UHDWorker::process(struct UHDWorkerData *uwd) frame->fct, tx_second, pps_offset); + usleep(23000); // 23ms, a bit faster than realtime for TM 2 #endif last_pps = pps_offset; diff --git a/src/RemoteControl.h b/src/RemoteControl.h index 5ffb2fb..17352bf 100644 --- a/src/RemoteControl.h +++ b/src/RemoteControl.h @@ -4,6 +4,9 @@ Center Canada) Written by Matthias P. Braendli, matthias.braendli@mpb.li, 2012 + + This module adds remote-control capability to some of the dabmod modules. + see testremotecontrol/test.cpp for an example of how to use this. */ /* This file is part of CRC-DADMOD. -- cgit v1.2.3