From 855311975814891f531577f90115bfb5fa6ed252 Mon Sep 17 00:00:00 2001 From: Jörgen Scott Date: Fri, 15 Aug 2014 15:13:39 +0200 Subject: Fixed commented zmq example --- doc/example.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/example.ini b/doc/example.ini index 9cdfe03..1c25529 100644 --- a/doc/example.ini +++ b/doc/example.ini @@ -25,7 +25,7 @@ loop=0 ; When recieving data using ZeroMQ, the source is the URI to be used ;transport=zeromq -;source=tcp://localhost:8080 +;source=zmq+tcp://localhost:8080 [modulator] ; Gain mode: 0=FIX, 1=MAX, 2=VAR -- cgit v1.2.3 From f4e359f774eef5ec2a006a431a546e915b27f02b Mon Sep 17 00:00:00 2001 From: Jörgen Scott Date: Tue, 16 Dec 2014 09:23:31 +0100 Subject: Added static delay via telnet control --- config.h.in | 189 +++++++++++++++++++++++++++++++++ doc/.example.ini.un~ | Bin 0 -> 13605 bytes doc/example.ini | 13 +-- doc/fir-filter/.README.un~ | Bin 0 -> 519 bytes doc/fir-filter/.generate-filter.py.un~ | Bin 0 -> 3536 bytes src/.DabMod.cpp.un~ | Bin 0 -> 30089 bytes src/.OutputUHD.cpp.un~ | Bin 0 -> 67312 bytes src/.OutputUHD.h.un~ | Bin 0 -> 13690 bytes src/.TimestampDecoder.cpp.un~ | Bin 0 -> 4958 bytes src/DabMod.cpp | 3 + src/OutputUHD.cpp | 56 +++++++++- src/OutputUHD.h | 5 +- 12 files changed, 255 insertions(+), 11 deletions(-) create mode 100644 config.h.in create mode 100644 doc/.example.ini.un~ create mode 100644 doc/fir-filter/.README.un~ create mode 100755 doc/fir-filter/.generate-filter.py.un~ create mode 100644 src/.DabMod.cpp.un~ create mode 100644 src/.OutputUHD.cpp.un~ create mode 100644 src/.OutputUHD.h.un~ create mode 100644 src/.TimestampDecoder.cpp.un~ diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..cd9076d --- /dev/null +++ b/config.h.in @@ -0,0 +1,189 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* define if the Boost library is available */ +#undef HAVE_BOOST + +/* Define to 1 if you have the `bzero' function. */ +#undef HAVE_BZERO + +/* Define to 1 if you have the declaration of `_mm_malloc', and to 0 if you + don't. */ +#undef HAVE_DECL__MM_MALLOC + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `floor' function. */ +#undef HAVE_FLOOR + +/* Define to 1 if you have the `ftime' function. */ +#undef HAVE_FTIME + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define if ZeroMQ input is enabled */ +#undef HAVE_INPUT_ZEROMQ + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `boost_system' library (-lboost_system). */ +#undef HAVE_LIBBOOST_SYSTEM + +/* Define to 1 if you have the `boost_thread' library (-lboost_thread). */ +#undef HAVE_LIBBOOST_THREAD + +/* Define to 1 if you have the `duma' library (-lduma). */ +#undef HAVE_LIBDUMA + +/* Define to 1 if you have the `efence' library (-lefence). */ +#undef HAVE_LIBEFENCE + +/* Define to 1 if you have the `rt' library (-lrt). */ +#undef HAVE_LIBRT + +/* Define to 1 if you have the `uhd' library (-luhd). */ +#undef HAVE_LIBUHD + +/* Define to 1 if you have the `zmq' library (-lzmq). */ +#undef HAVE_LIBZMQ + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define if UHD output is enabled */ +#undef HAVE_OUTPUT_UHD + +/* Define to 1 if you have the `sqrt' function. */ +#undef HAVE_SQRT + +/* Define to 1 if stdbool.h conforms to C99. */ +#undef HAVE_STDBOOL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIMEB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if the system has the type `_Bool'. */ +#undef HAVE__BOOL + +/* Replacing define */ +#undef M_PIl + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Version number of package */ +#undef VERSION + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT32_T + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT8_T + +/* __16BIT__, __64BIT__ */ +#undef __32BIT__ + +/* __16BIT__, __32BIT__ */ +#undef __64BIT__ + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to `unsigned int' if does not define. */ +#undef size_t + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +#undef uint16_t + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef uint32_t + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +#undef uint8_t diff --git a/doc/.example.ini.un~ b/doc/.example.ini.un~ new file mode 100644 index 0000000..d500812 Binary files /dev/null and b/doc/.example.ini.un~ differ diff --git a/doc/example.ini b/doc/example.ini index 1c25529..49f6eda 100644 --- a/doc/example.ini +++ b/doc/example.ini @@ -25,7 +25,7 @@ loop=0 ; When recieving data using ZeroMQ, the source is the URI to be used ;transport=zeromq -;source=zmq+tcp://localhost:8080 +;source=tcp://localhost:8080 [modulator] ; Gain mode: 0=FIX, 1=MAX, 2=VAR @@ -59,7 +59,7 @@ gainmode=2 ; and wide-band noise will be generated. ; ; Be aware that there is a dependency with resampling. -digital_gain=1.0 +digital_gain=0.8 ; Output sample rate. Values other than 2048000 enable ; resampling. @@ -106,8 +106,8 @@ filename=/dev/stdout ; or even a higher factor. ; ; Settings for a USRP B100: -device=master_clock_rate=32768000,type=b100 -txgain=2 +;device=master_clock_rate=32768000,type=b100 +;txgain=2 ; Try first with small gain values ; Also set rate to 2048000 @@ -116,8 +116,9 @@ txgain=2 ; http://opendigitalradio.org/index.php/USRP_B200_Measurements ; ; Settings: +device=master_clock_rate=2048000,type=b200 ;device=master_clock_rate=20480000,type=b200 -;txgain=40 +txgain=40 ; The B200 needs larger gains (up to 89dB) but, ; "Gain settings are application specific, but it is recommended that users ; consider using at least half of the available gain to get reasonable dynamic @@ -140,7 +141,7 @@ channel=13C ; The reference clock to use. ; possible values : internal, external, MIMO -refclk_source=internal +refclk_source=external ; The reference one pulse-per second to use ; possible values : none, external, MIMO diff --git a/doc/fir-filter/.README.un~ b/doc/fir-filter/.README.un~ new file mode 100644 index 0000000..b4a2d9d Binary files /dev/null and b/doc/fir-filter/.README.un~ differ diff --git a/doc/fir-filter/.generate-filter.py.un~ b/doc/fir-filter/.generate-filter.py.un~ new file mode 100755 index 0000000..573ffae Binary files /dev/null and b/doc/fir-filter/.generate-filter.py.un~ differ diff --git a/src/.DabMod.cpp.un~ b/src/.DabMod.cpp.un~ new file mode 100644 index 0000000..ebbb822 Binary files /dev/null and b/src/.DabMod.cpp.un~ differ diff --git a/src/.OutputUHD.cpp.un~ b/src/.OutputUHD.cpp.un~ new file mode 100644 index 0000000..96f080d Binary files /dev/null and b/src/.OutputUHD.cpp.un~ differ diff --git a/src/.OutputUHD.h.un~ b/src/.OutputUHD.h.un~ new file mode 100644 index 0000000..5f3e54a Binary files /dev/null and b/src/.OutputUHD.h.un~ differ diff --git a/src/.TimestampDecoder.cpp.un~ b/src/.TimestampDecoder.cpp.un~ new file mode 100644 index 0000000..01d7cc7 Binary files /dev/null and b/src/.TimestampDecoder.cpp.un~ differ diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 14c7c4b..ee21ed4 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -363,6 +363,9 @@ int main(int argc, char* argv[]) } } + //std::string zmqCtrlEndpoint = pt.get("remotecontrol.zmqctrlendpoint", ""); + //std::cout << "ZmqCtrlEndpoint: " << zmqCtrlEndpoint << std::endl; + // input params: if (pt.get("input.loop", 0) == 1) { loop = true; diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index b44cd3f..8713042 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -53,10 +53,12 @@ OutputUHD::OutputUHD( // Since we don't know the buffer size, we cannot initialise // the buffers at object initialisation. first_run(true), - activebuffer(1) + activebuffer(1), + m_delayBuf(196608) { myMuting = 0; // is remote-controllable + myStaticDelay = 0; // is remote-controllable std::stringstream device; device << myConf.device; @@ -81,7 +83,9 @@ OutputUHD::OutputUHD( /* register the parameters that can be remote controlled */ RC_ADD_PARAMETER(txgain, "UHD analog daughterboard TX gain"); RC_ADD_PARAMETER(freq, "UHD transmission frequency"); - RC_ADD_PARAMETER(muting, "mute the output by stopping the transmitter"); + 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(iqbalance, "Set I/Q balance between 0 and 1.0"); uhd::set_thread_priority_safe(); @@ -229,6 +233,10 @@ OutputUHD::~OutputUHD() { MDEBUG("OutputUHD::~OutputUHD() @ %p\n", this); worker.stop(); + if (!first_run) { + free(uwd.frame0.buf); + free(uwd.frame1.buf); + } } int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) @@ -283,14 +291,35 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) uwd.sourceContainsTimestamp = myConf.enableSync && myEtiReader->sourceContainsTimestamp(); + // calculate delay + uint32_t noSampleDelay = (myStaticDelay * 2048) / 1000; + uint32_t noByteDelay = noSampleDelay * sizeof(complexf); + + uint8_t* pInData = (uint8_t*) dataIn->getData(); if (activebuffer == 0) { - memcpy(uwd.frame0.buf, dataIn->getData(), uwd.bufsize); + uint8_t *pTmp = (uint8_t*) uwd.frame0.buf; + // copy remain from delaybuf + memcpy(pTmp, &m_delayBuf[0], noByteDelay); + // copy new data + memcpy(&pTmp[noByteDelay], pInData, uwd.bufsize - noByteDelay); + // copy remaining data to delay buf + memcpy(&m_delayBuf[0], &pInData[uwd.bufsize - noByteDelay], noByteDelay); + + //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); + uint8_t *pTmp = (uint8_t*) uwd.frame1.buf; + // copy remain from delaybuf + memcpy(pTmp, &m_delayBuf[0], noByteDelay); + // copy new data + memcpy(&pTmp[noByteDelay], pInData, uwd.bufsize - noByteDelay); + // copy remaining data to delay buf + memcpy(&m_delayBuf[0], &pInData[uwd.bufsize - noByteDelay], noByteDelay); + + //memcpy(uwd.frame1.buf, dataIn->getData(), uwd.bufsize); uwd.frame1.ts = ts; uwd.frame1.fct = myEtiReader->getFCT(); @@ -591,6 +620,22 @@ void OutputUHD::set_parameter(const string& parameter, const string& value) else if (parameter == "muting") { ss >> myMuting; } + else if (parameter == "staticdelay") { + int adjust; + ss >> adjust; + int newStaticDelay = myStaticDelay + adjust; + if (newStaticDelay > 96000) + myStaticDelay = newStaticDelay - 96000; + else if (newStaticDelay < 0) + myStaticDelay = newStaticDelay + 96000; + else + myStaticDelay = newStaticDelay; + } + else if (parameter == "iqbalance") { + ss >> myConf.frequency; + myUsrp->set_tx_freq(myConf.frequency); + myConf.frequency = myUsrp->get_tx_freq(); + } else { stringstream ss; ss << "Parameter '" << parameter @@ -611,6 +656,9 @@ const string OutputUHD::get_parameter(const string& parameter) const else if (parameter == "muting") { ss << myMuting; } + else if (parameter == "staticdelay") { + ss << myStaticDelay; + } else { ss << "Parameter '" << parameter << "' is not exported by controllable " << get_rc_name(); diff --git a/src/OutputUHD.h b/src/OutputUHD.h index 69e5b20..f50807d 100644 --- a/src/OutputUHD.h +++ b/src/OutputUHD.h @@ -48,6 +48,7 @@ DESCRIPTION: #include #include #include +#include #include "Log.h" #include "ModOutput.h" @@ -220,7 +221,9 @@ class OutputUHD: public ModOutput, public RemoteControllable { // muting can only be changed using the remote control bool myMuting; - + int myStaticDelay; + std::vector m_delayBuf; + size_t lastLen; }; -- cgit v1.2.3 From 7e3e3f290e9fbbd314919474ed7bc61c3ce43041 Mon Sep 17 00:00:00 2001 From: Jörgen Scott Date: Tue, 16 Dec 2014 14:49:57 +0100 Subject: added zmq controller to uhd --- src/.DabMod.cpp.un~ | Bin 30089 -> 0 bytes src/.OutputUHD.cpp.un~ | Bin 67312 -> 0 bytes src/.OutputUHD.h.un~ | Bin 13690 -> 0 bytes src/DabMod.cpp | 10 +++-- src/OutputUHD.cpp | 113 ++++++++++++++++++++++++++++++++++++++++++++++++- src/OutputUHD.h | 20 ++++++++- 6 files changed, 137 insertions(+), 6 deletions(-) delete mode 100644 src/.DabMod.cpp.un~ delete mode 100644 src/.OutputUHD.cpp.un~ delete mode 100644 src/.OutputUHD.h.un~ diff --git a/src/.DabMod.cpp.un~ b/src/.DabMod.cpp.un~ deleted file mode 100644 index ebbb822..0000000 Binary files a/src/.DabMod.cpp.un~ and /dev/null differ diff --git a/src/.OutputUHD.cpp.un~ b/src/.OutputUHD.cpp.un~ deleted file mode 100644 index 96f080d..0000000 Binary files a/src/.OutputUHD.cpp.un~ and /dev/null differ diff --git a/src/.OutputUHD.h.un~ b/src/.OutputUHD.h.un~ deleted file mode 100644 index 5f3e54a..0000000 Binary files a/src/.OutputUHD.h.un~ and /dev/null differ diff --git a/src/DabMod.cpp b/src/DabMod.cpp index ee21ed4..4342522 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #ifdef HAVE_NETINET_IN_H # include @@ -189,6 +190,9 @@ int main(int argc, char* argv[]) OutputUHDConfig outputuhd_conf; #endif + zmq::context_t zmqCtrlContext(1); + std::string zmqCtrlEndpoint = ""; + // To handle the timestamp offset of the modulator struct modulator_offset_config modconf; modconf.use_offset_file = false; @@ -363,8 +367,8 @@ int main(int argc, char* argv[]) } } - //std::string zmqCtrlEndpoint = pt.get("remotecontrol.zmqctrlendpoint", ""); - //std::cout << "ZmqCtrlEndpoint: " << zmqCtrlEndpoint << std::endl; + zmqCtrlEndpoint = pt.get("remotecontrol.zmqctrlendpoint", ""); + std::cout << "ZmqCtrlEndpoint: " << zmqCtrlEndpoint << std::endl; // input params: if (pt.get("input.loop", 0) == 1) { @@ -701,7 +705,7 @@ int main(int argc, char* argv[]) outputuhd_conf.sampleRate = outputRate; try { - output = new OutputUHD(outputuhd_conf, logger); + output = new OutputUHD(outputuhd_conf, logger, &zmqCtrlContext, zmqCtrlEndpoint); ((OutputUHD*)output)->enrol_at(*rc); } catch (std::exception& e) { diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index 8713042..6a4ccf4 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -45,7 +45,9 @@ typedef std::complex complexf; OutputUHD::OutputUHD( OutputUHDConfig& config, - Logger& logger) : + Logger& logger, + zmq::context_t *pContext, + const std::string &zmqCtrlEndpoint) : ModOutput(ModFormat(1), ModFormat(0)), RemoteControllable("uhd"), myLogger(logger), @@ -225,6 +227,14 @@ OutputUHD::OutputUHD( worker.start(&uwd); + m_pZmqRepThread = NULL; + if (!zmqCtrlEndpoint.empty()) + { + m_pContext = pContext; + m_zmqCtrlEndpoint = zmqCtrlEndpoint; + m_pZmqRepThread = new boost::thread(boost::bind(&OutputUHD::ZmqCtrl, this)); + } + MDEBUG("OutputUHD:UHD ready.\n"); } @@ -232,6 +242,12 @@ OutputUHD::OutputUHD( OutputUHD::~OutputUHD() { MDEBUG("OutputUHD::~OutputUHD() @ %p\n", this); + if (m_pZmqRepThread != NULL) + { + m_pZmqRepThread->interrupt(); + m_pZmqRepThread->join(); + } + worker.stop(); if (!first_run) { free(uwd.frame0.buf); @@ -667,3 +683,98 @@ const string OutputUHD::get_parameter(const string& parameter) const return ss.str(); } +void OutputUHD::RecvAll(zmq::socket_t* pSocket, std::vector &message) +{ + int more = -1; + size_t more_size = sizeof(more); + + while (more != 0) + { + zmq::message_t msg; + pSocket->recv(&msg); + message.push_back(std::string((char*)msg.data(), msg.size())); + pSocket->getsockopt(ZMQ_RCVMORE, &more, &more_size); + } +} + +void OutputUHD::SendOkReply(zmq::socket_t *pSocket) +{ + zmq::message_t msg(2); + char repCode[2] = {'o', 'k'}; + memcpy ((void*) msg.data(), repCode, 2); + pSocket->send(msg, 0); +} + +void OutputUHD::SendFailReply(zmq::socket_t *pSocket, const std::string &error) +{ + zmq::message_t msg1(4); + char repCode[4] = {'f', 'a', 'i', 'l'}; + memcpy ((void*) msg1.data(), repCode, 4); + pSocket->send(msg1, ZMQ_SNDMORE); + + zmq::message_t msg2(error.length()); + memcpy ((void*) msg2.data(), error.c_str(), error.length()); + pSocket->send(msg2, 0); +} + +//TODO: Should be implemented as an alternative to RemoteControllerTelnet and +//moved to the RemoteControl.h/cpp file instead. +void OutputUHD::ZmqCtrl() +{ + // create zmq reply socket for receiving ctrl parameters + zmq::socket_t repSocket(*m_pContext, ZMQ_REP); + std::cout << "Starting output UHD control thread" << std::endl; + try + { + // connect the socket + int hwm = 5; + int linger = 0; + repSocket.setsockopt(ZMQ_RCVHWM, &hwm, sizeof(hwm)); + repSocket.setsockopt(ZMQ_SNDHWM, &hwm, sizeof(hwm)); + repSocket.setsockopt(ZMQ_LINGER, &linger, sizeof(linger)); + repSocket.connect(m_zmqCtrlEndpoint.c_str()); + + // create pollitem that polls the ZMQ sockets + zmq::pollitem_t pollItems[] = { {repSocket, 0, ZMQ_POLLIN, 0} }; + for(;;) + { + zmq::poll(pollItems, 1, 100); + std::vector msg; + if (pollItems[0].revents & ZMQ_POLLIN) + { + RecvAll(&repSocket, msg); + std::string module((char*)msg[0].data(), msg[0].size()); + if (module == "uhd") + { + if (msg.size() != 3) + { + SendFailReply(&repSocket, "Wrong request format"); + continue; + } + + std::string param((char*) msg[1].data(), msg[1].size()); + std::string value((char*) msg[2].data(), msg[2].size()); + try + { + set_parameter(param, value); + } + catch (ParameterError &err) + { + SendFailReply(&repSocket, err.what()); + continue; + } + SendOkReply(&repSocket); + } + } + + // check if thread is interrupted + boost::this_thread::interruption_point(); + } + } + catch (boost::thread_interrupted&) {} + catch (zmq::error_t &e) + { + std::cerr << "ZMQ error: " << std::string(e.what()) << std::endl; + } + repSocket.close(); +} diff --git a/src/OutputUHD.h b/src/OutputUHD.h index f50807d..25f7476 100644 --- a/src/OutputUHD.h +++ b/src/OutputUHD.h @@ -181,9 +181,12 @@ struct OutputUHDConfig { class OutputUHD: public ModOutput, public RemoteControllable { public: + OutputUHD( OutputUHDConfig& config, - Logger& logger); + Logger& logger, + zmq::context_t *pContext, + const std::string &zmqCtrlEndpoint); ~OutputUHD(); int process(Buffer* dataIn, Buffer* dataOut); @@ -221,9 +224,22 @@ class OutputUHD: public ModOutput, public RemoteControllable { // muting can only be changed using the remote control bool myMuting; + + private: + // zmq receiving method + //TODO: Should be implemented as an alternative to RemoteControllerTelnet and + //moved to the RemoteControl.h/cpp file instead. + void ZmqCtrl(void); + void RecvAll(zmq::socket_t* pSocket, std::vector &message); + void SendOkReply(zmq::socket_t *pSocket); + void SendFailReply(zmq::socket_t *pSocket, const std::string &error); + + // data int myStaticDelay; std::vector m_delayBuf; - + zmq::context_t *m_pContext; + std::string m_zmqCtrlEndpoint; + boost::thread *m_pZmqRepThread; size_t lastLen; }; -- cgit v1.2.3 From 593c130b1e6848a08b30a84732ebd6862ef2e3b7 Mon Sep 17 00:00:00 2001 From: Jörgen Scott Date: Mon, 22 Dec 2014 08:32:15 +0100 Subject: changed zmq api --- src/OutputUHD.cpp | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index 6a4ccf4..e3d2d77 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -727,12 +727,12 @@ void OutputUHD::ZmqCtrl() try { // connect the socket - int hwm = 5; + int hwm = 100; int linger = 0; repSocket.setsockopt(ZMQ_RCVHWM, &hwm, sizeof(hwm)); repSocket.setsockopt(ZMQ_SNDHWM, &hwm, sizeof(hwm)); repSocket.setsockopt(ZMQ_LINGER, &linger, sizeof(linger)); - repSocket.connect(m_zmqCtrlEndpoint.c_str()); + repSocket.bind(m_zmqCtrlEndpoint.c_str()); // create pollitem that polls the ZMQ sockets zmq::pollitem_t pollItems[] = { {repSocket, 0, ZMQ_POLLIN, 0} }; @@ -746,24 +746,34 @@ void OutputUHD::ZmqCtrl() std::string module((char*)msg[0].data(), msg[0].size()); if (module == "uhd") { - if (msg.size() != 3) + if (msg.size() < 2) { SendFailReply(&repSocket, "Wrong request format"); continue; } - + std::string param((char*) msg[1].data(), msg[1].size()); - std::string value((char*) msg[2].data(), msg[2].size()); - try + if (msg.size() == 2 && param == "ping") { - set_parameter(param, value); + SendOkReply(&repSocket); } - catch (ParameterError &err) + else if (msg.size() != 3) { - SendFailReply(&repSocket, err.what()); - continue; + SendFailReply(&repSocket, "Wrong request format"); + } + else + { + std::string value((char*) msg[2].data(), msg[2].size()); + try + { + set_parameter(param, value); + SendOkReply(&repSocket); + } + catch (ParameterError &err) + { + SendFailReply(&repSocket, err.what()); + } } - SendOkReply(&repSocket); } } -- cgit v1.2.3 From 9ffaa58ba47f5211cce25483e7408dbaf9a6cbfc Mon Sep 17 00:00:00 2001 From: Kenneth Mortensen Date: Thu, 13 Nov 2014 10:44:33 +0100 Subject: No error termination in case of zero read bytes --- src/InputFileReader.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/InputFileReader.cpp b/src/InputFileReader.cpp index 52fbb99..4a7e050 100644 --- a/src/InputFileReader.cpp +++ b/src/InputFileReader.cpp @@ -284,13 +284,18 @@ int InputFileReader::GetNextFrame(void* buffer) if (read_bytes != frameSize) { // A short read of a frame (i.e. reading an incomplete frame) // is not tolerated. Input files must not contain incomplete frames - fprintf(stderr, - "Unable to read a complete frame of %u data bytes from input file!\n", - frameSize); - - perror(filename_.c_str()); - logger_.level(error) << "Unable to read from input file!"; - return -1; + if (read_bytes != 0){ + fprintf(stderr, + "Unable to read a complete frame of %u data bytes from input file!\n", + frameSize); + + perror(filename_.c_str()); + logger_.level(error) << "Unable to read from input file!"; + return -1; + } + else { + return 0; + } } memset(&((uint8_t*)buffer)[frameSize], 0x55, 6144 - frameSize); -- cgit v1.2.3 From aa63facf2c4140acef2ba6e7f1b8012eec5536bf Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 22 Dec 2014 18:20:32 +0100 Subject: Reindent InputFileReader::GetNextFrame() --- src/InputFileReader.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/InputFileReader.cpp b/src/InputFileReader.cpp index 4a7e050..205fbfa 100644 --- a/src/InputFileReader.cpp +++ b/src/InputFileReader.cpp @@ -284,17 +284,17 @@ int InputFileReader::GetNextFrame(void* buffer) if (read_bytes != frameSize) { // A short read of a frame (i.e. reading an incomplete frame) // is not tolerated. Input files must not contain incomplete frames - if (read_bytes != 0){ - fprintf(stderr, - "Unable to read a complete frame of %u data bytes from input file!\n", - frameSize); - - perror(filename_.c_str()); - logger_.level(error) << "Unable to read from input file!"; - return -1; + if (read_bytes != 0) { + fprintf(stderr, + "Unable to read a complete frame of %u data bytes from input file!\n", + frameSize); + + perror(filename_.c_str()); + logger_.level(error) << "Unable to read from input file!"; + return -1; } else { - return 0; + return 0; } } -- cgit v1.2.3 From 78c4a0b9af981dc66cb42d46dfd60fe87679d178 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Thu, 25 Dec 2014 14:57:56 +0100 Subject: Add file output format converter --- src/DabMod.cpp | 50 ++++++++++++++++++-------- src/FormatConverter.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ src/FormatConverter.h | 53 +++++++++++++++++++++++++++ src/Makefile.am | 1 + 4 files changed, 186 insertions(+), 14 deletions(-) create mode 100644 src/FormatConverter.cpp create mode 100644 src/FormatConverter.h diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 91c0b9d..dc61ae2 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -35,6 +35,7 @@ #include "DabModulator.h" #include "InputMemory.h" #include "OutputFile.h" +#include "FormatConverter.h" #if defined(HAVE_OUTPUT_UHD) # include "OutputUHD.h" #endif @@ -176,6 +177,7 @@ int main(int argc, char* argv[]) std::string outputName; int useZeroMQOutput = 0; int useFileOutput = 0; + std::string fileOutputFormat = "complexf"; int useUHDOutput = 0; uint64_t frame = 0; @@ -187,6 +189,17 @@ int main(int argc, char* argv[]) GainMode gainMode = GAIN_VAR; Buffer data; + + /* UHD requires the input I and Q samples to be in the interval + * [-1.0,1.0], otherwise they get truncated, which creates very + * wide-spectrum spikes. Depending on the Transmission Mode, the + * Gain Mode and the sample rate (and maybe other parameters), the + * samples can have peaks up to about 48000. The value of 50000 + * should guarantee that with a digital gain of 1.0, UHD never clips + * our samples. + */ + const float normalise_factor = 50000.0f; + std::string filterTapsFilename = ""; // Two configuration sources exist: command line and (new) INI file @@ -207,6 +220,7 @@ int main(int argc, char* argv[]) Flowgraph* flowgraph = NULL; DabModulator* modulator = NULL; InputMemory* input = NULL; + FormatConverter* format_converter = NULL; ModOutput* output = NULL; BaseRemoteController* rc = NULL; @@ -478,6 +492,8 @@ int main(int argc, char* argv[]) goto END_MAIN; } useFileOutput = 1; + + fileOutputFormat = pt.get("fileoutput.format", fileOutputFormat); } #if defined(HAVE_OUTPUT_UHD) else if (output_selected == "uhd") { @@ -741,23 +757,23 @@ int main(int argc, char* argv[]) goto END_MAIN; } - if (useFileOutput) { - // Opening COFDM output file - output = new OutputFile(outputName); + if (fileOutputFormat == "complexf") { + output = new OutputFile(outputName); + } + else if (fileOutputFormat == "s8") { + // We must normalise the samples to the interval [-127.0; 127.0] + normalise = 127.0f / normalise_factor; + + format_converter = new FormatConverter(); + + output = new OutputFile(outputName); + } } #if defined(HAVE_OUTPUT_UHD) else if (useUHDOutput) { - /* UHD requires the input I and Q samples to be in the interval - * [-1.0,1.0], otherwise they get truncated, which creates very - * wide-spectrum spikes. Depending on the Transmission Mode, the - * Gain Mode and the sample rate (and maybe other parameters), the - * samples can have peaks up to about 48000. The value of 50000 - * should guarantee that with a digital gain of 1.0, UHD never clips - * our samples. - */ - normalise = 1.0f/50000.0f; + normalise = 1.0f / normalise_factor; outputuhd_conf.sampleRate = outputRate; try { @@ -773,7 +789,7 @@ int main(int argc, char* argv[]) #if defined(HAVE_OUTPUT_ZEROMQ) else if (useZeroMQOutput) { /* We normalise the same way as for the UHD output */ - normalise = 1.0f/50000.0f; + normalise = 1.0f / normalise_factor; output = new OutputZeroMQ(outputName); } @@ -785,7 +801,13 @@ int main(int argc, char* argv[]) modulator = new DabModulator(modconf, rc, logger, outputRate, clockRate, dabMode, gainMode, digitalgain, normalise, filterTapsFilename); flowgraph->connect(input, modulator); - flowgraph->connect(modulator, output); + if (format_converter) { + flowgraph->connect(modulator, format_converter); + flowgraph->connect(format_converter, output); + } + else { + flowgraph->connect(modulator, output); + } #if defined(HAVE_OUTPUT_UHD) if (useUHDOutput) { diff --git a/src/FormatConverter.cpp b/src/FormatConverter.cpp new file mode 100644 index 0000000..4f7d95c --- /dev/null +++ b/src/FormatConverter.cpp @@ -0,0 +1,96 @@ +/* + Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty + the Queen in Right of Canada (Communications Research Center Canada) + + Copyright (C) 2014 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org + + This flowgraph block converts complexf to signed integer. + */ +/* + This file is part of ODR-DabMod. + + ODR-DabMod is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + ODR-DabMod is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ODR-DabMod. If not, see . + */ + +#include "FormatConverter.h" +#include "PcDebug.h" + +#include +#include +#include +#include +#include + + +FormatConverter::FormatConverter(void) : + ModCodec(ModFormat(sizeof(complexf)), + ModFormat(sizeof(int8_t))) { } + +/* Expect the input samples to be in the range [-255.0, 255.0] */ +int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) +{ + PDEBUG("FormatConverter::process(dataIn: %p, dataOut: %p)\n", + dataIn, dataOut); + + size_t sizeIn = dataIn->getLength() / sizeof(float); + dataOut->setLength(sizeIn * sizeof(int8_t)); + + float* in = reinterpret_cast(dataIn->getData()); + int8_t* out = reinterpret_cast(dataOut->getData()); + +#if 0 + // WARNING: Untested Code Ahead + assert(sizeIn % 16 == 0); + assert((uintptr_t)in % 16 == 0); + for(int i = 0; i < sizeIn; i+=16) + { + __m128 a1 = _mm_load_ps(in+i+0); + __m128 a2 = _mm_load_ps(in+i+4); + __m128 a3 = _mm_load_ps(in+i+8); + __m128 a4 = _mm_load_ps(in+i+12); + __m64 b1 = _mm_cvtps_pi8(a1); + __m64 b2 = _mm_cvtps_pi8(a2); + __m64 b3 = _mm_cvtps_pi8(a3); + __m64 b4 = _mm_cvtps_pi8(a4); + _mm_store_ps(out+i+0, b1); + _mm_store_ps(out+i+4, b2); + _mm_store_ps(out+i+8, b3); + _mm_store_ps(out+i+12, b4); + } +#else + // Slow implementation that uses _ftol() + for (size_t i = 0; i < sizeIn; i++) { + if (in[i] > 127.0f) { + out[i] = 127; + } + else if (in[i] < -127.0f) { + out[i] = -127; + } + else { + out[i] = in[i]; + } + } +#endif + + return 1; +} + +const char* FormatConverter::name() +{ + return "FormatConverter"; +} + diff --git a/src/FormatConverter.h b/src/FormatConverter.h new file mode 100644 index 0000000..0243685 --- /dev/null +++ b/src/FormatConverter.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty + the Queen in Right of Canada (Communications Research Center Canada) + + Copyright (C) 2014 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org + + This flowgraph block converts complexf to signed integer. + */ +/* + This file is part of ODR-DabMod. + + ODR-DabMod is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + ODR-DabMod is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ODR-DabMod. If not, see . + */ + +#ifndef FORMAT_CONVERTER_H +#define FORMAT_CONVERTER_H + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "porting.h" +#include "ModCodec.h" +#include +#include + +typedef std::complex complexf; + +class FormatConverter : public ModCodec +{ + public: + FormatConverter(void); + + int process(Buffer* const dataIn, Buffer* dataOut); + const char* name(); +}; + +#endif // FORMAT_CONVERTER_H + diff --git a/src/Makefile.am b/src/Makefile.am index 922ce52..f8ba7c2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -110,6 +110,7 @@ odr_dabmod_SOURCES = DabMod.cpp \ ThreadsafeQueue.h \ Log.cpp Log.h \ RemoteControl.cpp RemoteControl.h \ + FormatConverter.cpp FormatConverter.h \ zmq.hpp nodist_odr_dabmod_SOURCES = $(FFT_SRC) -- cgit v1.2.3 From 289ca8255ec7341530327a4b118372276cc3147e Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Thu, 25 Dec 2014 15:56:46 +0100 Subject: FormatConverter: correct SSE code --- src/FormatConverter.cpp | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/FormatConverter.cpp b/src/FormatConverter.cpp index 4f7d95c..8b510bd 100644 --- a/src/FormatConverter.cpp +++ b/src/FormatConverter.cpp @@ -35,6 +35,9 @@ #include #include +#ifdef __SSE__ +# include +#endif FormatConverter::FormatConverter(void) : ModCodec(ModFormat(sizeof(complexf)), @@ -50,13 +53,20 @@ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) dataOut->setLength(sizeIn * sizeof(int8_t)); float* in = reinterpret_cast(dataIn->getData()); - int8_t* out = reinterpret_cast(dataOut->getData()); -#if 0 - // WARNING: Untested Code Ahead +#ifdef __SSE__ + /* + _mm_cvtps_pi8 does: + |<----------- 128 bits ------------>| + __m128 | I1 | Q1 | I2 | Q2 | in float + __m64 |I1Q1I2Q2|00000000| in int8_t + */ + + uint32_t* out = reinterpret_cast(dataOut->getData()); + assert(sizeIn % 16 == 0); assert((uintptr_t)in % 16 == 0); - for(int i = 0; i < sizeIn; i+=16) + for(size_t i = 0, j = 0; i < sizeIn; i+=16, j+=4) { __m128 a1 = _mm_load_ps(in+i+0); __m128 a2 = _mm_load_ps(in+i+4); @@ -66,23 +76,17 @@ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) __m64 b2 = _mm_cvtps_pi8(a2); __m64 b3 = _mm_cvtps_pi8(a3); __m64 b4 = _mm_cvtps_pi8(a4); - _mm_store_ps(out+i+0, b1); - _mm_store_ps(out+i+4, b2); - _mm_store_ps(out+i+8, b3); - _mm_store_ps(out+i+12, b4); + out[j+0] = b1[0]; + out[j+1] = b2[0]; + out[j+2] = b3[0]; + out[j+3] = b4[0]; } #else + int8_t* out = reinterpret_cast(dataOut->getData()); + // Slow implementation that uses _ftol() for (size_t i = 0; i < sizeIn; i++) { - if (in[i] > 127.0f) { - out[i] = 127; - } - else if (in[i] < -127.0f) { - out[i] = -127; - } - else { - out[i] = in[i]; - } + out[i] = in[i]; } #endif -- cgit v1.2.3 From b9b0b1ff957d72407cd2b6a28a18c34a3038b159 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Thu, 25 Dec 2014 16:17:29 +0100 Subject: Update example.ini with s8 format --- doc/example.ini | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/doc/example.ini b/doc/example.ini index e1ce252..ada7a03 100644 --- a/doc/example.ini +++ b/doc/example.ini @@ -90,11 +90,22 @@ filtertapsfile=simple_taps.txt output=uhd [fileoutput] -; The file output writes I/Q float values (i.e. complex float) +; Two output formats are supported: In the default mode, +; the file output writes I/Q float values (i.e. complex float) ; to the file. The I and Q samples can take values up to ; 100000 in absolute magnitude with gainmode FIX. ; With gainmode VAR, they should never exceed 50000. ; With gainmode MAX, thet are limited to 32767. +;format=complexf +; +; When the format is set to s8, the output writes I/Q 8-bit +; signed integers, where the magnitude is multiplied by 128/50000 +; effectively mapping the gainmode VAR range of -50000 -- 50000 +; to -128 -- 128. For other gainmodes, use the digital_gain setting +; to make sure you don't create clipping. +;format=s8 + +; The output file: filename=/dev/stdout [uhdoutput] -- cgit v1.2.3 From 782bb1624b3ac9d340cb12f2ca52b549c64c23e5 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Thu, 25 Dec 2014 19:09:56 +0100 Subject: FormatConverter: disable SSE --- src/FormatConverter.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/FormatConverter.cpp b/src/FormatConverter.cpp index 8b510bd..766b6d8 100644 --- a/src/FormatConverter.cpp +++ b/src/FormatConverter.cpp @@ -54,7 +54,10 @@ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) float* in = reinterpret_cast(dataIn->getData()); -#ifdef __SSE__ +#if 0 + // Disabled because subscripting a __m64 doesn't seem to work + // on all platforms. + /* _mm_cvtps_pi8 does: |<----------- 128 bits ------------>| -- cgit v1.2.3 From ba790cba2f7b48dd66f4418de0b7b366422926b0 Mon Sep 17 00:00:00 2001 From: Jörgen Scott Date: Tue, 13 Jan 2015 11:27:39 +0100 Subject: added zmq remote control --- doc/example.ini | 22 ++++++++ src/DabMod.cpp | 45 ++++++++++------ src/DabModulator.cpp | 8 +-- src/DabModulator.h | 4 +- src/OutputUHD.cpp | 137 +++--------------------------------------------- src/OutputUHD.h | 18 +------ src/RemoteControl.cpp | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/RemoteControl.h | 131 +++++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 336 insertions(+), 171 deletions(-) diff --git a/doc/example.ini b/doc/example.ini index 49f6eda..9a80eeb 100644 --- a/doc/example.ini +++ b/doc/example.ini @@ -8,6 +8,28 @@ telnet=1 telnetport=2121 +; Enable zmq remote control. +; The zmq remote control is intended for machine-to-machine +; integration and requires that the odr-mod is build with zmq support. +; The zmq remote control may run in parallell with Telnet. +; Protocol: +; The odr-dabmod binds a zmq rep socket so clients must connect +; using either req or dealer socket. +; [] denotes message part as zmq multi-part message are used for delimitation. +; All message parts are utf-8 encoded strings and matches the Telnet command set. +; Explicit codes are denoted with "". +; The following commands are supported: +; REQ: ["ping"] +; REP: ["ok"] +; +; REQ: ["get"][module name][parameter] +; REP: [value] _OR_ ["fail"][error description] +; +; REQ: ["set"][module name][parameter][value] +; REP: ["ok"] _OR_ ["fail"][error description] +zmqctrl=1 +zmqctrlendpoint=tcp://127.0.0.1:9400 + [log] ; Write to a logfile or to syslog. ; Setting filename to stderr is very useful during tests and development diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 4342522..dadade9 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -55,7 +55,7 @@ #include #include #include -#include +//#include #ifdef HAVE_NETINET_IN_H # include @@ -190,8 +190,8 @@ int main(int argc, char* argv[]) OutputUHDConfig outputuhd_conf; #endif - zmq::context_t zmqCtrlContext(1); - std::string zmqCtrlEndpoint = ""; + //zmq::context_t zmqCtrlContext(1); + //std::string zmqCtrlEndpoint = ""; // To handle the timestamp offset of the modulator struct modulator_offset_config modconf; @@ -204,7 +204,8 @@ int main(int argc, char* argv[]) InputMemory* input = NULL; ModOutput* output = NULL; - BaseRemoteController* rc = NULL; + //BaseRemoteController* rc = NULL; + RemoteControllers rcs; Logger logger; InputFileReader inputFileReader(logger); @@ -358,7 +359,7 @@ int main(int argc, char* argv[]) try { int telnetport = pt.get("remotecontrol.telnetport"); RemoteControllerTelnet* telnetrc = new RemoteControllerTelnet(telnetport); - rc = telnetrc; + rcs.add_controller(telnetrc); } catch (std::exception &e) { std::cerr << "Error: " << e.what() << "\n"; @@ -367,8 +368,22 @@ int main(int argc, char* argv[]) } } - zmqCtrlEndpoint = pt.get("remotecontrol.zmqctrlendpoint", ""); - std::cout << "ZmqCtrlEndpoint: " << zmqCtrlEndpoint << std::endl; +#if defined(HAVE_INPUT_ZEROMQ) + if (pt.get("remotecontrol.zmqctrl", 0) == 1) { + try { + std::string zmqCtrlEndpoint = + pt.get("remotecontrol.zmqctrlendpoint", ""); + std::cout << "ZmqCtrlEndpoint: " << zmqCtrlEndpoint << std::endl; + RemoteControllerZmq* zmqrc = new RemoteControllerZmq(zmqCtrlEndpoint); + rcs.add_controller(zmqrc); + } + catch (std::exception &e) { + std::cerr << "Error: " << e.what() << "\n"; + std::cerr << " zmq remote control enabled, but no endpoint defined.\n"; + goto END_MAIN; + } + } +#endif // input params: if (pt.get("input.loop", 0) == 1) { @@ -570,9 +585,9 @@ int main(int argc, char* argv[]) outputuhd_conf.muteNoTimestamps = (pt.get("delaymanagement.mutenotimestamps", 0) == 1); #endif } - if (!rc) { + if (rcs.get_no_controllers() == 0) { logger.level(warn) << "No Remote-Control started"; - rc = new RemoteControllerDummy(); + rcs.add_controller(new RemoteControllerDummy()); } @@ -705,8 +720,8 @@ int main(int argc, char* argv[]) outputuhd_conf.sampleRate = outputRate; try { - output = new OutputUHD(outputuhd_conf, logger, &zmqCtrlContext, zmqCtrlEndpoint); - ((OutputUHD*)output)->enrol_at(*rc); + output = new OutputUHD(outputuhd_conf, logger/*, &zmqCtrlContext, zmqCtrlEndpoint*/); + ((OutputUHD*)output)->enrol_at(rcs); } catch (std::exception& e) { logger.level(error) << "UHD initialisation failed:" << e.what(); @@ -718,7 +733,7 @@ int main(int argc, char* argv[]) flowgraph = new Flowgraph(); data.setLength(6144); input = new InputMemory(&data); - modulator = new DabModulator(modconf, rc, logger, outputRate, clockRate, + modulator = new DabModulator(modconf, &rcs, logger, outputRate, clockRate, dabMode, gainMode, digitalgain, normalise, filterTapsFilename); flowgraph->connect(input, modulator); flowgraph->connect(modulator, output); @@ -757,10 +772,8 @@ int main(int argc, char* argv[]) /* Check every once in a while if the remote control * is still working */ - if (rc && (frame % 250) == 0 && rc->fault_detected()) { - fprintf(stderr, - "Detected Remote Control fault, restarting it\n"); - rc->restart(); + if (rcs.get_no_controllers() > 0 && (frame % 250) == 0) { + rcs.check_faults(); } } if (framesize == 0) { diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp index 7f246d8..2664a08 100644 --- a/src/DabModulator.cpp +++ b/src/DabModulator.cpp @@ -53,7 +53,7 @@ DabModulator::DabModulator( struct modulator_offset_config& modconf, - BaseRemoteController* rc, + RemoteControllers* rcs, Logger& logger, unsigned outputRate, unsigned clockRate, unsigned dabMode, GainMode gainMode, @@ -71,7 +71,7 @@ DabModulator::DabModulator( myEtiReader(EtiReader(modconf, myLogger)), myFlowgraph(NULL), myFilterTapsFilename(filterTapsFilename), - myRC(rc) + myRCs(rcs) { PDEBUG("DabModulator::DabModulator(%u, %u, %u, %u) @ %p\n", outputRate, clockRate, dabMode, gainMode, this); @@ -201,13 +201,13 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) cifOfdm = new OfdmGenerator((1 + myNbSymbols), myNbCarriers, mySpacing); cifGain = new GainControl(mySpacing, myGainMode, myDigGain, myNormalise); - cifGain->enrol_at(*myRC); + cifGain->enrol_at(*myRCs); cifGuard = new GuardIntervalInserter(myNbSymbols, mySpacing, myNullSize, mySymSize); if (myFilterTapsFilename != "") { cifFilter = new FIRFilter(myFilterTapsFilename); - cifFilter->enrol_at(*myRC); + cifFilter->enrol_at(*myRCs); } myOutput = new OutputMemory(); diff --git a/src/DabModulator.h b/src/DabModulator.h index 21f9f61..84c9926 100644 --- a/src/DabModulator.h +++ b/src/DabModulator.h @@ -47,7 +47,7 @@ class DabModulator : public ModCodec public: DabModulator( struct modulator_offset_config& modconf, - BaseRemoteController* rc, + RemoteControllers* rcs, Logger& logger, unsigned outputRate = 2048000, unsigned clockRate = 0, unsigned dabMode = 0, GainMode gainMode = GAIN_VAR, @@ -77,7 +77,7 @@ protected: Flowgraph* myFlowgraph; OutputMemory* myOutput; std::string myFilterTapsFilename; - BaseRemoteController* myRC; + RemoteControllers* myRCs; size_t myNbSymbols; size_t myNbCarriers; diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index e3d2d77..4776965 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -45,9 +45,7 @@ typedef std::complex complexf; OutputUHD::OutputUHD( OutputUHDConfig& config, - Logger& logger, - zmq::context_t *pContext, - const std::string &zmqCtrlEndpoint) : + Logger& logger) : ModOutput(ModFormat(1), ModFormat(0)), RemoteControllable("uhd"), myLogger(logger), @@ -56,7 +54,7 @@ OutputUHD::OutputUHD( // the buffers at object initialisation. first_run(true), activebuffer(1), - m_delayBuf(196608) + myDelayBuf(196608) { myMuting = 0; // is remote-controllable @@ -227,14 +225,6 @@ OutputUHD::OutputUHD( worker.start(&uwd); - m_pZmqRepThread = NULL; - if (!zmqCtrlEndpoint.empty()) - { - m_pContext = pContext; - m_zmqCtrlEndpoint = zmqCtrlEndpoint; - m_pZmqRepThread = new boost::thread(boost::bind(&OutputUHD::ZmqCtrl, this)); - } - MDEBUG("OutputUHD:UHD ready.\n"); } @@ -242,12 +232,6 @@ OutputUHD::OutputUHD( OutputUHD::~OutputUHD() { MDEBUG("OutputUHD::~OutputUHD() @ %p\n", this); - if (m_pZmqRepThread != NULL) - { - m_pZmqRepThread->interrupt(); - m_pZmqRepThread->join(); - } - worker.stop(); if (!first_run) { free(uwd.frame0.buf); @@ -315,13 +299,11 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) if (activebuffer == 0) { uint8_t *pTmp = (uint8_t*) uwd.frame0.buf; // copy remain from delaybuf - memcpy(pTmp, &m_delayBuf[0], noByteDelay); + memcpy(pTmp, &myDelayBuf[0], noByteDelay); // copy new data memcpy(&pTmp[noByteDelay], pInData, uwd.bufsize - noByteDelay); // copy remaining data to delay buf - memcpy(&m_delayBuf[0], &pInData[uwd.bufsize - noByteDelay], noByteDelay); - - //memcpy(uwd.frame0.buf, dataIn->getData(), uwd.bufsize); + memcpy(&myDelayBuf[0], &pInData[uwd.bufsize - noByteDelay], noByteDelay); uwd.frame0.ts = ts; uwd.frame0.fct = myEtiReader->getFCT(); @@ -329,13 +311,11 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) else if (activebuffer == 1) { uint8_t *pTmp = (uint8_t*) uwd.frame1.buf; // copy remain from delaybuf - memcpy(pTmp, &m_delayBuf[0], noByteDelay); + memcpy(pTmp, &myDelayBuf[0], noByteDelay); // copy new data memcpy(&pTmp[noByteDelay], pInData, uwd.bufsize - noByteDelay); // copy remaining data to delay buf - memcpy(&m_delayBuf[0], &pInData[uwd.bufsize - noByteDelay], noByteDelay); - - //memcpy(uwd.frame1.buf, dataIn->getData(), uwd.bufsize); + memcpy(&myDelayBuf[0], &pInData[uwd.bufsize - noByteDelay], noByteDelay); uwd.frame1.ts = ts; uwd.frame1.fct = myEtiReader->getFCT(); @@ -683,108 +663,3 @@ const string OutputUHD::get_parameter(const string& parameter) const return ss.str(); } -void OutputUHD::RecvAll(zmq::socket_t* pSocket, std::vector &message) -{ - int more = -1; - size_t more_size = sizeof(more); - - while (more != 0) - { - zmq::message_t msg; - pSocket->recv(&msg); - message.push_back(std::string((char*)msg.data(), msg.size())); - pSocket->getsockopt(ZMQ_RCVMORE, &more, &more_size); - } -} - -void OutputUHD::SendOkReply(zmq::socket_t *pSocket) -{ - zmq::message_t msg(2); - char repCode[2] = {'o', 'k'}; - memcpy ((void*) msg.data(), repCode, 2); - pSocket->send(msg, 0); -} - -void OutputUHD::SendFailReply(zmq::socket_t *pSocket, const std::string &error) -{ - zmq::message_t msg1(4); - char repCode[4] = {'f', 'a', 'i', 'l'}; - memcpy ((void*) msg1.data(), repCode, 4); - pSocket->send(msg1, ZMQ_SNDMORE); - - zmq::message_t msg2(error.length()); - memcpy ((void*) msg2.data(), error.c_str(), error.length()); - pSocket->send(msg2, 0); -} - -//TODO: Should be implemented as an alternative to RemoteControllerTelnet and -//moved to the RemoteControl.h/cpp file instead. -void OutputUHD::ZmqCtrl() -{ - // create zmq reply socket for receiving ctrl parameters - zmq::socket_t repSocket(*m_pContext, ZMQ_REP); - std::cout << "Starting output UHD control thread" << std::endl; - try - { - // connect the socket - int hwm = 100; - int linger = 0; - repSocket.setsockopt(ZMQ_RCVHWM, &hwm, sizeof(hwm)); - repSocket.setsockopt(ZMQ_SNDHWM, &hwm, sizeof(hwm)); - repSocket.setsockopt(ZMQ_LINGER, &linger, sizeof(linger)); - repSocket.bind(m_zmqCtrlEndpoint.c_str()); - - // create pollitem that polls the ZMQ sockets - zmq::pollitem_t pollItems[] = { {repSocket, 0, ZMQ_POLLIN, 0} }; - for(;;) - { - zmq::poll(pollItems, 1, 100); - std::vector msg; - if (pollItems[0].revents & ZMQ_POLLIN) - { - RecvAll(&repSocket, msg); - std::string module((char*)msg[0].data(), msg[0].size()); - if (module == "uhd") - { - if (msg.size() < 2) - { - SendFailReply(&repSocket, "Wrong request format"); - continue; - } - - std::string param((char*) msg[1].data(), msg[1].size()); - if (msg.size() == 2 && param == "ping") - { - SendOkReply(&repSocket); - } - else if (msg.size() != 3) - { - SendFailReply(&repSocket, "Wrong request format"); - } - else - { - std::string value((char*) msg[2].data(), msg[2].size()); - try - { - set_parameter(param, value); - SendOkReply(&repSocket); - } - catch (ParameterError &err) - { - SendFailReply(&repSocket, err.what()); - } - } - } - } - - // check if thread is interrupted - boost::this_thread::interruption_point(); - } - } - catch (boost::thread_interrupted&) {} - catch (zmq::error_t &e) - { - std::cerr << "ZMQ error: " << std::string(e.what()) << std::endl; - } - repSocket.close(); -} diff --git a/src/OutputUHD.h b/src/OutputUHD.h index 25f7476..60dfc65 100644 --- a/src/OutputUHD.h +++ b/src/OutputUHD.h @@ -48,7 +48,6 @@ DESCRIPTION: #include #include #include -#include #include "Log.h" #include "ModOutput.h" @@ -184,9 +183,7 @@ class OutputUHD: public ModOutput, public RemoteControllable { OutputUHD( OutputUHDConfig& config, - Logger& logger, - zmq::context_t *pContext, - const std::string &zmqCtrlEndpoint); + Logger& logger); ~OutputUHD(); int process(Buffer* dataIn, Buffer* dataOut); @@ -226,20 +223,9 @@ class OutputUHD: public ModOutput, public RemoteControllable { bool myMuting; private: - // zmq receiving method - //TODO: Should be implemented as an alternative to RemoteControllerTelnet and - //moved to the RemoteControl.h/cpp file instead. - void ZmqCtrl(void); - void RecvAll(zmq::socket_t* pSocket, std::vector &message); - void SendOkReply(zmq::socket_t *pSocket); - void SendFailReply(zmq::socket_t *pSocket, const std::string &error); - // data int myStaticDelay; - std::vector m_delayBuf; - zmq::context_t *m_pContext; - std::string m_zmqCtrlEndpoint; - boost::thread *m_pZmqRepThread; + std::vector myDelayBuf; size_t lastLen; }; diff --git a/src/RemoteControl.cpp b/src/RemoteControl.cpp index 5bbd2f8..c7c5914 100644 --- a/src/RemoteControl.cpp +++ b/src/RemoteControl.cpp @@ -246,3 +246,145 @@ void RemoteControllerTelnet::reply(tcp::socket& socket, string message) ignored_error); } + +#if defined(HAVE_INPUT_ZEROMQ) + +void RemoteControllerZmq::restart() +{ + m_restarter_thread = boost::thread(&RemoteControllerZmq::restart_thread, this); +} + +// This runs in a separate thread, because +// it would take too long to be done in the main loop +// thread. +void RemoteControllerZmq::restart_thread() +{ + m_running = false; + + if (!m_endpoint.empty()) { + m_child_thread.interrupt(); + m_child_thread.join(); + } + + m_child_thread = boost::thread(&RemoteControllerZmq::process, this); +} + +void RemoteControllerZmq::recv_all(zmq::socket_t* pSocket, std::vector &message) +{ + int more = -1; + size_t more_size = sizeof(more); + + while (more != 0) + { + zmq::message_t msg; + pSocket->recv(&msg); + message.push_back(std::string((char*)msg.data(), msg.size())); + pSocket->getsockopt(ZMQ_RCVMORE, &more, &more_size); + } +} + +void RemoteControllerZmq::send_ok_reply(zmq::socket_t *pSocket) +{ + zmq::message_t msg(2); + char repCode[2] = {'o', 'k'}; + memcpy ((void*) msg.data(), repCode, 2); + pSocket->send(msg, 0); +} + +void RemoteControllerZmq::send_fail_reply(zmq::socket_t *pSocket, const std::string &error) +{ + zmq::message_t msg1(4); + char repCode[4] = {'f', 'a', 'i', 'l'}; + memcpy ((void*) msg1.data(), repCode, 4); + pSocket->send(msg1, ZMQ_SNDMORE); + + zmq::message_t msg2(error.length()); + memcpy ((void*) msg2.data(), error.c_str(), error.length()); + pSocket->send(msg2, 0); +} + +void RemoteControllerZmq::process() +{ + // create zmq reply socket for receiving ctrl parameters + zmq::socket_t repSocket(m_zmqContext, ZMQ_REP); + std::cout << "Starting zmq remote control thread" << std::endl; + try + { + // connect the socket + int hwm = 100; + int linger = 0; + repSocket.setsockopt(ZMQ_RCVHWM, &hwm, sizeof(hwm)); + repSocket.setsockopt(ZMQ_SNDHWM, &hwm, sizeof(hwm)); + repSocket.setsockopt(ZMQ_LINGER, &linger, sizeof(linger)); + repSocket.bind(m_endpoint.c_str()); + + // create pollitem that polls the ZMQ sockets + zmq::pollitem_t pollItems[] = { {repSocket, 0, ZMQ_POLLIN, 0} }; + for(;;) + { + zmq::poll(pollItems, 1, 100); + std::vector msg; + if (pollItems[0].revents & ZMQ_POLLIN) + { + recv_all(&repSocket, msg); + std::string command((char*)msg[0].data(), msg[0].size()); + + if (msg.size() == 1 && command == "ping") + { + send_ok_reply(&repSocket); + } + else if (msg.size() == 3 && command == "get") + { + std::string module((char*) msg[1].data(), msg[1].size()); + std::string parameter((char*) msg[2].data(), msg[2].size()); + + try + { + std::string value = get_param_(module, parameter); + zmq::message_t *pMsg = new zmq::message_t(value.size()); + memcpy ((void*) pMsg->data(), value.data(), value.size()); + repSocket.send(*pMsg, 0); + delete pMsg; + } + catch (ParameterError &err) + { + send_fail_reply(&repSocket, err.what()); + } + } + else if (msg.size() == 4 && command == "set") + { + std::string module((char*) msg[1].data(), msg[1].size()); + std::string parameter((char*) msg[2].data(), msg[2].size()); + std::string value((char*) msg[3].data(), msg[3].size()); + + try + { + set_param_(module, parameter, value); + send_ok_reply(&repSocket); + } + catch (ParameterError &err) + { + send_fail_reply(&repSocket, err.what()); + } + } + else + send_fail_reply(&repSocket, "Unsupported command"); + } + + // check if thread is interrupted + boost::this_thread::interruption_point(); + } + } + catch (boost::thread_interrupted&) {} + catch (zmq::error_t &e) + { + std::cerr << "ZMQ error: " << std::string(e.what()) << std::endl; + } + catch (std::exception& e) + { + std::cerr << "Remote control caught exception: " << e.what() << std::endl; + m_fault = true; + } + repSocket.close(); +} +#endif diff --git a/src/RemoteControl.h b/src/RemoteControl.h index 09e7492..7c830b2 100644 --- a/src/RemoteControl.h +++ b/src/RemoteControl.h @@ -29,6 +29,14 @@ #ifndef _REMOTECONTROL_H #define _REMOTECONTROL_H +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if defined(HAVE_INPUT_ZEROMQ) +#include +#endif + #include #include #include @@ -85,6 +93,42 @@ class BaseRemoteController { virtual ~BaseRemoteController() {} }; +class RemoteControllers { +/* Holds all our remote controllers, i.e. we may have more than + * one type of controller running. +*/ + public: + RemoteControllers() {} + virtual ~RemoteControllers() {} + + void add_controller(BaseRemoteController *rc) { + m_controllers.push_back(rc); + } + + void add_controllable(RemoteControllable *rc) { + for (std::list::iterator it = m_controllers.begin(); + it != m_controllers.end(); ++it) { + (*it)->enrol(rc); + } + } + + void check_faults() { + for (std::list::iterator it = m_controllers.begin(); + it != m_controllers.end(); ++it) { + if ((*it)->fault_detected()) + { + fprintf(stderr, + "Detected Remote Control fault, restarting it\n"); + (*it)->restart(); + } + } + } + size_t get_no_controllers() { return m_controllers.size(); } + + private: + std::list m_controllers; +}; + /* Objects that support remote control must implement the following class */ class RemoteControllable { public: @@ -100,8 +144,8 @@ class RemoteControllable { virtual std::string get_rc_name() const { return m_name; } /* Tell the controllable to enrol at the given controller */ - virtual void enrol_at(BaseRemoteController& controller) { - controller.enrol(this); + virtual void enrol_at(RemoteControllers& controllers) { + controllers.add_controllable(this); } /* Return a list of possible parameters that can be set */ @@ -254,6 +298,89 @@ class RemoteControllerTelnet : public BaseRemoteController { int m_port; }; +#if defined(HAVE_INPUT_ZEROMQ) +/* Implements a Remote controller using zmq transportlayer + * that listens on localhost + */ +class RemoteControllerZmq : public BaseRemoteController { + public: + RemoteControllerZmq() + : m_running(false), m_fault(false), + m_zmqContext(1), + m_endpoint("") { } + + RemoteControllerZmq(std::string endpoint) + : m_running(true), m_fault(false), + m_child_thread(&RemoteControllerZmq::process, this), + m_zmqContext(1), + m_endpoint(endpoint) + { } + + ~RemoteControllerZmq() { + m_running = false; + m_fault = false; + if (!m_endpoint.empty()) { + m_child_thread.interrupt(); + m_child_thread.join(); + } + } + + void enrol(RemoteControllable* controllable) { + m_cohort.push_back(controllable); + } + + virtual bool fault_detected() { return m_fault; } + + virtual void restart(); + + private: + void restart_thread(); + + void recv_all(zmq::socket_t* pSocket, std::vector &message); + void send_ok_reply(zmq::socket_t *pSocket); + void send_fail_reply(zmq::socket_t *pSocket, const std::string &error); + void process(); + + + RemoteControllerZmq& operator=(const RemoteControllerZmq& other); + RemoteControllerZmq(const RemoteControllerZmq& other); + + RemoteControllable* get_controllable_(std::string name) { + for (std::list::iterator it = m_cohort.begin(); + it != m_cohort.end(); ++it) { + if ((*it)->get_rc_name() == name) + { + return *it; + } + } + throw ParameterError("Module name unknown"); + } + + std::string get_param_(std::string name, std::string param) { + RemoteControllable* controllable = get_controllable_(name); + return controllable->get_parameter(param); + } + + void set_param_(std::string name, std::string param, std::string value) { + RemoteControllable* controllable = get_controllable_(name); + return controllable->set_parameter(param, value); + } + + bool m_running; + + /* This is set to true if a fault occurred */ + bool m_fault; + boost::thread m_restarter_thread; + + boost::thread m_child_thread; + + /* This controller commands the controllables in the cohort */ + std::list m_cohort; + + zmq::context_t m_zmqContext; + std::string m_endpoint; +}; +#endif /* The Dummy remote controller does nothing, and never fails */ -- cgit v1.2.3 From acadc7f9ea3e7f83abae78b662216b7fe6b7c25c Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 23 Jan 2015 10:03:38 +0100 Subject: Delete unimportant and autogenerated files --- config.h.in | 189 --------------------------------- doc/.example.ini.un~ | Bin 13605 -> 0 bytes doc/fir-filter/.README.un~ | Bin 519 -> 0 bytes doc/fir-filter/.generate-filter.py.un~ | Bin 3536 -> 0 bytes src/.TimestampDecoder.cpp.un~ | Bin 4958 -> 0 bytes 5 files changed, 189 deletions(-) delete mode 100644 config.h.in delete mode 100644 doc/.example.ini.un~ delete mode 100644 doc/fir-filter/.README.un~ delete mode 100755 doc/fir-filter/.generate-filter.py.un~ delete mode 100644 src/.TimestampDecoder.cpp.un~ diff --git a/config.h.in b/config.h.in deleted file mode 100644 index cd9076d..0000000 --- a/config.h.in +++ /dev/null @@ -1,189 +0,0 @@ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* define if the Boost library is available */ -#undef HAVE_BOOST - -/* Define to 1 if you have the `bzero' function. */ -#undef HAVE_BZERO - -/* Define to 1 if you have the declaration of `_mm_malloc', and to 0 if you - don't. */ -#undef HAVE_DECL__MM_MALLOC - -/* Define to 1 if you have the header file. */ -#undef HAVE_FCNTL_H - -/* Define to 1 if you have the `floor' function. */ -#undef HAVE_FLOOR - -/* Define to 1 if you have the `ftime' function. */ -#undef HAVE_FTIME - -/* Define to 1 if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY - -/* Define if ZeroMQ input is enabled */ -#undef HAVE_INPUT_ZEROMQ - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the `boost_system' library (-lboost_system). */ -#undef HAVE_LIBBOOST_SYSTEM - -/* Define to 1 if you have the `boost_thread' library (-lboost_thread). */ -#undef HAVE_LIBBOOST_THREAD - -/* Define to 1 if you have the `duma' library (-lduma). */ -#undef HAVE_LIBDUMA - -/* Define to 1 if you have the `efence' library (-lefence). */ -#undef HAVE_LIBEFENCE - -/* Define to 1 if you have the `rt' library (-lrt). */ -#undef HAVE_LIBRT - -/* Define to 1 if you have the `uhd' library (-luhd). */ -#undef HAVE_LIBUHD - -/* Define to 1 if you have the `zmq' library (-lzmq). */ -#undef HAVE_LIBZMQ - -/* Define to 1 if you have the header file. */ -#undef HAVE_LIMITS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MALLOC_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the `memset' function. */ -#undef HAVE_MEMSET - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_H - -/* Define if UHD output is enabled */ -#undef HAVE_OUTPUT_UHD - -/* Define to 1 if you have the `sqrt' function. */ -#undef HAVE_SQRT - -/* Define to 1 if stdbool.h conforms to C99. */ -#undef HAVE_STDBOOL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the `strchr' function. */ -#undef HAVE_STRCHR - -/* Define to 1 if you have the `strerror' function. */ -#undef HAVE_STRERROR - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `strtol' function. */ -#undef HAVE_STRTOL - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TIMEB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TIME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if the system has the type `_Bool'. */ -#undef HAVE__BOOL - -/* Replacing define */ -#undef M_PIl - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define as the return type of signal handlers (`int' or `void'). */ -#undef RETSIGTYPE - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Define to 1 if you can safely include both and . */ -#undef TIME_WITH_SYS_TIME - -/* Version number of package */ -#undef VERSION - -/* Define for Solaris 2.5.1 so the uint32_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -#undef _UINT32_T - -/* Define for Solaris 2.5.1 so the uint8_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -#undef _UINT8_T - -/* __16BIT__, __64BIT__ */ -#undef __32BIT__ - -/* __16BIT__, __32BIT__ */ -#undef __64BIT__ - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#undef inline -#endif - -/* Define to `unsigned int' if does not define. */ -#undef size_t - -/* Define to the type of an unsigned integer type of width exactly 16 bits if - such a type exists and the standard includes do not define it. */ -#undef uint16_t - -/* Define to the type of an unsigned integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -#undef uint32_t - -/* Define to the type of an unsigned integer type of width exactly 8 bits if - such a type exists and the standard includes do not define it. */ -#undef uint8_t diff --git a/doc/.example.ini.un~ b/doc/.example.ini.un~ deleted file mode 100644 index d500812..0000000 Binary files a/doc/.example.ini.un~ and /dev/null differ diff --git a/doc/fir-filter/.README.un~ b/doc/fir-filter/.README.un~ deleted file mode 100644 index b4a2d9d..0000000 Binary files a/doc/fir-filter/.README.un~ and /dev/null differ diff --git a/doc/fir-filter/.generate-filter.py.un~ b/doc/fir-filter/.generate-filter.py.un~ deleted file mode 100755 index 573ffae..0000000 Binary files a/doc/fir-filter/.generate-filter.py.un~ and /dev/null differ diff --git a/src/.TimestampDecoder.cpp.un~ b/src/.TimestampDecoder.cpp.un~ deleted file mode 100644 index 01d7cc7..0000000 Binary files a/src/.TimestampDecoder.cpp.un~ and /dev/null differ -- cgit v1.2.3 From d82422fbb3d9d34a0566197245376548ce3ef14e Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 23 Jan 2015 10:15:34 +0100 Subject: Code indentation, minor corrections --- doc/example.ini | 13 ++-- src/DabMod.cpp | 14 +--- src/OutputUHD.cpp | 56 +++++++------- src/OutputUHD.h | 8 +- src/RemoteControl.cpp | 197 +++++++++++++++++++++++++------------------------- src/RemoteControl.h | 64 ++++++++-------- 6 files changed, 172 insertions(+), 180 deletions(-) diff --git a/doc/example.ini b/doc/example.ini index 9a80eeb..ecb7440 100644 --- a/doc/example.ini +++ b/doc/example.ini @@ -9,14 +9,15 @@ telnet=1 telnetport=2121 ; Enable zmq remote control. -; The zmq remote control is intended for machine-to-machine -; integration and requires that the odr-mod is build with zmq support. -; The zmq remote control may run in parallell with Telnet. +; The zmq remote control is intended for machine-to-machine +; integration and requires that ODR-DabMod is built with zmq support. +; The zmq remote control may run in parallel with Telnet. +; ; Protocol: -; The odr-dabmod binds a zmq rep socket so clients must connect +; ODR-DabMod binds a zmq rep socket so clients must connect ; using either req or dealer socket. ; [] denotes message part as zmq multi-part message are used for delimitation. -; All message parts are utf-8 encoded strings and matches the Telnet command set. +; All message parts are utf-8 encoded strings and match the Telnet command set. ; Explicit codes are denoted with "". ; The following commands are supported: ; REQ: ["ping"] @@ -163,7 +164,7 @@ channel=13C ; The reference clock to use. ; possible values : internal, external, MIMO -refclk_source=external +refclk_source=internal ; The reference one pulse-per second to use ; possible values : none, external, MIMO diff --git a/src/DabMod.cpp b/src/DabMod.cpp index dadade9..ea6334f 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -55,7 +55,6 @@ #include #include #include -//#include #ifdef HAVE_NETINET_IN_H # include @@ -190,9 +189,6 @@ int main(int argc, char* argv[]) OutputUHDConfig outputuhd_conf; #endif - //zmq::context_t zmqCtrlContext(1); - //std::string zmqCtrlEndpoint = ""; - // To handle the timestamp offset of the modulator struct modulator_offset_config modconf; modconf.use_offset_file = false; @@ -204,7 +200,6 @@ int main(int argc, char* argv[]) InputMemory* input = NULL; ModOutput* output = NULL; - //BaseRemoteController* rc = NULL; RemoteControllers rcs; Logger logger; @@ -371,9 +366,8 @@ int main(int argc, char* argv[]) #if defined(HAVE_INPUT_ZEROMQ) if (pt.get("remotecontrol.zmqctrl", 0) == 1) { try { - std::string zmqCtrlEndpoint = - pt.get("remotecontrol.zmqctrlendpoint", ""); - std::cout << "ZmqCtrlEndpoint: " << zmqCtrlEndpoint << std::endl; + std::string zmqCtrlEndpoint = pt.get("remotecontrol.zmqctrlendpoint", ""); + std::cerr << "ZmqCtrlEndpoint: " << zmqCtrlEndpoint << std::endl; RemoteControllerZmq* zmqrc = new RemoteControllerZmq(zmqCtrlEndpoint); rcs.add_controller(zmqrc); } @@ -720,7 +714,7 @@ int main(int argc, char* argv[]) outputuhd_conf.sampleRate = outputRate; try { - output = new OutputUHD(outputuhd_conf, logger/*, &zmqCtrlContext, zmqCtrlEndpoint*/); + output = new OutputUHD(outputuhd_conf, logger); ((OutputUHD*)output)->enrol_at(rcs); } catch (std::exception& e) { @@ -773,7 +767,7 @@ int main(int argc, char* argv[]) /* Check every once in a while if the remote control * is still working */ if (rcs.get_no_controllers() > 0 && (frame % 250) == 0) { - rcs.check_faults(); + rcs.check_faults(); } } if (framesize == 0) { diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index 4776965..c7770fa 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -54,7 +54,7 @@ OutputUHD::OutputUHD( // the buffers at object initialisation. first_run(true), activebuffer(1), - myDelayBuf(196608) + myDelayBuf(196608) { myMuting = 0; // is remote-controllable @@ -233,10 +233,10 @@ OutputUHD::~OutputUHD() { MDEBUG("OutputUHD::~OutputUHD() @ %p\n", this); worker.stop(); - if (!first_run) { - free(uwd.frame0.buf); - free(uwd.frame1.buf); - } + if (!first_run) { + free(uwd.frame0.buf); + free(uwd.frame1.buf); + } } int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) @@ -291,31 +291,31 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) uwd.sourceContainsTimestamp = myConf.enableSync && myEtiReader->sourceContainsTimestamp(); - // calculate delay - uint32_t noSampleDelay = (myStaticDelay * 2048) / 1000; - uint32_t noByteDelay = noSampleDelay * sizeof(complexf); + // calculate delay + uint32_t noSampleDelay = (myStaticDelay * 2048) / 1000; + uint32_t noByteDelay = noSampleDelay * sizeof(complexf); - uint8_t* pInData = (uint8_t*) dataIn->getData(); + uint8_t* pInData = (uint8_t*) dataIn->getData(); if (activebuffer == 0) { - uint8_t *pTmp = (uint8_t*) uwd.frame0.buf; - // copy remain from delaybuf + uint8_t *pTmp = (uint8_t*) uwd.frame0.buf; + // copy remain from delaybuf memcpy(pTmp, &myDelayBuf[0], noByteDelay); - // copy new data + // copy new data memcpy(&pTmp[noByteDelay], pInData, uwd.bufsize - noByteDelay); - // copy remaining data to delay buf - memcpy(&myDelayBuf[0], &pInData[uwd.bufsize - noByteDelay], noByteDelay); + // copy remaining data to delay buf + memcpy(&myDelayBuf[0], &pInData[uwd.bufsize - noByteDelay], noByteDelay); uwd.frame0.ts = ts; uwd.frame0.fct = myEtiReader->getFCT(); } else if (activebuffer == 1) { - uint8_t *pTmp = (uint8_t*) uwd.frame1.buf; - // copy remain from delaybuf + uint8_t *pTmp = (uint8_t*) uwd.frame1.buf; + // copy remain from delaybuf memcpy(pTmp, &myDelayBuf[0], noByteDelay); - // copy new data + // copy new data memcpy(&pTmp[noByteDelay], pInData, uwd.bufsize - noByteDelay); - // copy remaining data to delay buf - memcpy(&myDelayBuf[0], &pInData[uwd.bufsize - noByteDelay], noByteDelay); + // copy remaining data to delay buf + memcpy(&myDelayBuf[0], &pInData[uwd.bufsize - noByteDelay], noByteDelay); uwd.frame1.ts = ts; uwd.frame1.fct = myEtiReader->getFCT(); @@ -617,15 +617,15 @@ void OutputUHD::set_parameter(const string& parameter, const string& value) ss >> myMuting; } else if (parameter == "staticdelay") { - int adjust; - ss >> adjust; - int newStaticDelay = myStaticDelay + adjust; - if (newStaticDelay > 96000) - myStaticDelay = newStaticDelay - 96000; - else if (newStaticDelay < 0) - myStaticDelay = newStaticDelay + 96000; - else - myStaticDelay = newStaticDelay; + int adjust; + ss >> adjust; + int newStaticDelay = myStaticDelay + adjust; + if (newStaticDelay > 96000) + myStaticDelay = newStaticDelay - 96000; + else if (newStaticDelay < 0) + myStaticDelay = newStaticDelay + 96000; + else + myStaticDelay = newStaticDelay; } else if (parameter == "iqbalance") { ss >> myConf.frequency; diff --git a/src/OutputUHD.h b/src/OutputUHD.h index 60dfc65..90d9d1b 100644 --- a/src/OutputUHD.h +++ b/src/OutputUHD.h @@ -222,10 +222,10 @@ class OutputUHD: public ModOutput, public RemoteControllable { // muting can only be changed using the remote control bool myMuting; - private: - // data - int myStaticDelay; - std::vector myDelayBuf; + private: + // data + int myStaticDelay; + std::vector myDelayBuf; size_t lastLen; }; diff --git a/src/RemoteControl.cpp b/src/RemoteControl.cpp index c7c5914..6f538dc 100644 --- a/src/RemoteControl.cpp +++ b/src/RemoteControl.cpp @@ -271,120 +271,121 @@ void RemoteControllerZmq::restart_thread() void RemoteControllerZmq::recv_all(zmq::socket_t* pSocket, std::vector &message) { - int more = -1; - size_t more_size = sizeof(more); - - while (more != 0) - { - zmq::message_t msg; - pSocket->recv(&msg); - message.push_back(std::string((char*)msg.data(), msg.size())); - pSocket->getsockopt(ZMQ_RCVMORE, &more, &more_size); - } + int more = -1; + size_t more_size = sizeof(more); + + while (more != 0) + { + zmq::message_t msg; + pSocket->recv(&msg); + message.push_back(std::string((char*)msg.data(), msg.size())); + pSocket->getsockopt(ZMQ_RCVMORE, &more, &more_size); + } } void RemoteControllerZmq::send_ok_reply(zmq::socket_t *pSocket) { - zmq::message_t msg(2); - char repCode[2] = {'o', 'k'}; - memcpy ((void*) msg.data(), repCode, 2); - pSocket->send(msg, 0); + zmq::message_t msg(2); + char repCode[2] = {'o', 'k'}; + memcpy ((void*) msg.data(), repCode, 2); + pSocket->send(msg, 0); } void RemoteControllerZmq::send_fail_reply(zmq::socket_t *pSocket, const std::string &error) { - zmq::message_t msg1(4); - char repCode[4] = {'f', 'a', 'i', 'l'}; - memcpy ((void*) msg1.data(), repCode, 4); - pSocket->send(msg1, ZMQ_SNDMORE); - - zmq::message_t msg2(error.length()); - memcpy ((void*) msg2.data(), error.c_str(), error.length()); - pSocket->send(msg2, 0); + zmq::message_t msg1(4); + char repCode[4] = {'f', 'a', 'i', 'l'}; + memcpy ((void*) msg1.data(), repCode, 4); + pSocket->send(msg1, ZMQ_SNDMORE); + + zmq::message_t msg2(error.length()); + memcpy ((void*) msg2.data(), error.c_str(), error.length()); + pSocket->send(msg2, 0); } void RemoteControllerZmq::process() { - // create zmq reply socket for receiving ctrl parameters - zmq::socket_t repSocket(m_zmqContext, ZMQ_REP); - std::cout << "Starting zmq remote control thread" << std::endl; - try - { - // connect the socket - int hwm = 100; - int linger = 0; - repSocket.setsockopt(ZMQ_RCVHWM, &hwm, sizeof(hwm)); - repSocket.setsockopt(ZMQ_SNDHWM, &hwm, sizeof(hwm)); - repSocket.setsockopt(ZMQ_LINGER, &linger, sizeof(linger)); - repSocket.bind(m_endpoint.c_str()); - - // create pollitem that polls the ZMQ sockets - zmq::pollitem_t pollItems[] = { {repSocket, 0, ZMQ_POLLIN, 0} }; - for(;;) - { - zmq::poll(pollItems, 1, 100); - std::vector msg; - if (pollItems[0].revents & ZMQ_POLLIN) - { - recv_all(&repSocket, msg); - std::string command((char*)msg[0].data(), msg[0].size()); - - if (msg.size() == 1 && command == "ping") - { - send_ok_reply(&repSocket); - } - else if (msg.size() == 3 && command == "get") - { - std::string module((char*) msg[1].data(), msg[1].size()); - std::string parameter((char*) msg[2].data(), msg[2].size()); - - try - { - std::string value = get_param_(module, parameter); - zmq::message_t *pMsg = new zmq::message_t(value.size()); - memcpy ((void*) pMsg->data(), value.data(), value.size()); - repSocket.send(*pMsg, 0); - delete pMsg; - } - catch (ParameterError &err) - { - send_fail_reply(&repSocket, err.what()); - } - } - else if (msg.size() == 4 && command == "set") - { - std::string module((char*) msg[1].data(), msg[1].size()); - std::string parameter((char*) msg[2].data(), msg[2].size()); - std::string value((char*) msg[3].data(), msg[3].size()); - - try - { - set_param_(module, parameter, value); - send_ok_reply(&repSocket); - } - catch (ParameterError &err) - { - send_fail_reply(&repSocket, err.what()); - } - } - else - send_fail_reply(&repSocket, "Unsupported command"); - } - - // check if thread is interrupted - boost::this_thread::interruption_point(); - } - } - catch (boost::thread_interrupted&) {} - catch (zmq::error_t &e) - { - std::cerr << "ZMQ error: " << std::string(e.what()) << std::endl; - } + // create zmq reply socket for receiving ctrl parameters + zmq::socket_t repSocket(m_zmqContext, ZMQ_REP); + std::cout << "Starting zmq remote control thread" << std::endl; + try + { + // connect the socket + int hwm = 100; + int linger = 0; + repSocket.setsockopt(ZMQ_RCVHWM, &hwm, sizeof(hwm)); + repSocket.setsockopt(ZMQ_SNDHWM, &hwm, sizeof(hwm)); + repSocket.setsockopt(ZMQ_LINGER, &linger, sizeof(linger)); + repSocket.bind(m_endpoint.c_str()); + + // create pollitem that polls the ZMQ sockets + zmq::pollitem_t pollItems[] = { {repSocket, 0, ZMQ_POLLIN, 0} }; + for(;;) + { + zmq::poll(pollItems, 1, 100); + std::vector msg; + if (pollItems[0].revents & ZMQ_POLLIN) + { + recv_all(&repSocket, msg); + std::string command((char*)msg[0].data(), msg[0].size()); + + if (msg.size() == 1 && command == "ping") + { + send_ok_reply(&repSocket); + } + else if (msg.size() == 3 && command == "get") + { + std::string module((char*) msg[1].data(), msg[1].size()); + std::string parameter((char*) msg[2].data(), msg[2].size()); + + try + { + std::string value = get_param_(module, parameter); + zmq::message_t *pMsg = new zmq::message_t(value.size()); + memcpy ((void*) pMsg->data(), value.data(), value.size()); + repSocket.send(*pMsg, 0); + delete pMsg; + } + catch (ParameterError &err) + { + send_fail_reply(&repSocket, err.what()); + } + } + else if (msg.size() == 4 && command == "set") + { + std::string module((char*) msg[1].data(), msg[1].size()); + std::string parameter((char*) msg[2].data(), msg[2].size()); + std::string value((char*) msg[3].data(), msg[3].size()); + + try + { + set_param_(module, parameter, value); + send_ok_reply(&repSocket); + } + catch (ParameterError &err) + { + send_fail_reply(&repSocket, err.what()); + } + } + else + send_fail_reply(&repSocket, "Unsupported command"); + } + + // check if thread is interrupted + boost::this_thread::interruption_point(); + } + } + catch (boost::thread_interrupted&) {} + catch (zmq::error_t &e) + { + std::cerr << "ZMQ error: " << std::string(e.what()) << std::endl; + } catch (std::exception& e) { std::cerr << "Remote control caught exception: " << e.what() << std::endl; m_fault = true; } - repSocket.close(); + repSocket.close(); } #endif + diff --git a/src/RemoteControl.h b/src/RemoteControl.h index 7c830b2..905e153 100644 --- a/src/RemoteControl.h +++ b/src/RemoteControl.h @@ -93,40 +93,37 @@ class BaseRemoteController { virtual ~BaseRemoteController() {} }; -class RemoteControllers { /* Holds all our remote controllers, i.e. we may have more than * one type of controller running. -*/ + */ +class RemoteControllers { public: - RemoteControllers() {} - virtual ~RemoteControllers() {} - - void add_controller(BaseRemoteController *rc) { - m_controllers.push_back(rc); - } + void add_controller(BaseRemoteController *rc) { + m_controllers.push_back(rc); + } - void add_controllable(RemoteControllable *rc) { + void add_controllable(RemoteControllable *rc) { for (std::list::iterator it = m_controllers.begin(); it != m_controllers.end(); ++it) { - (*it)->enrol(rc); - } - } - + (*it)->enrol(rc); + } + } + void check_faults() { for (std::list::iterator it = m_controllers.begin(); it != m_controllers.end(); ++it) { - if ((*it)->fault_detected()) - { - fprintf(stderr, - "Detected Remote Control fault, restarting it\n"); - (*it)->restart(); - } - } - } - size_t get_no_controllers() { return m_controllers.size(); } - - private: - std::list m_controllers; + if ((*it)->fault_detected()) + { + fprintf(stderr, + "Detected Remote Control fault, restarting it\n"); + (*it)->restart(); + } + } + } + size_t get_no_controllers() { return m_controllers.size(); } + + private: + std::list m_controllers; }; /* Objects that support remote control must implement the following class */ @@ -306,15 +303,14 @@ class RemoteControllerZmq : public BaseRemoteController { public: RemoteControllerZmq() : m_running(false), m_fault(false), - m_zmqContext(1), + m_zmqContext(1), m_endpoint("") { } RemoteControllerZmq(std::string endpoint) : m_running(true), m_fault(false), m_child_thread(&RemoteControllerZmq::process, this), - m_zmqContext(1), - m_endpoint(endpoint) - { } + m_zmqContext(1), + m_endpoint(endpoint) { } ~RemoteControllerZmq() { m_running = false; @@ -336,9 +332,9 @@ class RemoteControllerZmq : public BaseRemoteController { private: void restart_thread(); - void recv_all(zmq::socket_t* pSocket, std::vector &message); - void send_ok_reply(zmq::socket_t *pSocket); - void send_fail_reply(zmq::socket_t *pSocket, const std::string &error); + void recv_all(zmq::socket_t* pSocket, std::vector &message); + void send_ok_reply(zmq::socket_t *pSocket); + void send_fail_reply(zmq::socket_t *pSocket, const std::string &error); void process(); @@ -377,8 +373,8 @@ class RemoteControllerZmq : public BaseRemoteController { /* This controller commands the controllables in the cohort */ std::list m_cohort; - zmq::context_t m_zmqContext; - std::string m_endpoint; + zmq::context_t m_zmqContext; + std::string m_endpoint; }; #endif -- cgit v1.2.3 From 076ac8aaf7adfeca57d5d04d4b2f066bb6db54ee Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 23 Jan 2015 10:34:12 +0100 Subject: Security issue: telnet RC only on localhost --- src/RemoteControl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/RemoteControl.cpp b/src/RemoteControl.cpp index 6f538dc..1e8dda5 100644 --- a/src/RemoteControl.cpp +++ b/src/RemoteControl.cpp @@ -66,7 +66,8 @@ void RemoteControllerTelnet::process(long) try { boost::asio::io_service io_service; - tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), m_port)); + tcp::acceptor acceptor(io_service, tcp::endpoint( + boost::asio::ip::address::from_string("127.0.0.1"), m_port) ); while (m_running) { in_message = ""; -- cgit v1.2.3 From 2e646a26c9db66dd5776667d9c9b73d798f5ffda Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 23 Jan 2015 10:46:26 +0100 Subject: Merge input-zeromq and output-zeromq configure options --- INSTALL | 7 ++++--- configure.ac | 19 ++++++------------- src/DabMod.cpp | 17 +++++++---------- src/InputReader.h | 4 ++-- src/InputZeroMQReader.cpp | 2 +- src/OutputZeroMQ.cpp | 4 ++-- src/OutputZeroMQ.h | 4 ++-- src/RemoteControl.cpp | 2 +- src/RemoteControl.h | 4 ++-- 9 files changed, 27 insertions(+), 36 deletions(-) diff --git a/INSTALL b/INSTALL index 55385ba..bb14565 100644 --- a/INSTALL +++ b/INSTALL @@ -2,8 +2,8 @@ Required dependencies: ====================== * Boost 1.41 or later + * Optional UHD for USRP * Optional ZeroMQ http://www.zeromq.org - Use --disable-input-zeromq if you don't have it * Optional FFTW 3.x (included KISS FFT is used as fallback) Simple install procedure: @@ -11,7 +11,7 @@ Simple install procedure: % tar xjf odr-dabmod-X.Y.Z.tar.bz2 # Unpack the source % cd odr-dabmod-X.Y.Z # Change to the source directory - % ./configure --disable-debug --with-debug-malloc=yes + % ./configure --enable-zeromq --enable-output-uhd # Run the configure script % make # Build ODR-DabMod [ as root ] @@ -21,7 +21,8 @@ Configure options ================= The configure script can be launch with a variety of options: - --enable-input-zeromq Enable ZeroMQ input (to be used with ODR-DabMux) + --enable-zeromq Enable ZeroMQ input (to be used with ODR-DabMux), + output and remotecontrol. --enable-output-uhd Includes the binding to the UHD driver for USRPs You have the choice between two FFT libraries: KISS FFT and FFTW. KISS FFT is a diff --git a/configure.ac b/configure.ac index 615bf6d..739f54a 100644 --- a/configure.ac +++ b/configure.ac @@ -71,12 +71,8 @@ AC_ARG_ENABLE([kiss_fft], [], [enable_kiss=no]) # ZeroMQ message queue input -AC_ARG_ENABLE([input_zeromq], - AS_HELP_STRING([--enable-input-zeromq], [Enable ZeroMQ input])) - -# ZeroMQ message IQ output -AC_ARG_ENABLE([output_zeromq], - AS_HELP_STRING([--enable-output-zeromq], [Enable ZeroMQ output])) +AC_ARG_ENABLE([zeromq], + AS_HELP_STRING([--enable-zeromq], [Enable ZeroMQ input, output and remote control])) # UHD support control AC_ARG_ENABLE([output_uhd], @@ -91,13 +87,10 @@ AS_IF([test "x$enable_fftw" = "xyes"], AC_MSG_NOTICE([Found FFTW3]), AC_MSG_NOTICE([Using Kiss FFT]) ) -echo "Checking input zeromq" +echo "Checking zeromq" -AS_IF([test "x$enable_input_zeromq" = "xyes"], - [AC_DEFINE(HAVE_INPUT_ZEROMQ, [1], [Define if ZeroMQ input is enabled]) , - AC_CHECK_LIB(zmq, zmq_init, ZMQ_LIBS="-lzmq" ,[AC_MSG_ERROR([ZeroMQ libzmq is required])])]) -AS_IF([test "x$enable_output_zeromq" = "xyes"], - [AC_DEFINE(HAVE_OUTPUT_ZEROMQ, [1], [Define if ZeroMQ output is enabled]) , +AS_IF([test "x$enable_zeromq" = "xyes"], + [AC_DEFINE(HAVE_ZEROMQ, [1], [Define if ZeroMQ is enabled]) , AC_CHECK_LIB(zmq, zmq_init, ZMQ_LIBS="-lzmq" ,[AC_MSG_ERROR([ZeroMQ libzmq is required])])]) AS_IF([test "x$enable_debug" = "xno"], [OPTIM="-O2" DEBUG="" EXTRA="$EXTRA -DNDEBUG"], @@ -203,7 +196,7 @@ echo "***********************************************" echo enabled="" disabled="" -for feat in debug prof trace fftw fft_simd output_uhd input_zeromq output_zeromq +for feat in debug prof trace fftw fft_simd output_uhd zeromq do eval var=\$enable_$feat AS_IF([test "x$var" = "xyes"], diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 4912bee..cc7dd96 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -213,7 +213,7 @@ int main(int argc, char* argv[]) Logger logger; InputFileReader inputFileReader(logger); -#if defined(HAVE_INPUT_ZEROMQ) +#if defined(HAVE_ZEROMQ) InputZeroMQReader inputZeroMQReader(logger); #endif InputReader* inputReader; @@ -352,14 +352,11 @@ int main(int argc, char* argv[]) "\n"; std::cerr << "Compiled with features: " << -#if defined(HAVE_INPUT_ZEROMQ) - "input_zeromq " << +#if defined(HAVE_ZEROMQ) + "zeromq " << #endif #if defined(HAVE_OUTPUT_UHD) "output_uhd " << -#endif -#if defined(HAVE_OUTPUT_ZEROMQ) - "output_zeromq " << #endif "\n"; @@ -408,7 +405,7 @@ int main(int argc, char* argv[]) } } -#if defined(HAVE_INPUT_ZEROMQ) +#if defined(HAVE_ZEROMQ) if (pt.get("remotecontrol.zmqctrl", 0) == 1) { try { std::string zmqCtrlEndpoint = pt.get("remotecontrol.zmqctrlendpoint", ""); @@ -592,7 +589,7 @@ int main(int argc, char* argv[]) useUHDOutput = 1; } #endif -#if defined(HAVE_OUTPUT_ZEROMQ) +#if defined(HAVE_ZEROMQ) else if (output_selected == "zmq") { outputName = pt.get("zmqoutput.listen"); useZeroMQOutput = 1; @@ -735,7 +732,7 @@ int main(int argc, char* argv[]) inputReader = &inputFileReader; } else if (inputTransport == "zeromq") { -#if !defined(HAVE_INPUT_ZEROMQ) +#if !defined(HAVE_ZEROMQ) fprintf(stderr, "Error, ZeroMQ input transport selected, but not compiled in!\n"); ret = -1; goto END_MAIN; @@ -786,7 +783,7 @@ int main(int argc, char* argv[]) } } #endif -#if defined(HAVE_OUTPUT_ZEROMQ) +#if defined(HAVE_ZEROMQ) else if (useZeroMQOutput) { /* We normalise the same way as for the UHD output */ normalise = 1.0f/50000.0f; diff --git a/src/InputReader.h b/src/InputReader.h index 164c5ac..3e0dcab 100644 --- a/src/InputReader.h +++ b/src/InputReader.h @@ -31,7 +31,7 @@ #endif #include -#if defined(HAVE_INPUT_ZEROMQ) +#if defined(HAVE_ZEROMQ) # include "zmq.hpp" # include "ThreadsafeQueue.h" #endif @@ -130,7 +130,7 @@ class InputFileReader : public InputReader // after 2**32 * 24ms ~= 3.3 years }; -#if defined(HAVE_INPUT_ZEROMQ) +#if defined(HAVE_ZEROMQ) /* A ZeroMQ input. See www.zeromq.org for more info */ struct InputZeroMQThreadData diff --git a/src/InputZeroMQReader.cpp b/src/InputZeroMQReader.cpp index cfb56b2..f7f5702 100644 --- a/src/InputZeroMQReader.cpp +++ b/src/InputZeroMQReader.cpp @@ -29,7 +29,7 @@ # include "config.h" #endif -#if defined(HAVE_INPUT_ZEROMQ) +#if defined(HAVE_ZEROMQ) #include #include diff --git a/src/OutputZeroMQ.cpp b/src/OutputZeroMQ.cpp index 0e759dd..793e473 100644 --- a/src/OutputZeroMQ.cpp +++ b/src/OutputZeroMQ.cpp @@ -30,7 +30,7 @@ #include #include -#if defined(HAVE_OUTPUT_ZEROMQ) +#if defined(HAVE_ZEROMQ) OutputZeroMQ::OutputZeroMQ(std::string endpoint, Buffer* dataOut) : ModOutput(ModFormat(1), ModFormat(0)), @@ -63,5 +63,5 @@ int OutputZeroMQ::process(Buffer* dataIn, Buffer* dataOut) return dataIn->getLength(); } -#endif // HAVE_OUTPUT_ZEROMQ_H +#endif // HAVE_ZEROMQ diff --git a/src/OutputZeroMQ.h b/src/OutputZeroMQ.h index 1c48fe7..a80eab4 100644 --- a/src/OutputZeroMQ.h +++ b/src/OutputZeroMQ.h @@ -31,7 +31,7 @@ # include "config.h" #endif -#if defined(HAVE_OUTPUT_ZEROMQ) +#if defined(HAVE_ZEROMQ) #include "ModOutput.h" #include "zmq.hpp" @@ -54,7 +54,7 @@ class OutputZeroMQ : public ModOutput std::string m_name; }; -#endif // HAVE_OUTPUT_ZEROMQ_H +#endif // HAVE_ZEROMQ #endif // OUTPUT_ZEROMQ_H diff --git a/src/RemoteControl.cpp b/src/RemoteControl.cpp index 1e8dda5..65da3b7 100644 --- a/src/RemoteControl.cpp +++ b/src/RemoteControl.cpp @@ -248,7 +248,7 @@ void RemoteControllerTelnet::reply(tcp::socket& socket, string message) } -#if defined(HAVE_INPUT_ZEROMQ) +#if defined(HAVE_ZEROMQ) void RemoteControllerZmq::restart() { diff --git a/src/RemoteControl.h b/src/RemoteControl.h index 905e153..89a1583 100644 --- a/src/RemoteControl.h +++ b/src/RemoteControl.h @@ -33,7 +33,7 @@ # include "config.h" #endif -#if defined(HAVE_INPUT_ZEROMQ) +#if defined(HAVE_ZEROMQ) #include #endif @@ -295,7 +295,7 @@ class RemoteControllerTelnet : public BaseRemoteController { int m_port; }; -#if defined(HAVE_INPUT_ZEROMQ) +#if defined(HAVE_ZEROMQ) /* Implements a Remote controller using zmq transportlayer * that listens on localhost */ -- cgit v1.2.3 From 109d40f1e598f9d122a91ad0267e6ce199b174a4 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 23 Jan 2015 12:00:54 +0100 Subject: Replace signal() by sigaction() --- src/DabMod.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/DabMod.cpp b/src/DabMod.cpp index cc7dd96..06d1254 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -71,13 +71,13 @@ typedef std::complex complexf; -bool running = true; +volatile sig_atomic_t running = 1; void signalHandler(int signalNb) { PDEBUG("signalHandler(%i)\n", signalNb); - running = false; + running = 0; } @@ -218,7 +218,14 @@ int main(int argc, char* argv[]) #endif InputReader* inputReader; - signal(SIGINT, signalHandler); + struct sigaction sa; + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = &signalHandler; + + if (sigaction(SIGINT, &sa, NULL) == -1) { + perror("sigaction"); + return EXIT_FAILURE; + } // Set timezone to UTC setenv("TZ", "", 1); @@ -844,7 +851,7 @@ int main(int argc, char* argv[]) else { fprintf(stderr, "Input read error.\n"); } - running = false; + running = 0; } } catch (std::exception& e) { fprintf(stderr, "EXCEPTION: %s\n", e.what()); -- cgit v1.2.3 From 8912158484d7e75f5e8c343ac33ca98f3e6f7f50 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sat, 24 Jan 2015 11:21:16 +0100 Subject: Prepare release v0.5.1 --- ChangeLog | 8 ++++++++ README.md | 5 +++-- configure.ac | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index e005721..d13be34 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,14 @@ This file contains information about the changes done to the ODR-DabMod in this repository +2015-01-24: Matthias P. Braendli + (v0.5.1) + * odr-dabmod: + Security: force Telnet RC to listen only on + localhost. + Add raspine's ZeroMQ RC and UHD staticdelay setting + Add I/Q format converter (signed 8-bit) + 2014-12-09: Matthias P. Braendli (v0.5.0) * odr-dabmod: diff --git a/README.md b/README.md index 8ea87c9..292bba5 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,9 @@ In addition to the features of CRC-DabMod, this fork contains: - A FIR filter (previously done in GNURadio by crc-dwap.py) - Improvements in logging (log to file, to syslog) - ETI sources: file (Raw, Framed and Streamed) and ZeroMQ -- A Telnet remote-control that can be used to change some parameters during - runtime +- A Telnet and ZeroMQ remote-control that can be used to change + some parameters during runtime +- 8-bit signed I/Q output format The src/ directory contains the source code of ODR-DabMod. diff --git a/configure.ac b/configure.ac index 739f54a..3f21f89 100644 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,7 @@ # along with ODR-DabMod. If not, see . AC_PREREQ(2.59) -AC_INIT([ODR-DabMod], [0.5.0], [matthias.braendli@mpb.li]) +AC_INIT([ODR-DabMod], [0.5.1], [matthias.braendli@mpb.li]) AC_CONFIG_AUX_DIR([build-aux]) AC_CANONICAL_SYSTEM AM_INIT_AUTOMAKE([-Wall foreign]) -- cgit v1.2.3 From 7e9fa603ee00fa0ec8ebf6e258f94cadbb300856 Mon Sep 17 00:00:00 2001 From: Jörgen Scott Date: Tue, 3 Feb 2015 17:09:37 +0100 Subject: added filter for vim backup files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 85dfe44..1851b69 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ src/odr-dabmod .clang_complete .*.swp +*~ -- cgit v1.2.3 From 1ab555f832c764bd10cebeeee51d9f7ad5c4b2c6 Mon Sep 17 00:00:00 2001 From: Jörgen Scott Date: Wed, 4 Feb 2015 12:19:55 +0100 Subject: Removed magick numbers and added support for static delay in all dab modes --- src/DabMod.cpp | 1 + src/OutputUHD.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++---------- src/OutputUHD.h | 7 ++++++- 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 82f03e5..214231c 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -535,6 +535,7 @@ int main(int argc, char* argv[]) outputuhd_conf.txgain = pt.get("uhdoutput.txgain", 0.0); outputuhd_conf.frequency = pt.get("uhdoutput.frequency", 0); std::string chan = pt.get("uhdoutput.channel", ""); + outputuhd_conf.dabMode = dabMode; if (outputuhd_conf.frequency == 0 && chan == "") { std::cerr << " UHD output enabled, but neither frequency nor channel defined.\n"; diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index 741731e..91c030f 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -57,11 +57,11 @@ OutputUHD::OutputUHD( // the buffers at object initialisation. first_run(true), activebuffer(1), - myDelayBuf(196608) + myDelayBuf(0) { myMuting = 0; // is remote-controllable - myStaticDelay = 0; // is remote-controllable + myStaticDelayUs = 0; // is remote-controllable #if FAKE_UHD MDEBUG("OutputUHD:Using fake UHD output"); @@ -225,6 +225,7 @@ OutputUHD::OutputUHD( uwd.check_refclk_loss = true; } + SetDelayBuffer(config.dabMode); shared_ptr b(new barrier(2)); mySyncBarrier = b; @@ -246,6 +247,35 @@ OutputUHD::~OutputUHD() } } +void OutputUHD::SetDelayBuffer(unsigned int dabMode) +{ + // find out the duration of the transmission frame (Table 2 in ETSI 300 401) + switch (dabMode) { + case 0: // could happen when called from constructor and we take the mode from ETI + myTFDurationMs = 0; + break; + case 1: + myTFDurationMs = 96; + break; + case 2: + myTFDurationMs = 24; + break; + case 3: + myTFDurationMs = 24; + break; + case 4: + myTFDurationMs = 48; + break; + default: + throw std::runtime_error("OutPutUHD: invalid DAB mode"); + } + fprintf(stderr, "DelayBuf = %d\n", myTFDurationMs * myConf.sampleRate / 1000); + // The buffer size equals the number of samples per transmission frame so + // we calculate it by multiplying the duration of the transmission frame + // with the samplerate. + myDelayBuf.resize(myTFDurationMs * myConf.sampleRate / 1000); +} + int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) { struct frame_timestamp ts; @@ -281,6 +311,10 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) default: break; } + // we only set the delay buffer from the dab mode signaled in ETI if the + // dab mode was not set in contructor + if (myTFDurationMs == 0) + SetDelayBuffer(myEtiReader->getMode()); activebuffer = 1; @@ -307,7 +341,7 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) myEtiReader->sourceContainsTimestamp(); // calculate delay - uint32_t noSampleDelay = (myStaticDelay * 2048) / 1000; + uint32_t noSampleDelay = (myStaticDelayUs * myConf.sampleRate / 1000) / 1000; uint32_t noByteDelay = noSampleDelay * sizeof(complexf); uint8_t* pInData = (uint8_t*) dataIn->getData(); @@ -655,13 +689,13 @@ void OutputUHD::set_parameter(const string& parameter, const string& value) else if (parameter == "staticdelay") { int adjust; ss >> adjust; - int newStaticDelay = myStaticDelay + adjust; - if (newStaticDelay > 96000) - myStaticDelay = newStaticDelay - 96000; - else if (newStaticDelay < 0) - myStaticDelay = newStaticDelay + 96000; + int newStaticDelayUs = myStaticDelayUs + adjust; + if (newStaticDelayUs > myTFDurationMs * 1000) + myStaticDelayUs = newStaticDelayUs - myTFDurationMs * 1000; + else if (newStaticDelayUs < 0) + myStaticDelayUs = newStaticDelayUs + myTFDurationMs * 1000; else - myStaticDelay = newStaticDelay; + myStaticDelayUs = newStaticDelayUs; } else if (parameter == "iqbalance") { ss >> myConf.frequency; @@ -689,7 +723,7 @@ const string OutputUHD::get_parameter(const string& parameter) const ss << myMuting; } else if (parameter == "staticdelay") { - ss << myStaticDelay; + ss << myStaticDelayUs; } else { ss << "Parameter '" << parameter << diff --git a/src/OutputUHD.h b/src/OutputUHD.h index 7eb6733..d002e98 100644 --- a/src/OutputUHD.h +++ b/src/OutputUHD.h @@ -171,6 +171,7 @@ struct OutputUHDConfig { double txgain; bool enableSync; bool muteNoTimestamps; + unsigned dabMode; /* allowed values : auto, int, sma, mimo */ std::string refclk_src; @@ -231,8 +232,12 @@ class OutputUHD: public ModOutput, public RemoteControllable { bool myMuting; private: + // methods + void SetDelayBuffer(unsigned int dabMode); + // data - int myStaticDelay; + int myStaticDelayUs; // static delay in microseconds + int myTFDurationMs; // TF duration in milliseconds std::vector myDelayBuf; size_t lastLen; }; -- cgit v1.2.3 From ac43b12ea669b3ea81dafdffdae3d3e374a836f4 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Wed, 4 Feb 2015 21:02:54 +0100 Subject: Add pkg.m4 autoconf script --- m4/pkg.m4 | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 m4/pkg.m4 diff --git a/m4/pkg.m4 b/m4/pkg.m4 new file mode 100644 index 0000000..c5b26b5 --- /dev/null +++ b/m4/pkg.m4 @@ -0,0 +1,214 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 1 (pkg-config-0.24) +# +# Copyright © 2004 Scott James Remnant . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +# only at the first occurence in configure.ac, so if the first place +# it's called might be skipped (such as if it is within an "if", you +# have to call PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])# PKG_CHECK_MODULES + + +# PKG_INSTALLDIR(DIRECTORY) +# ------------------------- +# Substitutes the variable pkgconfigdir as the location where a module +# should install pkg-config .pc files. By default the directory is +# $libdir/pkgconfig, but the default can be changed by passing +# DIRECTORY. The user can override through the --with-pkgconfigdir +# parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +]) dnl PKG_INSTALLDIR + + +# PKG_NOARCH_INSTALLDIR(DIRECTORY) +# ------------------------- +# Substitutes the variable noarch_pkgconfigdir as the location where a +# module should install arch-independent pkg-config .pc files. By +# default the directory is $datadir/pkgconfig, but the default can be +# changed by passing DIRECTORY. The user can override through the +# --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +]) dnl PKG_NOARCH_INSTALLDIR + + +# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# ------------------------------------------- +# Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])# PKG_CHECK_VAR -- cgit v1.2.3 From bcf924ecc3962381e5bf14107d7cab2144a81c78 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Thu, 5 Feb 2015 17:58:37 +0100 Subject: Change autotools to "subdir-objects" and simplify --- Makefile.am | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- configure.ac | 7 ++- lib/Makefile.am | 19 -------- src/Makefile.am | 127 ------------------------------------------------ 4 files changed, 149 insertions(+), 152 deletions(-) delete mode 100644 lib/Makefile.am delete mode 100644 src/Makefile.am diff --git a/Makefile.am b/Makefile.am index c0b3024..b384024 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,8 +18,152 @@ # You should have received a copy of the GNU General Public License # along with ODR-DabMod. If not, see . -SUBDIRS = src lib - ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = COPYING NEWS README.md AUTHORS ChangeLog TODO doc + +if IS_GIT_REPO +GITVERSION_FLAGS = -DGITVERSION="\"`git describe`\"" +else +GITVERSION_FLAGS = +endif + +if HAVE_SSE +SIMD_CFLAGS = -msse -msse2 +else +SIMD_CFLAGS = +endif + +bin_PROGRAMS = odr-dabmod + +FFT_DIR=lib/kiss_fft129 +FFT_LDADD= + +if USE_KISS_FFT +FFT_INC=-I$(FFT_DIR) -I$(FFT_DIR)/tools +FFT_FLG=-ffast-math + +.PHONY: lib/kiss_fft129 + +BUILT_SOURCES=lib/kiss_fft129 + +lib/kiss_fft129: + if [ ! -e lib/kiss_fft129/kiss_fft.c ]; then \ + tar xzf lib/kiss_fft129.tar.gz -C lib; \ + fi + +nodist_odr_dabmod_SOURCES = lib/kiss_fft129/kiss_fft.c \ + lib/kiss_fft129/kiss_fft.h \ + lib/kiss_fft129/tools/kiss_fftr.c \ + lib/kiss_fft129/tools/kiss_fftr.h \ + src/kiss_fftsimd.c \ + src/kiss_fftsimd.h + +clean-local: + rm -rf $(FFT_DIR) + +else +FFT_INC= +FFT_FLG= +endif + +odr_dabmod_CPPFLAGS = -Wall \ + $(FFT_INC) $(FFT_FLG) $(SIMD_CFLAGS) $(GITVERSION_FLAGS) +odr_dabmod_LDADD = $(FFT_LDADD) +odr_dabmod_SOURCES = src/DabMod.cpp \ + src/PcDebug.h \ + src/porting.c \ + src/porting.h \ + src/DabModulator.cpp \ + src/DabModulator.h \ + src/Buffer.cpp \ + src/Buffer.h \ + src/ModCodec.cpp \ + src/ModCodec.h \ + src/ModPlugin.cpp \ + src/ModPlugin.h \ + src/ModFormat.cpp \ + src/ModFormat.h \ + src/EtiReader.cpp \ + src/EtiReader.h \ + src/Eti.cpp \ + src/Eti.h \ + src/FicSource.cpp \ + src/FicSource.h \ + src/FIRFilter.cpp \ + src/FIRFilter.h \ + src/ModInput.cpp \ + src/ModInput.h \ + src/PuncturingRule.cpp \ + src/PuncturingRule.h \ + src/PuncturingEncoder.cpp \ + src/PuncturingEncoder.h \ + src/SubchannelSource.cpp \ + src/SubchannelSource.h \ + src/Flowgraph.cpp \ + src/Flowgraph.h \ + src/GainControl.cpp \ + src/GainControl.h \ + src/OutputMemory.cpp \ + src/OutputMemory.h \ + src/OutputZeroMQ.cpp \ + src/OutputZeroMQ.h \ + src/TimestampDecoder.h \ + src/TimestampDecoder.cpp \ + src/OutputUHD.cpp \ + src/OutputUHD.h \ + src/ModOutput.cpp \ + src/ModOutput.h \ + src/InputMemory.cpp \ + src/InputMemory.h \ + src/InputFileReader.cpp \ + src/InputZeroMQReader.cpp \ + src/InputReader.h \ + src/OutputFile.cpp \ + src/OutputFile.h \ + src/FrameMultiplexer.cpp \ + src/FrameMultiplexer.h \ + src/ModMux.cpp \ + src/ModMux.h \ + src/PrbsGenerator.cpp \ + src/PrbsGenerator.h \ + src/BlockPartitioner.cpp \ + src/BlockPartitioner.h \ + src/QpskSymbolMapper.cpp \ + src/QpskSymbolMapper.h \ + src/FrequencyInterleaver.cpp \ + src/FrequencyInterleaver.h \ + src/PhaseReference.cpp \ + src/PhaseReference.h \ + src/DifferentialModulator.cpp \ + src/DifferentialModulator.h \ + src/NullSymbol.cpp \ + src/NullSymbol.h \ + src/SignalMultiplexer.cpp \ + src/SignalMultiplexer.h \ + src/CicEqualizer.cpp \ + src/CicEqualizer.h \ + src/OfdmGenerator.cpp \ + src/OfdmGenerator.h \ + src/GuardIntervalInserter.cpp \ + src/GuardIntervalInserter.h \ + src/Resampler.cpp \ + src/Resampler.h \ + src/ConvEncoder.cpp \ + src/ConvEncoder.h \ + src/TimeInterleaver.cpp \ + src/TimeInterleaver.h \ + src/ThreadsafeQueue.h \ + src/Log.cpp \ + src/Log.h \ + src/RemoteControl.cpp \ + src/RemoteControl.h \ + src/FormatConverter.cpp \ + src/FormatConverter.h \ + src/zmq.hpp + +dist_bin_SCRIPTS = src/crc-dwap.py + +EXTRA_DIST += lib/kiss_fft129.tar.gz +EXTRA_DIST += src/kiss_fftsimd.c src/kiss_fftsimd.h + diff --git a/configure.ac b/configure.ac index 3f21f89..a73ee39 100644 --- a/configure.ac +++ b/configure.ac @@ -21,8 +21,9 @@ AC_PREREQ(2.59) AC_INIT([ODR-DabMod], [0.5.1], [matthias.braendli@mpb.li]) AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE([-Wall foreign]) +AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) AC_CONFIG_SRCDIR([src/DabMod.cpp]) AM_CONFIG_HEADER([config.h]) AM_SILENT_RULES([yes]) @@ -186,9 +187,7 @@ AM_CONDITIONAL([HAVE_SSE], [test "x$has_sse" = "xyes"]) AC_TYPE_SIGNAL AC_CHECK_FUNCS([bzero floor ftime gettimeofday memset sqrt strchr strerror strtol]) -AC_CONFIG_FILES([Makefile - lib/Makefile - src/Makefile]) +AC_CONFIG_FILES([Makefile]) AC_OUTPUT echo diff --git a/lib/Makefile.am b/lib/Makefile.am deleted file mode 100644 index c37fb46..0000000 --- a/lib/Makefile.am +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (C) 2008, 2009 Her Majesty the Queen in Right of Canada -# (Communications Research Center Canada) - -# This file is part of ODR-DabMod. -# -# ODR-DabMod is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# ODR-DabMod is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with ODR-DabMod. If not, see . - -EXTRA_DIST =kiss_fft129.tar.gz diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index f8ba7c2..0000000 --- a/src/Makefile.am +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Her Majesty the -# Queen in Right of Canada (Communications Research Center Canada) - -# This file is part of ODR-DabMod. -# -# ODR-DabMod is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# ODR-DabMod is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with ODR-DabMod. If not, see . - -if IS_GIT_REPO -GITVERSION_FLAGS = -DGITVERSION="\"`git describe`\"" -else -GITVERSION_FLAGS = -endif - -if HAVE_SSE -SIMD_CFLAGS = -msse -msse2 -else -SIMD_CFLAGS = -endif - -bin_PROGRAMS = odr-dabmod - -if USE_KISS_FFT -FFT_DIR=$(top_builddir)/lib/kiss_fft129 -FFT_INC=-I$(FFT_DIR) -I$(FFT_DIR)/tools -FFT_SRC=$(FFT_DIR)/kiss_fft.c \ - $(FFT_DIR)/kiss_fft.h \ - $(FFT_DIR)/tools/kiss_fftr.c \ - $(FFT_DIR)/tools/kiss_fftr.h \ - kiss_fftsimd.c \ - kiss_fftsimd.h -FFT_FLG=-ffast-math - -.PHONY: kiss_fft129 reed-solomon-4.0 - -DabModulator.cpp: $(FFT_DIR) - -BUILT_SOURCES: $(FFT_DIR) - -FFT_LDADD= - -$(FFT_DIR): - if [ ! -e $(FFT_DIR) ]; then \ - tar xzf $(top_srcdir)/lib/kiss_fft129.tar.gz -C $(top_builddir)/lib; \ - fi - -else -FFT_LDADD= -FFT_DIR= -FFT_INC= -FFT_SRC= -FFT_FLG= -endif - -odr_dabmod_CPPFLAGS = -Wall \ - $(FFT_INC) $(FFT_FLG) $(SIMD_CFLAGS) $(GITVERSION_FLAGS) -odr_dabmod_LDADD = $(FFT_LDADD) -odr_dabmod_SOURCES = DabMod.cpp \ - PcDebug.h \ - porting.c porting.h \ - DabModulator.cpp DabModulator.h \ - Buffer.cpp Buffer.h \ - ModCodec.cpp ModCodec.h \ - ModPlugin.cpp ModPlugin.h \ - ModFormat.cpp ModFormat.h \ - EtiReader.cpp EtiReader.h \ - Eti.cpp Eti.h \ - FicSource.cpp FicSource.h \ - FIRFilter.cpp FIRFilter.h \ - ModInput.cpp ModInput.h \ - PuncturingRule.cpp PuncturingRule.h \ - PuncturingEncoder.cpp PuncturingEncoder.h \ - SubchannelSource.cpp SubchannelSource.h \ - Flowgraph.cpp Flowgraph.h \ - GainControl.cpp GainControl.h \ - OutputMemory.cpp OutputMemory.h \ - OutputZeroMQ.cpp OutputZeroMQ.h \ - TimestampDecoder.h TimestampDecoder.cpp \ - OutputUHD.cpp OutputUHD.h \ - ModOutput.cpp ModOutput.h \ - InputMemory.cpp InputMemory.h \ - InputFileReader.cpp InputZeroMQReader.cpp InputReader.h \ - OutputFile.cpp OutputFile.h \ - FrameMultiplexer.cpp FrameMultiplexer.h \ - ModMux.cpp ModMux.h \ - PrbsGenerator.cpp PrbsGenerator.h \ - BlockPartitioner.cpp BlockPartitioner.h \ - QpskSymbolMapper.cpp QpskSymbolMapper.h \ - FrequencyInterleaver.cpp FrequencyInterleaver.h \ - PhaseReference.cpp PhaseReference.h \ - DifferentialModulator.cpp DifferentialModulator.h \ - NullSymbol.cpp NullSymbol.h \ - SignalMultiplexer.cpp SignalMultiplexer.h \ - CicEqualizer.cpp CicEqualizer.h \ - OfdmGenerator.cpp OfdmGenerator.h \ - GuardIntervalInserter.cpp GuardIntervalInserter.h \ - Resampler.cpp Resampler.h \ - ConvEncoder.cpp ConvEncoder.h \ - TimeInterleaver.cpp TimeInterleaver.h \ - ThreadsafeQueue.h \ - Log.cpp Log.h \ - RemoteControl.cpp RemoteControl.h \ - FormatConverter.cpp FormatConverter.h \ - zmq.hpp - -nodist_odr_dabmod_SOURCES = $(FFT_SRC) - -dist_bin_SCRIPTS = crc-dwap.py - -if USE_KISS_FFT -EXTRA_DIST = kiss_fftsimd.c kiss_fftsimd.h - -clean-local: - rm -rf $(FFT_DIR) - -endif - -- cgit v1.2.3 From 52f695a63a74c36a0f2d1f74a0af20cba095ee1e Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Thu, 5 Feb 2015 17:59:09 +0100 Subject: doc: change wiki link --- doc/example.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/example.ini b/doc/example.ini index 43adacb..cec0f23 100644 --- a/doc/example.ini +++ b/doc/example.ini @@ -150,7 +150,7 @@ txgain=2.0 ; For the B200 ; More information and measurements available on: -; http://opendigitalradio.org/index.php/USRP_B200_Measurements +; http://wiki.opendigitalradio.org/index.php/USRP_B200_Measurements ; ; Settings: ;device= -- cgit v1.2.3 From 1f7576701b54bf83d600780483017457841e830b Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Thu, 5 Feb 2015 19:22:50 +0100 Subject: Add -Isrc to CPPFLAGS --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index b384024..3f5d639 100644 --- a/Makefile.am +++ b/Makefile.am @@ -67,7 +67,7 @@ FFT_INC= FFT_FLG= endif -odr_dabmod_CPPFLAGS = -Wall \ +odr_dabmod_CPPFLAGS = -Wall -Isrc \ $(FFT_INC) $(FFT_FLG) $(SIMD_CFLAGS) $(GITVERSION_FLAGS) odr_dabmod_LDADD = $(FFT_LDADD) odr_dabmod_SOURCES = src/DabMod.cpp \ -- cgit v1.2.3 From e8e7350db3bbf1d408ca4b305329c17d545c91eb Mon Sep 17 00:00:00 2001 From: Jörgen Scott Date: Mon, 9 Feb 2015 10:17:01 +0100 Subject: Bug fix for static delay --- src/OutputUHD.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index 91c030f..3845439 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -341,7 +341,7 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) myEtiReader->sourceContainsTimestamp(); // calculate delay - uint32_t noSampleDelay = (myStaticDelayUs * myConf.sampleRate / 1000) / 1000; + uint32_t noSampleDelay = (myStaticDelayUs * (myConf.sampleRate / 1000)) / 1000; uint32_t noByteDelay = noSampleDelay * sizeof(complexf); uint8_t* pInData = (uint8_t*) dataIn->getData(); @@ -690,10 +690,10 @@ void OutputUHD::set_parameter(const string& parameter, const string& value) int adjust; ss >> adjust; int newStaticDelayUs = myStaticDelayUs + adjust; - if (newStaticDelayUs > myTFDurationMs * 1000) - myStaticDelayUs = newStaticDelayUs - myTFDurationMs * 1000; + if (newStaticDelayUs > (myTFDurationMs * 1000)) + myStaticDelayUs = newStaticDelayUs - (myTFDurationMs * 1000); else if (newStaticDelayUs < 0) - myStaticDelayUs = newStaticDelayUs + myTFDurationMs * 1000; + myStaticDelayUs = newStaticDelayUs + (myTFDurationMs * 1000); else myStaticDelayUs = newStaticDelayUs; } -- cgit v1.2.3 From 413aeff4088a1d5adadf07cb1833091a197dc393 Mon Sep 17 00:00:00 2001 From: Jörgen Scott Date: Mon, 9 Feb 2015 12:42:00 +0100 Subject: added reset for static delay --- src/OutputUHD.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index 3845439..bfd24a8 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -269,7 +269,6 @@ void OutputUHD::SetDelayBuffer(unsigned int dabMode) default: throw std::runtime_error("OutPutUHD: invalid DAB mode"); } - fprintf(stderr, "DelayBuf = %d\n", myTFDurationMs * myConf.sampleRate / 1000); // The buffer size equals the number of samples per transmission frame so // we calculate it by multiplying the duration of the transmission frame // with the samplerate. @@ -687,15 +686,23 @@ void OutputUHD::set_parameter(const string& parameter, const string& value) ss >> myMuting; } else if (parameter == "staticdelay") { - int adjust; + int64_t adjust; ss >> adjust; - int newStaticDelayUs = myStaticDelayUs + adjust; - if (newStaticDelayUs > (myTFDurationMs * 1000)) - myStaticDelayUs = newStaticDelayUs - (myTFDurationMs * 1000); - else if (newStaticDelayUs < 0) - myStaticDelayUs = newStaticDelayUs + (myTFDurationMs * 1000); - else - myStaticDelayUs = newStaticDelayUs; + if (adjust > (myTFDurationMs * 1000)) + { // reset static delay for values outside range + myStaticDelayUs = 0; + } + else + { // the new adjust value is added to the existing delay and the result + // is wrapped around at TF duration + int newStaticDelayUs = myStaticDelayUs + adjust; + if (newStaticDelayUs > (myTFDurationMs * 1000)) + myStaticDelayUs = newStaticDelayUs - (myTFDurationMs * 1000); + else if (newStaticDelayUs < 0) + myStaticDelayUs = newStaticDelayUs + (myTFDurationMs * 1000); + else + myStaticDelayUs = newStaticDelayUs; + } } else if (parameter == "iqbalance") { ss >> myConf.frequency; -- cgit v1.2.3 From ebdd156e45a520c67201c0382b1971e39bb25b72 Mon Sep 17 00:00:00 2001 From: Jörgen Scott Date: Mon, 9 Feb 2015 12:45:21 +0100 Subject: Added c++ client API --- doc/zmq-ctrl/cpp/OdrModCtrl.cpp | 306 +++++++++++++++++++++++++++++++++++ doc/zmq-ctrl/cpp/OdrModCtrl.hpp | 86 ++++++++++ doc/zmq-ctrl/cpp/test/CMakeLists.txt | 31 ++++ doc/zmq-ctrl/cpp/test/README | 14 ++ doc/zmq-ctrl/cpp/test/ctrl_test.cpp | 88 ++++++++++ 5 files changed, 525 insertions(+) create mode 100644 doc/zmq-ctrl/cpp/OdrModCtrl.cpp create mode 100644 doc/zmq-ctrl/cpp/OdrModCtrl.hpp create mode 100755 doc/zmq-ctrl/cpp/test/CMakeLists.txt create mode 100644 doc/zmq-ctrl/cpp/test/README create mode 100644 doc/zmq-ctrl/cpp/test/ctrl_test.cpp diff --git a/doc/zmq-ctrl/cpp/OdrModCtrl.cpp b/doc/zmq-ctrl/cpp/OdrModCtrl.cpp new file mode 100644 index 0000000..9b3f8dd --- /dev/null +++ b/doc/zmq-ctrl/cpp/OdrModCtrl.cpp @@ -0,0 +1,306 @@ +/*! + * This is an implementation for the zmq ctrl API of the odr-dabmod. + * + * Copyright (c) 2015 by Jörgen Scott (jorgen.scott@paneda.se) + * + * ODR-DabMod is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ODR-DabMod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ODR-DabMod. If not, see . + * + * \code + * #include "OdrModCtrl.hpp" + * #include + * ... + * zmq::context_t ctx; + * std::string error; + * COdrModCtrl *pCtrl = new COdrModCtrl(&context, // zmq context + * "tcp://127.0.0.1:9400", // zmq endpoint + * 1000); // timeout in milliseconds + * if (pCtrl->SetTxGain(50, error)) + * std::cout << "Tx gain set to 50" << std::endl; + * else + * std::cout << "An error occured: " << error << std::endl; + * delete pCtrl; // destructor will close zmq socket + * + * \endcode + **/ +#include "OdrModCtrl.hpp" +#include + +COdrModCtrl::COdrModCtrl(zmq::context_t *pContext, std::string odrEndpoint, + unsigned int timeoutMs) +{ + m_pContext = pContext; + m_odrEndpoint = odrEndpoint; + m_timeoutMs = (uint32_t) timeoutMs; +} + +COdrModCtrl::~COdrModCtrl() +{ + if (m_pReqSocket != NULL) + { + m_pReqSocket->close(); + delete m_pReqSocket; + } +} + +//// public get methods ///////////////////////////////////////////////////////// +bool COdrModCtrl::GetDigitalGain(double &gain, std::string &error) +{ + return DoGet("gain", "digital", gain, error); +} + +bool COdrModCtrl::GetTxGain(double &gain, std::string &error) +{ + return DoGet("uhd", "txgain", gain, error); +} + +bool COdrModCtrl::GetTxFrequency(double &freqHz, std::string &error) +{ + return DoGet("uhd", "freq", freqHz, error); +} + +bool COdrModCtrl::GetMuting(bool &mute, std::string &error) +{ + return DoGet("uhd", "muting", (uint32_t&) mute, error); +} + +bool COdrModCtrl::GetStaticDelay(uint32_t &delayUs, std::string &error) +{ + return DoGet("uhd", "staticdelay", delayUs, error); +} + + +//// public set methods ///////////////////////////////////////////////////////// + +bool COdrModCtrl::SetDigitalGain(const double gain, std::string &error) +{ + return DoSet("gain", "digital", gain, error); +} + +bool COdrModCtrl::SetTxGain(const double gain, std::string &error) +{ + return DoSet("uhd", "txgain", gain, error); +} + +bool COdrModCtrl::SetTxFrequency(const double freqHz, std::string &error) +{ + return DoSet("uhd", "freq", freqHz, error); +} + +bool COdrModCtrl::SetMuting(const bool mute, std::string &error) +{ + return DoSet("uhd", "muting", mute, error); +} + +bool COdrModCtrl::SetStaticDelay(const uint32_t delayUs, std::string &error) +{ + return DoSet("uhd", "staticdelay", delayUs, error); +} + + +//// private methods //////////////////////////////////////////////////////////// + +template +bool COdrModCtrl::DoSet(const std::string module, const std::string parameter, + const Type value, std::string &error) +{ + if (m_pReqSocket == NULL) + { + m_pReqSocket = new zmq::socket_t(*m_pContext, ZMQ_REQ); + if (!ConnectSocket(m_pReqSocket, m_odrEndpoint, error)) + return false; + } + + std::vector msg; + msg.push_back("set"); + msg.push_back(module); + msg.push_back(parameter); + std::stringstream ss; + ss << value; + msg.push_back(ss.str()); + + // send the message + if (!SendMessage(m_pReqSocket, msg, error)) + { + // destroy the socket according to the "Lazy Pirate Pattern" in + // the zmq guide + m_pReqSocket->close(); + delete m_pReqSocket; + m_pReqSocket = NULL; + return false; + } + + // wait for reply + if (!RecvAll(m_pReqSocket, msg, m_timeoutMs, error)) + return false; + + return ParseSetReply(msg, error); +} + +bool COdrModCtrl::ParseSetReply(const std::vector &msg, + std::string &error) +{ + error = ""; + if (msg.size() < 1) + error = "Bad reply format"; + else if (msg.size() == 1 && msg[0] == "ok") + return true; + else if (msg.size() == 2 && msg[0] == "fail") + { + error = msg[1]; + return false; + } + else + { + error = "Bad reply format"; + return false; + } +} + +template +bool COdrModCtrl::DoGet(const std::string module, const std::string parameter, + Type &value, std::string &error) +{ + if (m_pReqSocket == NULL) + { + m_pReqSocket = new zmq::socket_t(*m_pContext, ZMQ_REQ); + if (!ConnectSocket(m_pReqSocket, m_odrEndpoint, error)) + return false; + } + + std::vector msg; + msg.push_back("get"); + msg.push_back(module); + msg.push_back(parameter); + + // send the message + if (!SendMessage(m_pReqSocket, msg, error)) + { + // destroy the socket according to the "Lazy Pirate Pattern" + // in the zmq guide + m_pReqSocket->close(); + delete m_pReqSocket; + m_pReqSocket = NULL; + return false; + } + + // wait for reply + if (!RecvAll(m_pReqSocket, msg, m_timeoutMs, error)) + return false; + + return ParseGetReply(msg, value, error); +} + +template +bool COdrModCtrl::ParseGetReply(const std::vector &msg, + Type &value, std::string &error) +{ + error = ""; + if (msg.size() < 1) + error = "Bad reply format"; + else if (msg.size() == 1) + { + std::stringstream ss(msg[0]); + ss >> value; + return true; + } + else if (msg.size() == 2 && msg[0] == "fail") + { + error = msg[1]; + return false; + } + else + { + error = "Bad reply format"; + return false; + } +} + +bool COdrModCtrl::ConnectSocket(zmq::socket_t *pSocket, const std::string endpoint, + std::string &error) +{ + error = ""; + try + { + int hwm = 1; + int linger = 0; + pSocket->setsockopt(ZMQ_RCVHWM, &hwm, sizeof(hwm)); + pSocket->setsockopt(ZMQ_SNDHWM, &hwm, sizeof(hwm)); + pSocket->setsockopt(ZMQ_LINGER, &linger, sizeof(linger)); + pSocket->connect(endpoint.c_str()); + return true; + } + catch(zmq::error_t &ex) + { + error = "Failed to connect: " + endpoint + + std::string(". ZMQ: " + std::string(ex.what())); + return false; + } +} + +bool COdrModCtrl::SendMessage(zmq::socket_t* pSocket, + const std::vector &message, std::string &error) +{ + error = ""; + try + { + std::vector::size_type i = 0; + for ( ; i < message.size() - 1; i++) + { + zmq::message_t zmqMsg(message[i].length()); + memcpy ((void*) zmqMsg.data(), message[i].data(), message[i].length()); + pSocket->send(zmqMsg, ZMQ_SNDMORE); + } + zmq::message_t zmqMsg(message[i].length()); + memcpy ((void*) zmqMsg.data(), message[i].data(), message[i].length()); + pSocket->send(zmqMsg, 0); + return true; + } + catch(zmq::error_t &ex) + { + error = "ZMQ send error: " + std::string(ex.what()); + return false; + } +} + +bool COdrModCtrl::RecvAll(zmq::socket_t* pSocket, + std::vector &message, unsigned int timeoutMs, + std::string &error) +{ + error = ""; + message.clear(); + + int more = -1; + size_t more_size = sizeof(more); + zmq::pollitem_t pollItems[] = { {*pSocket, 0, ZMQ_POLLIN, 0} }; + zmq::poll(&pollItems[0], 1, timeoutMs); + + while (more != 0) + { + if (pollItems[0].revents & ZMQ_POLLIN) + { + zmq::message_t msg; + pSocket->recv(&msg); + message.push_back(std::string((char*)msg.data(), msg.size())); + pSocket->getsockopt(ZMQ_RCVMORE, &more, &more_size); + } + else + { + error = "Receive timeout"; + return false; + } + } + + return true; +} + diff --git a/doc/zmq-ctrl/cpp/OdrModCtrl.hpp b/doc/zmq-ctrl/cpp/OdrModCtrl.hpp new file mode 100644 index 0000000..0651311 --- /dev/null +++ b/doc/zmq-ctrl/cpp/OdrModCtrl.hpp @@ -0,0 +1,86 @@ +/** + * This is an interface for the zmq ctrl API of the odr-dabmod. + * The class is intended for clients that wish to control the odr-mod. + * + * Copyright (c) 2015 by Jörgen Scott (jorgen.scott@paneda.se) + * + * ODR-DabMod is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ODR-DabMod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ODR-DabMod. If not, see . + **/ +#pragma once + +#include +#include +#include +#include + +class COdrModCtrl +{ + public: + // ctors + COdrModCtrl(zmq::context_t *pContext, std::string odrEndpoint, + unsigned int timeoutMs); + virtual ~COdrModCtrl(); + + // All methods return true if successful, when false check the error + // string. + // + // IMPORTANT! All methods must be accessed from the same thread. + // + // For a detailed description of the various parameters, see + // example.ini. + virtual bool GetDigitalGain(double &gain, std::string &error); + virtual bool GetTxGain(double &gain, std::string &error); + virtual bool GetTxFrequency(double &freqHz, std::string &error); + virtual bool GetMuting(bool &mute, std::string &error); + virtual bool GetStaticDelay(uint32_t &delayUs, std::string &error); + + virtual bool SetDigitalGain(const double gain, std::string &error); + virtual bool SetTxGain(const double gain, std::string &error); + virtual bool SetTxFrequency(const double freqHz, std::string &error); + virtual bool SetMuting(const bool mute, std::string &error); + virtual bool SetStaticDelay(const uint32_t delayUs, std::string &error); + + private: + // methods + + template + bool DoSet(const std::string module, const std::string parameter, + const Type value, std::string &error); + + bool ParseSetReply(const std::vector &msg, std::string &error); + + template + bool DoGet(const std::string module, const std::string parameter, + Type &value, std::string &error); + + template + bool ParseGetReply(const std::vector &msg, Type &value, + std::string &error); + + bool ConnectSocket(zmq::socket_t *pSocket, const std::string endpoint, + std::string &error); + + bool SendMessage(zmq::socket_t* pSocket, + const std::vector &message, std::string &error); + + bool RecvAll(zmq::socket_t* pSocket, + std::vector &message, unsigned int timeoutMs, + std::string &error); + + // data + zmq::context_t *m_pContext; + std::string m_odrEndpoint; + uint32_t m_timeoutMs; + zmq::socket_t *m_pReqSocket; +}; diff --git a/doc/zmq-ctrl/cpp/test/CMakeLists.txt b/doc/zmq-ctrl/cpp/test/CMakeLists.txt new file mode 100755 index 0000000..4b877d0 --- /dev/null +++ b/doc/zmq-ctrl/cpp/test/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 2.6) +project (ctrl_test) + +ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK -D_SCL_SECURE_NO_WARNINGS) + +set(BOOST_LIBRARYDIR) +set(BOOST_INCLUDEDIR) +set(BOOST_USE_MULTITHREADED ON) +set(BOOST_USE_STATIC_LIBS ON) +set(BOOST_MIN_VERSION 1.55) + +find_package( Boost ${BOOST_MIN_VERSION} REQUIRED + unit_test_framework + system + ) + +set(PROJECT_TEST_SRCS +${CMAKE_CURRENT_SOURCE_DIR}/ctrl_test.cpp +${CMAKE_CURRENT_SOURCE_DIR}/../OdrModCtrl.cpp +) + +include_directories( ${PROJECT_SOURCE_DIR}/../ ) +link_directories (/usr/local/lib) +add_executable(${PROJECT_NAME} ${PROJECT_TEST_SRCS}) + +target_link_libraries(${PROJECT_NAME} + zmq + ${Boost_LIBRARIES} + ) + +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") diff --git a/doc/zmq-ctrl/cpp/test/README b/doc/zmq-ctrl/cpp/test/README new file mode 100644 index 0000000..76a1188 --- /dev/null +++ b/doc/zmq-ctrl/cpp/test/README @@ -0,0 +1,14 @@ +Instructions for zmq ctrl api test program + +Dependencies boost, zmq (and cpp binding through zmq.hpp) + +Build instruction (make sure your in the directory of this file) +* mkdir build +* cd build +* cmake ../ +* make + +Run +* make sure the ODR-DABMOD is started and that zmq ctrl api is enabled +* make sure the zmq endpoint matches (see ctrl_test.cpp) +* run the ctrl_test diff --git a/doc/zmq-ctrl/cpp/test/ctrl_test.cpp b/doc/zmq-ctrl/cpp/test/ctrl_test.cpp new file mode 100644 index 0000000..3c38c89 --- /dev/null +++ b/doc/zmq-ctrl/cpp/test/ctrl_test.cpp @@ -0,0 +1,88 @@ +/** + * This is a test program for the zmq ctrl API of the odr-dabmod. + * + * Copyright (c) 2015 by Jörgen Scott (jorgen.scott@paneda.se) + + * This file is part of CtrlTest. + * + * ODR-DabMod is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ODR-DabMod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ODR-DabMod. If not, see . + **/ +#define BOOST_TEST_MODULE "C++ unit tests for odr-mod zmq ctrl" +#include +#include "OdrModCtrl.hpp" + + +// Variables used in the test suite +struct TemplateVars +{ + std::string error; + zmq::context_t context; + COdrModCtrl modCtrl; + + // NOTE: Make sure the odr-dabmod is started before running the test and + // that the zmq endpoint matches. + TemplateVars() : context(1), modCtrl(&context, "tcp://127.0.0.1:9400", 1000) {} + ~TemplateVars() {} +}; + +// Note. The odr-mod do not validate parameters therefore there are no tests +// made for setting invalid parameters. +BOOST_FIXTURE_TEST_SUITE(test_template1, TemplateVars) + +BOOST_AUTO_TEST_CASE (DigitalGain) +{ + BOOST_CHECK(modCtrl.SetDigitalGain(0.5, error) == true); + double value; + BOOST_CHECK(modCtrl.GetDigitalGain(value, error) == true); + BOOST_CHECK(value == 0.5); +} + +BOOST_AUTO_TEST_CASE (TxGain) +{ + BOOST_CHECK(modCtrl.SetTxGain(50, error) == true); + double value; + BOOST_CHECK(modCtrl.GetTxGain(value, error) == true); + BOOST_CHECK(value == 50); +} + +BOOST_AUTO_TEST_CASE (TxFrequency) +{ + BOOST_CHECK(modCtrl.SetTxFrequency(234208000, error) == true); + double value; + BOOST_CHECK(modCtrl.GetTxFrequency(value, error) == true); + BOOST_CHECK(value == 234208000); +} + +BOOST_AUTO_TEST_CASE (Muting) +{ + BOOST_CHECK(modCtrl.SetMuting(true, error) == true); + bool value; + BOOST_CHECK(modCtrl.GetMuting(value, error) == true); + BOOST_CHECK(value == true); + BOOST_CHECK(modCtrl.SetMuting(false, error) == true); +} + +BOOST_AUTO_TEST_CASE (StaticDelay) +{ + // reset first or else test will fail on successive calls + BOOST_CHECK(modCtrl.SetStaticDelay(-1, error) == true); + BOOST_CHECK(modCtrl.SetStaticDelay(45000, error) == true); + uint32_t value; + BOOST_CHECK(modCtrl.GetStaticDelay(value, error) == true); + BOOST_CHECK(value == 45000); +} + + +BOOST_AUTO_TEST_SUITE_END() + -- cgit v1.2.3 From b31494c688ad93f2c09688a9061c7d392c6844a7 Mon Sep 17 00:00:00 2001 From: Jörgen Scott Date: Mon, 9 Feb 2015 13:36:22 +0100 Subject: added ping method + some cleaning --- doc/zmq-ctrl/cpp/OdrModCtrl.cpp | 60 ++++++++++++++++++++++++++++++------- doc/zmq-ctrl/cpp/OdrModCtrl.hpp | 1 + doc/zmq-ctrl/cpp/test/ctrl_test.cpp | 7 ++++- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/doc/zmq-ctrl/cpp/OdrModCtrl.cpp b/doc/zmq-ctrl/cpp/OdrModCtrl.cpp index 9b3f8dd..cd48fd1 100644 --- a/doc/zmq-ctrl/cpp/OdrModCtrl.cpp +++ b/doc/zmq-ctrl/cpp/OdrModCtrl.cpp @@ -36,6 +36,15 @@ #include "OdrModCtrl.hpp" #include +#define MOD_GAIN "gain" +#define MOD_UHD "uhd" + +#define PARAM_DIG_GAIN "digital" +#define PARAM_TX_GAIN "txgain" +#define PARAM_FREQ "freq" +#define PARAM_MUTE "muting" +#define PARAM_STAT_DELAY "staticdelay" + COdrModCtrl::COdrModCtrl(zmq::context_t *pContext, std::string odrEndpoint, unsigned int timeoutMs) { @@ -56,55 +65,86 @@ COdrModCtrl::~COdrModCtrl() //// public get methods ///////////////////////////////////////////////////////// bool COdrModCtrl::GetDigitalGain(double &gain, std::string &error) { - return DoGet("gain", "digital", gain, error); + return DoGet(MOD_GAIN, PARAM_DIG_GAIN, gain, error); } bool COdrModCtrl::GetTxGain(double &gain, std::string &error) { - return DoGet("uhd", "txgain", gain, error); + return DoGet(MOD_UHD, PARAM_TX_GAIN, gain, error); } bool COdrModCtrl::GetTxFrequency(double &freqHz, std::string &error) { - return DoGet("uhd", "freq", freqHz, error); + return DoGet(MOD_UHD, PARAM_FREQ, freqHz, error); } bool COdrModCtrl::GetMuting(bool &mute, std::string &error) { - return DoGet("uhd", "muting", (uint32_t&) mute, error); + return DoGet(MOD_UHD, PARAM_MUTE, (uint32_t&) mute, error); } bool COdrModCtrl::GetStaticDelay(uint32_t &delayUs, std::string &error) { - return DoGet("uhd", "staticdelay", delayUs, error); + return DoGet(MOD_UHD, PARAM_STAT_DELAY, delayUs, error); } //// public set methods ///////////////////////////////////////////////////////// +bool COdrModCtrl::Ping() +{ + std::string error; + if (m_pReqSocket == NULL) + { + m_pReqSocket = new zmq::socket_t(*m_pContext, ZMQ_REQ); + if (!ConnectSocket(m_pReqSocket, m_odrEndpoint, error)) + return false; + } + + std::vector msg; + msg.push_back("ping"); + + // send the message + if (!SendMessage(m_pReqSocket, msg, error)) + { + // destroy the socket according to the "Lazy Pirate Pattern" in + // the zmq guide + m_pReqSocket->close(); + delete m_pReqSocket; + m_pReqSocket = NULL; + return false; + } + + // wait for reply + if (!RecvAll(m_pReqSocket, msg, m_timeoutMs, error)) + return false; + + return true; +} + bool COdrModCtrl::SetDigitalGain(const double gain, std::string &error) { - return DoSet("gain", "digital", gain, error); + return DoSet(MOD_GAIN, PARAM_DIG_GAIN, gain, error); } bool COdrModCtrl::SetTxGain(const double gain, std::string &error) { - return DoSet("uhd", "txgain", gain, error); + return DoSet(MOD_UHD, PARAM_TX_GAIN, gain, error); } bool COdrModCtrl::SetTxFrequency(const double freqHz, std::string &error) { - return DoSet("uhd", "freq", freqHz, error); + return DoSet(MOD_UHD, PARAM_FREQ, freqHz, error); } bool COdrModCtrl::SetMuting(const bool mute, std::string &error) { - return DoSet("uhd", "muting", mute, error); + return DoSet(MOD_UHD, PARAM_MUTE, mute, error); } bool COdrModCtrl::SetStaticDelay(const uint32_t delayUs, std::string &error) { - return DoSet("uhd", "staticdelay", delayUs, error); + return DoSet(MOD_UHD, PARAM_STAT_DELAY, delayUs, error); } diff --git a/doc/zmq-ctrl/cpp/OdrModCtrl.hpp b/doc/zmq-ctrl/cpp/OdrModCtrl.hpp index 0651311..8b40666 100644 --- a/doc/zmq-ctrl/cpp/OdrModCtrl.hpp +++ b/doc/zmq-ctrl/cpp/OdrModCtrl.hpp @@ -39,6 +39,7 @@ class COdrModCtrl // // For a detailed description of the various parameters, see // example.ini. + virtual bool Ping(void); virtual bool GetDigitalGain(double &gain, std::string &error); virtual bool GetTxGain(double &gain, std::string &error); virtual bool GetTxFrequency(double &freqHz, std::string &error); diff --git a/doc/zmq-ctrl/cpp/test/ctrl_test.cpp b/doc/zmq-ctrl/cpp/test/ctrl_test.cpp index 3c38c89..21811d6 100644 --- a/doc/zmq-ctrl/cpp/test/ctrl_test.cpp +++ b/doc/zmq-ctrl/cpp/test/ctrl_test.cpp @@ -40,6 +40,11 @@ struct TemplateVars // made for setting invalid parameters. BOOST_FIXTURE_TEST_SUITE(test_template1, TemplateVars) +BOOST_AUTO_TEST_CASE (Ping) +{ + BOOST_CHECK(modCtrl.Ping() == true); +} + BOOST_AUTO_TEST_CASE (DigitalGain) { BOOST_CHECK(modCtrl.SetDigitalGain(0.5, error) == true); @@ -75,7 +80,7 @@ BOOST_AUTO_TEST_CASE (Muting) BOOST_AUTO_TEST_CASE (StaticDelay) { - // reset first or else test will fail on successive calls + // reset first or else test will fail on successive runs BOOST_CHECK(modCtrl.SetStaticDelay(-1, error) == true); BOOST_CHECK(modCtrl.SetStaticDelay(45000, error) == true); uint32_t value; -- cgit v1.2.3 From 958e286699348c1c2110155efd2a1682fb6a1ac4 Mon Sep 17 00:00:00 2001 From: Jörgen Scott Date: Mon, 9 Feb 2015 15:54:45 +0100 Subject: changed static delay parameter type --- doc/zmq-ctrl/cpp/OdrModCtrl.cpp | 2 +- doc/zmq-ctrl/cpp/OdrModCtrl.hpp | 2 +- doc/zmq-ctrl/cpp/test/ctrl_test.cpp | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/zmq-ctrl/cpp/OdrModCtrl.cpp b/doc/zmq-ctrl/cpp/OdrModCtrl.cpp index cd48fd1..731a9af 100644 --- a/doc/zmq-ctrl/cpp/OdrModCtrl.cpp +++ b/doc/zmq-ctrl/cpp/OdrModCtrl.cpp @@ -142,7 +142,7 @@ bool COdrModCtrl::SetMuting(const bool mute, std::string &error) return DoSet(MOD_UHD, PARAM_MUTE, mute, error); } -bool COdrModCtrl::SetStaticDelay(const uint32_t delayUs, std::string &error) +bool COdrModCtrl::SetStaticDelay(const int32_t delayUs, std::string &error) { return DoSet(MOD_UHD, PARAM_STAT_DELAY, delayUs, error); } diff --git a/doc/zmq-ctrl/cpp/OdrModCtrl.hpp b/doc/zmq-ctrl/cpp/OdrModCtrl.hpp index 8b40666..e343710 100644 --- a/doc/zmq-ctrl/cpp/OdrModCtrl.hpp +++ b/doc/zmq-ctrl/cpp/OdrModCtrl.hpp @@ -50,7 +50,7 @@ class COdrModCtrl virtual bool SetTxGain(const double gain, std::string &error); virtual bool SetTxFrequency(const double freqHz, std::string &error); virtual bool SetMuting(const bool mute, std::string &error); - virtual bool SetStaticDelay(const uint32_t delayUs, std::string &error); + virtual bool SetStaticDelay(const int32_t delayUs, std::string &error); private: // methods diff --git a/doc/zmq-ctrl/cpp/test/ctrl_test.cpp b/doc/zmq-ctrl/cpp/test/ctrl_test.cpp index 21811d6..fdfd35a 100644 --- a/doc/zmq-ctrl/cpp/test/ctrl_test.cpp +++ b/doc/zmq-ctrl/cpp/test/ctrl_test.cpp @@ -80,8 +80,9 @@ BOOST_AUTO_TEST_CASE (Muting) BOOST_AUTO_TEST_CASE (StaticDelay) { - // reset first or else test will fail on successive runs - BOOST_CHECK(modCtrl.SetStaticDelay(-1, error) == true); + // reset first (by setting out of range value) or else test + // will fail on successive runs + BOOST_CHECK(modCtrl.SetStaticDelay(100000, error) == true); BOOST_CHECK(modCtrl.SetStaticDelay(45000, error) == true); uint32_t value; BOOST_CHECK(modCtrl.GetStaticDelay(value, error) == true); -- cgit v1.2.3 From 277d29a529c37a8fe59883291e43db8ff8831b22 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Thu, 12 Feb 2015 10:20:54 +0100 Subject: indentation --- src/DabMod.cpp | 2 +- src/OutputUHD.cpp | 85 ++++++++++++++++++++++++++++--------------------------- src/OutputUHD.h | 9 +++--- 3 files changed, 49 insertions(+), 47 deletions(-) diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 214231c..77e5da4 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -535,7 +535,7 @@ int main(int argc, char* argv[]) outputuhd_conf.txgain = pt.get("uhdoutput.txgain", 0.0); outputuhd_conf.frequency = pt.get("uhdoutput.frequency", 0); std::string chan = pt.get("uhdoutput.channel", ""); - outputuhd_conf.dabMode = dabMode; + outputuhd_conf.dabMode = dabMode; if (outputuhd_conf.frequency == 0 && chan == "") { std::cerr << " UHD output enabled, but neither frequency nor channel defined.\n"; diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index bfd24a8..d033700 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -225,7 +225,7 @@ OutputUHD::OutputUHD( uwd.check_refclk_loss = true; } - SetDelayBuffer(config.dabMode); + SetDelayBuffer(config.dabMode); shared_ptr b(new barrier(2)); mySyncBarrier = b; @@ -249,30 +249,30 @@ OutputUHD::~OutputUHD() void OutputUHD::SetDelayBuffer(unsigned int dabMode) { - // find out the duration of the transmission frame (Table 2 in ETSI 300 401) + // find out the duration of the transmission frame (Table 2 in ETSI 300 401) switch (dabMode) { - case 0: // could happen when called from constructor and we take the mode from ETI - myTFDurationMs = 0; - break; - case 1: - myTFDurationMs = 96; - break; - case 2: - myTFDurationMs = 24; - break; - case 3: - myTFDurationMs = 24; - break; - case 4: - myTFDurationMs = 48; - break; - default: - throw std::runtime_error("OutPutUHD: invalid DAB mode"); + case 0: // could happen when called from constructor and we take the mode from ETI + myTFDurationMs = 0; + break; + case 1: + myTFDurationMs = 96; + break; + case 2: + myTFDurationMs = 24; + break; + case 3: + myTFDurationMs = 24; + break; + case 4: + myTFDurationMs = 48; + break; + default: + throw std::runtime_error("OutputUHD: invalid DAB mode"); } - // The buffer size equals the number of samples per transmission frame so - // we calculate it by multiplying the duration of the transmission frame - // with the samplerate. - myDelayBuf.resize(myTFDurationMs * myConf.sampleRate / 1000); + // The buffer size equals the number of samples per transmission frame so + // we calculate it by multiplying the duration of the transmission frame + // with the samplerate. + myDelayBuf.resize(myTFDurationMs * myConf.sampleRate / 1000); } int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) @@ -310,10 +310,11 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) default: break; } - // we only set the delay buffer from the dab mode signaled in ETI if the - // dab mode was not set in contructor - if (myTFDurationMs == 0) - SetDelayBuffer(myEtiReader->getMode()); + // we only set the delay buffer from the dab mode signaled in ETI if the + // dab mode was not set in contructor + if (myTFDurationMs == 0) { + SetDelayBuffer(myEtiReader->getMode()); + } activebuffer = 1; @@ -688,21 +689,21 @@ void OutputUHD::set_parameter(const string& parameter, const string& value) else if (parameter == "staticdelay") { int64_t adjust; ss >> adjust; - if (adjust > (myTFDurationMs * 1000)) - { // reset static delay for values outside range - myStaticDelayUs = 0; - } - else - { // the new adjust value is added to the existing delay and the result - // is wrapped around at TF duration - int newStaticDelayUs = myStaticDelayUs + adjust; - if (newStaticDelayUs > (myTFDurationMs * 1000)) - myStaticDelayUs = newStaticDelayUs - (myTFDurationMs * 1000); - else if (newStaticDelayUs < 0) - myStaticDelayUs = newStaticDelayUs + (myTFDurationMs * 1000); - else - myStaticDelayUs = newStaticDelayUs; - } + if (adjust > (myTFDurationMs * 1000)) + { // reset static delay for values outside range + myStaticDelayUs = 0; + } + else + { // the new adjust value is added to the existing delay and the result + // is wrapped around at TF duration + int newStaticDelayUs = myStaticDelayUs + adjust; + if (newStaticDelayUs > (myTFDurationMs * 1000)) + myStaticDelayUs = newStaticDelayUs - (myTFDurationMs * 1000); + else if (newStaticDelayUs < 0) + myStaticDelayUs = newStaticDelayUs + (myTFDurationMs * 1000); + else + myStaticDelayUs = newStaticDelayUs; + } } else if (parameter == "iqbalance") { ss >> myConf.frequency; diff --git a/src/OutputUHD.h b/src/OutputUHD.h index d002e98..c5d561b 100644 --- a/src/OutputUHD.h +++ b/src/OutputUHD.h @@ -171,7 +171,7 @@ struct OutputUHDConfig { double txgain; bool enableSync; bool muteNoTimestamps; - unsigned dabMode; + unsigned dabMode; /* allowed values : auto, int, sma, mimo */ std::string refclk_src; @@ -232,12 +232,13 @@ class OutputUHD: public ModOutput, public RemoteControllable { bool myMuting; private: - // methods - void SetDelayBuffer(unsigned int dabMode); + // Resize the internal delay buffer according to the dabMode and + // the sample rate. + void SetDelayBuffer(unsigned int dabMode); // data int myStaticDelayUs; // static delay in microseconds - int myTFDurationMs; // TF duration in milliseconds + int myTFDurationMs; // TF duration in milliseconds std::vector myDelayBuf; size_t lastLen; }; -- cgit v1.2.3 From 7bacaf3818494cf706f7372cb6cd194dbaf3f251 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Thu, 12 Feb 2015 10:43:06 +0100 Subject: Move some code from DabMod into Utils --- Makefile.am | 7 +++- src/DabMod.cpp | 90 +------------------------------------------ src/Utils.cpp | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Utils.h | 44 +++++++++++++++++++++ 4 files changed, 171 insertions(+), 89 deletions(-) create mode 100644 src/Utils.cpp create mode 100644 src/Utils.h diff --git a/Makefile.am b/Makefile.am index 3f5d639..fa8afd0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,10 @@ # Copyright (C) 2007, 2008, 2009, 2010 Her Majesty the Queen in Right # of Canada (Communications Research Center Canada) # -# Copyright (C) 2014 Matthias P. Braendli, http://mpb.li +# Copyright (C) 2014, 2015 +# Matthias P. Braendli, matthias.braendli@mpb.li + +# http://opendigitalradio.org # This file is part of ODR-DabMod. # @@ -160,6 +163,8 @@ odr_dabmod_SOURCES = src/DabMod.cpp \ src/RemoteControl.h \ src/FormatConverter.cpp \ src/FormatConverter.h \ + src/Utils.cpp \ + src/Utils.h \ src/zmq.hpp dist_bin_SCRIPTS = src/crc-dwap.py diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 77e5da4..1bbfc99 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -3,7 +3,7 @@ Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2014 + Copyright (C) 2014, 2015 Matthias P. Braendli, matthias.braendli@mpb.li http://opendigitalradio.org @@ -30,7 +30,7 @@ #endif #include "porting.h" - +#include "Utils.h" #include "Log.h" #include "DabModulator.h" #include "InputMemory.h" @@ -81,92 +81,6 @@ void signalHandler(int signalNb) running = 0; } - -void printUsage(char* progName, FILE* out = stderr) -{ - fprintf(out, "Welcome to %s %s, compiled at %s, %s\n\n", - PACKAGE, -#if defined(GITVERSION) - GITVERSION, -#else - VERSION, -#endif - __DATE__, __TIME__); - fprintf(out, "Usage with configuration file:\n"); - fprintf(out, "\t%s [-C] config_file.ini\n\n", progName); - - fprintf(out, "Usage with command line options:\n"); - fprintf(out, "\t%s" - " input" - " (-f filename | -u uhddevice -F frequency) " - " [-G txgain]" - " [-o offset]" - " [-O offsetfile]" - " [-T filter_taps_file]" - " [-a gain]" - " [-c clockrate]" - " [-g gainMode]" - " [-h]" - " [-l]" - " [-m dabMode]" - " [-r samplingRate]" - "\n", progName); - fprintf(out, "Where:\n"); - fprintf(out, "input: ETI input filename (default: stdin).\n"); - fprintf(out, "-f name: Use file output with given filename. (use /dev/stdout for standard output)\n"); - 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"); - fprintf(out, "-o: (UHD only) Set the timestamp offset added to the timestamp in the ETI. The offset is a double.\n"); - fprintf(out, "-O: (UHD only) Set the file containing the timestamp offset added to the timestamp in the ETI.\n" - "The file is read every six seconds, and must contain a double value.\n"); - fprintf(out, " Specifying either -o or -O has two implications: It enables synchronous transmission,\n" - " requiring an external REFCLK and PPS signal and frames that do not contain a valid timestamp\n" - " get muted.\n\n"); - fprintf(out, "-T taps_file: Enable filtering before the output, using the specified file containing the filter taps.\n"); - 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: Set computation gain mode: " - "%u FIX, %u MAX, %u VAR\n", GAIN_FIX, GAIN_MAX, GAIN_VAR); - fprintf(out, "-h: Print this help.\n"); - fprintf(out, "-l: Loop file when reach end of file.\n"); - fprintf(out, "-m mode: Set DAB mode: (0: auto, 1-4: force).\n"); - fprintf(out, "-r rate: Set output sampling rate (default: 2048000).\n"); -} - - -void printVersion(FILE *out = stderr) -{ - fprintf(out, "Welcome to %s %s, compiled at %s, %s\n\n", - PACKAGE, VERSION, __DATE__, __TIME__); - fprintf(out, - " ODR-DabMod is copyright (C) Her Majesty the Queen in Right of Canada,\n" - " 2009, 2010, 2011, 2012 Communications Research Centre (CRC),\n" - " and\n" - " Copyright (C) 2014 Matthias P. Braendli, matthias.braendli@mpb.li\n" - "\n" - " http://opendigitalradio.org\n" - "\n" - " This program is available free of charge and is licensed to you on a\n" - " non-exclusive basis; you may not redistribute it.\n" - "\n" - " This program is provided \"AS IS\" in the hope that it will be useful, but\n" - " WITHOUT ANY WARRANTY with respect to its accurancy or usefulness; witout\n" - " even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n" - " PURPOSE and NONINFRINGEMENT.\n" - "\n" - " In no event shall CRC be LIABLE for any LOSS, DAMAGE or COST that may be\n" - " incurred in connection with the use of this software.\n" - "\n" -#if USE_KISS_FFT - "ODR-DabMod makes use of the following open source packages:\n" - " Kiss FFT v1.2.9 (Revised BSD) - http://kissfft.sourceforge.net/\n" -#endif - ); - -} - - int main(int argc, char* argv[]) { int ret = 0; diff --git a/src/Utils.cpp b/src/Utils.cpp new file mode 100644 index 0000000..5c80eee --- /dev/null +++ b/src/Utils.cpp @@ -0,0 +1,119 @@ +/* + Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 + Her Majesty the Queen in Right of Canada (Communications Research + Center Canada) + + Copyright (C) 2015 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org + */ +/* + This file is part of ODR-DabMod. + + ODR-DabMod is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + ODR-DabMod is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ODR-DabMod. If not, see . + */ + +#include "Utils.h" +#include "GainControl.h" + +void printUsage(char* progName) +{ + FILE* out = stderr; + + fprintf(out, "Welcome to %s %s, compiled at %s, %s\n\n", + PACKAGE, +#if defined(GITVERSION) + GITVERSION, +#else + VERSION, +#endif + __DATE__, __TIME__); + fprintf(out, "Usage with configuration file:\n"); + fprintf(out, "\t%s [-C] config_file.ini\n\n", progName); + + fprintf(out, "Usage with command line options:\n"); + fprintf(out, "\t%s" + " input" + " (-f filename | -u uhddevice -F frequency) " + " [-G txgain]" + " [-o offset]" + " [-O offsetfile]" + " [-T filter_taps_file]" + " [-a gain]" + " [-c clockrate]" + " [-g gainMode]" + " [-h]" + " [-l]" + " [-m dabMode]" + " [-r samplingRate]" + "\n", progName); + fprintf(out, "Where:\n"); + fprintf(out, "input: ETI input filename (default: stdin).\n"); + fprintf(out, "-f name: Use file output with given filename. (use /dev/stdout for standard output)\n"); + 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"); + fprintf(out, "-o: (UHD only) Set the timestamp offset added to the timestamp in the ETI. The offset is a double.\n"); + fprintf(out, "-O: (UHD only) Set the file containing the timestamp offset added to the timestamp in the ETI.\n" + "The file is read every six seconds, and must contain a double value.\n"); + fprintf(out, " Specifying either -o or -O has two implications: It enables synchronous transmission,\n" + " requiring an external REFCLK and PPS signal and frames that do not contain a valid timestamp\n" + " get muted.\n\n"); + fprintf(out, "-T taps_file: Enable filtering before the output, using the specified file containing the filter taps.\n"); + 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: Set computation gain mode: " + "%u FIX, %u MAX, %u VAR\n", GAIN_FIX, GAIN_MAX, GAIN_VAR); + fprintf(out, "-h: Print this help.\n"); + fprintf(out, "-l: Loop file when reach end of file.\n"); + fprintf(out, "-m mode: Set DAB mode: (0: auto, 1-4: force).\n"); + fprintf(out, "-r rate: Set output sampling rate (default: 2048000).\n"); +} + + +void printVersion(void) +{ + FILE *out = stderr; + + fprintf(out, "Welcome to %s %s, compiled at %s, %s\n\n", + PACKAGE, VERSION, __DATE__, __TIME__); + fprintf(out, + " ODR-DabMod is copyright (C) Her Majesty the Queen in Right of Canada,\n" + " 2009, 2010, 2011, 2012 Communications Research Centre (CRC),\n" + " and\n" + " Copyright (C) 2014 Matthias P. Braendli, matthias.braendli@mpb.li\n" + "\n" + " http://opendigitalradio.org\n" + "\n" + " This program is available free of charge and is licensed to you on a\n" + " non-exclusive basis; you may not redistribute it.\n" + "\n" + " This program is provided \"AS IS\" in the hope that it will be useful, but\n" + " WITHOUT ANY WARRANTY with respect to its accurancy or usefulness; witout\n" + " even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n" + " PURPOSE and NONINFRINGEMENT.\n" + "\n" + " In no event shall CRC be LIABLE for any LOSS, DAMAGE or COST that may be\n" + " incurred in connection with the use of this software.\n" + "\n" +#if USE_KISS_FFT + "ODR-DabMod makes use of the following open source packages:\n" + " Kiss FFT v1.2.9 (Revised BSD) - http://kissfft.sourceforge.net/\n" +#endif + ); + +} + + diff --git a/src/Utils.h b/src/Utils.h new file mode 100644 index 0000000..7c3129c --- /dev/null +++ b/src/Utils.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 + Her Majesty the Queen in Right of Canada (Communications Research + Center Canada) + + Copyright (C) 2015 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org + */ +/* + This file is part of ODR-DabMod. + + ODR-DabMod is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + ODR-DabMod is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ODR-DabMod. If not, see . + */ + +#ifndef __UTILS_H_ +#define __UTILS_H_ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +void printUsage(char* progName); + +void printVersion(void); + +#endif + -- cgit v1.2.3 From c5c21c73c310c29675bff1a1f2da4ddd298c0f92 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 20 Feb 2015 10:12:06 +0100 Subject: Add max_frames_queued option for zmq input --- doc/example.ini | 3 +++ src/DabMod.cpp | 10 ++++++++-- src/InputReader.h | 6 ++++-- src/InputZeroMQReader.cpp | 9 ++++----- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/doc/example.ini b/doc/example.ini index cec0f23..3c51142 100644 --- a/doc/example.ini +++ b/doc/example.ini @@ -49,6 +49,9 @@ loop=0 ; When recieving data using ZeroMQ, the source is the URI to be used ;transport=zeromq ;source=tcp://localhost:8080 +; The option max_frames_queued defines the maximum number of ETI frames +; that can be in the input queue +;max_frames_queued=100 [modulator] ; Gain mode: 0=FIX, 1=MAX, 2=VAR diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 1bbfc99..f546e45 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -68,6 +68,8 @@ # define memalign(a, b) malloc(b) #endif +#define ZMQ_INPUT_MAX_FRAME_QUEUE 50 + typedef std::complex complexf; @@ -87,6 +89,7 @@ int main(int argc, char* argv[]) bool loop = false; std::string inputName = ""; std::string inputTransport = "file"; + unsigned inputMaxFramesQueued = ZMQ_INPUT_MAX_FRAME_QUEUE; std::string outputName; int useZeroMQOutput = 0; @@ -362,6 +365,9 @@ int main(int argc, char* argv[]) } inputTransport = pt.get("input.transport", "file"); + inputMaxFramesQueued = pt.get("input.max_frames_queued", + ZMQ_INPUT_MAX_FRAME_QUEUE); + inputName = pt.get("input.source", "/dev/stdin"); // log parameters: @@ -677,10 +683,10 @@ int main(int argc, char* argv[]) #else // The URL might start with zmq+tcp:// if (inputName.substr(0, 4) == "zmq+") { - inputZeroMQReader.Open(inputName.substr(4)); + inputZeroMQReader.Open(inputName.substr(4), inputMaxFramesQueued); } else { - inputZeroMQReader.Open(inputName); + inputZeroMQReader.Open(inputName, inputMaxFramesQueued); } inputReader = &inputZeroMQReader; #endif diff --git a/src/InputReader.h b/src/InputReader.h index 3e0dcab..3e3e000 100644 --- a/src/InputReader.h +++ b/src/InputReader.h @@ -3,7 +3,7 @@ Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyrigth (C) 2013 + Copyrigth (C) 2013, 2015 Matthias P. Braendli, matthias.braendli@mpb.li */ /* @@ -137,6 +137,7 @@ struct InputZeroMQThreadData { ThreadsafeQueue *in_messages; std::string uri; + unsigned max_queued_frames; }; class InputZeroMQWorker @@ -179,7 +180,7 @@ class InputZeroMQReader : public InputReader worker_.Stop(); } - int Open(std::string uri); + int Open(const std::string& uri, unsigned max_queued_frames); int GetNextFrame(void* buffer); @@ -197,3 +198,4 @@ class InputZeroMQReader : public InputReader #endif #endif + diff --git a/src/InputZeroMQReader.cpp b/src/InputZeroMQReader.cpp index f7f5702..01d8720 100644 --- a/src/InputZeroMQReader.cpp +++ b/src/InputZeroMQReader.cpp @@ -3,7 +3,7 @@ Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2013, 2014 + Copyright (C) 2013, 2014, 2015 Matthias P. Braendli, matthias.braendli@mpb.li http://opendigitalradio.org @@ -41,8 +41,6 @@ #include "InputReader.h" #include "PcDebug.h" -#define MAX_QUEUE_SIZE 50 - #define NUM_FRAMES_PER_ZMQ_MESSAGE 4 /* A concatenation of four ETI frames, * whose maximal size is 6144. @@ -64,10 +62,11 @@ struct zmq_dab_message_t uint8_t buf[NUM_FRAMES_PER_ZMQ_MESSAGE*6144]; }; -int InputZeroMQReader::Open(std::string uri) +int InputZeroMQReader::Open(const std::string& uri, unsigned max_queued_frames) { uri_ = uri; workerdata_.uri = uri; + workerdata_.max_queued_frames = max_queued_frames; // launch receiver thread worker_.Start(&workerdata_); @@ -123,7 +122,7 @@ void InputZeroMQWorker::RecvProcess(struct InputZeroMQThreadData* workerdata) } m_to_drop--; } - else if (queue_size < MAX_QUEUE_SIZE) { + else if (queue_size < workerdata->max_queued_frames) { if (buffer_full) { fprintf(stderr, "ZeroMQ buffer recovered: %zu elements\n", queue_size); -- cgit v1.2.3 From 3a20c7dbf7efa851a373f8ab8d4659bb977d6961 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 22 Feb 2015 18:37:37 +0100 Subject: Start using shared_ptr inside Flowgraph --- src/Flowgraph.cpp | 51 ++++++++++++++++++++++++++++++++------------------- src/Flowgraph.h | 18 ++++++++++-------- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/Flowgraph.cpp b/src/Flowgraph.cpp index dd9c68b..373533b 100644 --- a/src/Flowgraph.cpp +++ b/src/Flowgraph.cpp @@ -38,9 +38,12 @@ #include #endif +#include -typedef std::vector::iterator NodeIterator; -typedef std::vector::iterator EdgeIterator; +using namespace boost; + +typedef std::vector >::iterator NodeIterator; +typedef std::vector >::iterator EdgeIterator; Node::Node(ModPlugin* plugin) : @@ -64,7 +67,7 @@ Node::~Node() } -Edge::Edge(Node* srcNode, Node* dstNode) : +Edge::Edge(shared_ptr& srcNode, shared_ptr& dstNode) : mySrcNode(srcNode), myDstNode(dstNode) { @@ -73,7 +76,7 @@ Edge::Edge(Node* srcNode, Node* dstNode) : dstNode->plugin()->name(), dstNode, this); - myBuffer = new Buffer(); + myBuffer = shared_ptr(new Buffer()); srcNode->myOutputBuffers.push_back(myBuffer); dstNode->myInputBuffers.push_back(myBuffer); } @@ -83,7 +86,7 @@ Edge::~Edge() { PDEBUG("Edge::~Edge() @ %p\n", this); - std::vector::iterator buffer; + std::vector >::iterator buffer; if (myBuffer != NULL) { for (buffer = mySrcNode->myOutputBuffers.begin(); buffer != mySrcNode->myOutputBuffers.end(); @@ -102,7 +105,6 @@ Edge::~Edge() break; } } - delete myBuffer; } } @@ -112,7 +114,24 @@ int Node::process() PDEBUG("Edge::process()\n"); PDEBUG(" Plugin name: %s (%p)\n", myPlugin->name(), myPlugin); - return myPlugin->process(myInputBuffers, myOutputBuffers); + // the plugin process() still wants vector + // arguments. + std::vector inBuffers; + std::vector >::iterator buffer; + for (buffer = myInputBuffers.begin(); + buffer != myInputBuffers.end(); + ++buffer) { + inBuffers.push_back(buffer->get()); + } + + std::vector outBuffers; + for (buffer = myOutputBuffers.begin(); + buffer != myOutputBuffers.end(); + ++buffer) { + outBuffers.push_back(buffer->get()); + } + + return myPlugin->process(inBuffers, outBuffers); } @@ -128,15 +147,10 @@ Flowgraph::~Flowgraph() { PDEBUG("Flowgraph::~Flowgraph() @ %p\n", this); - std::vector::const_iterator edge; - for (edge = edges.begin(); edge != edges.end(); ++edge) { - delete *edge; - } - if (myProcessTime) { fprintf(stderr, "Process time:\n"); } - std::vector::const_iterator node; + std::vector >::const_iterator node; for (node = nodes.begin(); node != nodes.end(); ++node) { if (myProcessTime) { fprintf(stderr, " %30s: %10u us (%2.2f %%)\n", @@ -144,7 +158,6 @@ Flowgraph::~Flowgraph() (unsigned)(*node)->processTime(), (*node)->processTime() * 100.0 / myProcessTime); } - delete *node; } if (myProcessTime) { fprintf(stderr, " %30s: %10u us (100.00 %%)\n", "total", @@ -167,7 +180,7 @@ void Flowgraph::connect(ModPlugin* input, ModPlugin* output) } } if (inputNode == nodes.end()) { - inputNode = nodes.insert(nodes.end(), new Node(input)); + inputNode = nodes.insert(nodes.end(), shared_ptr(new Node(input))); } for (outputNode = nodes.begin(); outputNode != nodes.end(); ++outputNode) { @@ -176,14 +189,14 @@ void Flowgraph::connect(ModPlugin* input, ModPlugin* output) } } if (outputNode == nodes.end()) { - outputNode = nodes.insert(nodes.end(), new Node(output)); + outputNode = nodes.insert(nodes.end(), shared_ptr(new Node(output))); for (inputNode = nodes.begin(); inputNode != nodes.end(); ++inputNode) { if ((*inputNode)->plugin() == input) { break; } } } else if (inputNode > outputNode) { - Node* node = *outputNode; + shared_ptr node = *outputNode; nodes.erase(outputNode); outputNode = nodes.insert(nodes.end(), node); for (inputNode = nodes.begin(); inputNode != nodes.end(); ++inputNode) { @@ -196,7 +209,7 @@ void Flowgraph::connect(ModPlugin* input, ModPlugin* output) assert((*inputNode)->plugin() == input); assert((*outputNode)->plugin() == output); - edges.push_back(new Edge(*inputNode, *outputNode)); + edges.push_back(shared_ptr(new Edge(*inputNode, *outputNode))); } @@ -204,7 +217,7 @@ bool Flowgraph::run() { PDEBUG("Flowgraph::run()\n"); - std::vector::const_iterator node; + std::vector >::const_iterator node; timeval start, stop; time_t diff; diff --git a/src/Flowgraph.h b/src/Flowgraph.h index 178b6a9..00b8d42 100644 --- a/src/Flowgraph.h +++ b/src/Flowgraph.h @@ -32,6 +32,7 @@ #include #include +#include class Node @@ -44,8 +45,8 @@ public: ModPlugin* plugin() { return myPlugin; } - std::vector myInputBuffers; - std::vector myOutputBuffers; + std::vector > myInputBuffers; + std::vector > myOutputBuffers; int process(); time_t processTime() { return myProcessTime; } @@ -62,15 +63,15 @@ protected: class Edge { public: - Edge(Node* src, Node* dst); + Edge(boost::shared_ptr& src, boost::shared_ptr& dst); ~Edge(); Edge(const Edge&); Edge& operator=(const Edge&); protected: - Node* mySrcNode; - Node* myDstNode; - Buffer* myBuffer; + boost::shared_ptr mySrcNode; + boost::shared_ptr myDstNode; + boost::shared_ptr myBuffer; }; @@ -86,10 +87,11 @@ public: bool run(); protected: - std::vector nodes; - std::vector edges; + std::vector > nodes; + std::vector > edges; time_t myProcessTime; }; #endif // FLOWGRAPH_H + -- cgit v1.2.3 From 7d7cbc19bc5509aa9fb8fb430132fe82855cf8c4 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 22 Feb 2015 20:51:24 +0100 Subject: Reindent CicEqualizer --- src/CicEqualizer.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/CicEqualizer.cpp b/src/CicEqualizer.cpp index d8eb2ee..a9c0dd6 100644 --- a/src/CicEqualizer.cpp +++ b/src/CicEqualizer.cpp @@ -46,11 +46,12 @@ CicEqualizer::CicEqualizer(size_t nbCarriers, size_t spacing, int R) : float angle = pi * k / spacing; if (k == 0) { myFilter[i] = 1.0f; - } else { - myFilter[i] = sinf(angle / R) / sinf(angle * M); - myFilter[i] = fabsf(myFilter[i]) * R * M; - myFilter[i] = powf(myFilter[i], N); - } + } + else { + myFilter[i] = sinf(angle / R) / sinf(angle * M); + myFilter[i] = fabsf(myFilter[i]) * R * M; + myFilter[i] = powf(myFilter[i], N); + } PDEBUG("HCic[%zu -> %i] = %f (%f dB) -> angle: %f\n", i, k,myFilter[i], 20.0 * log10(myFilter[i]), angle); } @@ -93,3 +94,4 @@ int CicEqualizer::process(Buffer* const dataIn, Buffer* dataOut) return sizeOut; } + -- cgit v1.2.3 From 7cee56f37001640b88f4ac1249624c9c9758e844 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 22 Feb 2015 20:52:20 +0100 Subject: Replace pointers by shared_ptr in all flowgraph --- src/Buffer.cpp | 1 + src/DabMod.cpp | 93 +++++++++++++----------------- src/DabModulator.cpp | 147 +++++++++++++++++++++++++---------------------- src/DabModulator.h | 9 ++- src/EtiReader.cpp | 19 +++--- src/EtiReader.h | 12 ++-- src/Flowgraph.cpp | 27 ++++----- src/Flowgraph.h | 14 +++-- src/FrameMultiplexer.cpp | 8 ++- src/FrameMultiplexer.h | 9 +-- src/OutputMemory.h | 2 +- 11 files changed, 176 insertions(+), 165 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index aa0ef4c..fa7f52f 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -47,6 +47,7 @@ Buffer::Buffer(size_t len, const void *data) Buffer::~Buffer() { + PDEBUG("Buffer::~Buffer() len=%zu, data=%p\n", len, data); free(data); } diff --git a/src/DabMod.cpp b/src/DabMod.cpp index f546e45..1f6eedf 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -46,6 +46,7 @@ #include "FIRFilter.h" #include "RemoteControl.h" +#include #include #include #include @@ -73,6 +74,7 @@ typedef std::complex complexf; +using namespace boost; volatile sig_atomic_t running = 1; @@ -134,11 +136,9 @@ int main(int argc, char* argv[]) modconf.use_offset_fixed = false; modconf.delay_calculation_pipeline_stages = 0; - Flowgraph* flowgraph = NULL; - DabModulator* modulator = NULL; - InputMemory* input = NULL; - FormatConverter* format_converter = NULL; - ModOutput* output = NULL; + shared_ptr flowgraph(new Flowgraph()); + shared_ptr format_converter; + shared_ptr output; RemoteControllers rcs; @@ -188,7 +188,7 @@ int main(int argc, char* argv[]) #if defined(HAVE_OUTPUT_UHD) if (useUHDOutput) { fprintf(stderr, "Options -u and -f are mutually exclusive\n"); - goto END_MAIN; + throw std::invalid_argument("Invalid command line options"); } #endif outputName = optarg; @@ -214,7 +214,7 @@ int main(int argc, char* argv[]) if (modconf.use_offset_file) { fprintf(stderr, "Options -o and -O are mutually exclusive\n"); - goto END_MAIN; + throw std::invalid_argument("Invalid command line options"); } modconf.use_offset_fixed = true; modconf.offset_fixed = strtod(optarg, NULL); @@ -226,7 +226,7 @@ int main(int argc, char* argv[]) if (modconf.use_offset_fixed) { fprintf(stderr, "Options -o and -O are mutually exclusive\n"); - goto END_MAIN; + throw std::invalid_argument("Invalid command line options"); } modconf.use_offset_file = true; modconf.offset_filename = std::string(optarg); @@ -247,7 +247,7 @@ int main(int argc, char* argv[]) #if defined(HAVE_OUTPUT_UHD) if (useFileOutput) { fprintf(stderr, "Options -u and -f are mutually exclusive\n"); - goto END_MAIN; + throw std::invalid_argument("Invalid command line options"); } outputuhd_conf.device = optarg; useUHDOutput = 1; @@ -255,17 +255,17 @@ int main(int argc, char* argv[]) break; case 'V': printVersion(); - goto END_MAIN; + throw std::invalid_argument(""); break; case '?': case 'h': printUsage(argv[0]); - goto END_MAIN; + throw std::invalid_argument(""); break; default: fprintf(stderr, "Option '%c' not coded yet!\n", c); ret = -1; - goto END_MAIN; + throw std::invalid_argument("Invalid command line options"); } } @@ -306,7 +306,7 @@ int main(int argc, char* argv[]) // No argument given ? You can't be serious ! Show usage. if (argc == 1) { printUsage(argv[0]); - goto END_MAIN; + throw std::invalid_argument("Invalid command line options"); } // If only one argument is given, interpret as configuration file name @@ -326,7 +326,7 @@ int main(int argc, char* argv[]) catch (boost::property_tree::ini_parser::ini_parser_error &e) { fprintf(stderr, "Error, cannot read configuration file '%s'\n", configuration_file.c_str()); - goto END_MAIN; + throw std::runtime_error("Cannot read configuration file"); } // remote controller: @@ -339,7 +339,7 @@ int main(int argc, char* argv[]) catch (std::exception &e) { std::cerr << "Error: " << e.what() << "\n"; std::cerr << " telnet remote control enabled, but no telnetport defined.\n"; - goto END_MAIN; + throw std::runtime_error("Configuration error"); } } @@ -354,7 +354,7 @@ int main(int argc, char* argv[]) catch (std::exception &e) { std::cerr << "Error: " << e.what() << "\n"; std::cerr << " zmq remote control enabled, but no endpoint defined.\n"; - goto END_MAIN; + throw std::runtime_error("Configuration error"); } } #endif @@ -384,7 +384,7 @@ int main(int argc, char* argv[]) catch (std::exception &e) { std::cerr << "Error: " << e.what() << "\n"; std::cerr << " Configuration enables file log, but does not specify log filename\n"; - goto END_MAIN; + throw std::runtime_error("Configuration error"); } LogToFile* log_file = new LogToFile(logfilename); @@ -407,7 +407,7 @@ int main(int argc, char* argv[]) catch (std::exception &e) { std::cerr << "Error: " << e.what() << "\n"; std::cerr << " Configuration enables firfilter, but does not specify filter taps file\n"; - goto END_MAIN; + throw std::runtime_error("Configuration error"); } } @@ -419,7 +419,7 @@ int main(int argc, char* argv[]) catch (std::exception &e) { std::cerr << "Error: " << e.what() << "\n"; std::cerr << " Configuration does not specify output\n"; - goto END_MAIN; + throw std::runtime_error("Configuration error"); } if (output_selected == "file") { @@ -429,7 +429,7 @@ int main(int argc, char* argv[]) catch (std::exception &e) { std::cerr << "Error: " << e.what() << "\n"; std::cerr << " Configuration does not specify file name for file output\n"; - goto END_MAIN; + throw std::runtime_error("Configuration error"); } useFileOutput = 1; @@ -459,7 +459,7 @@ int main(int argc, char* argv[]) if (outputuhd_conf.frequency == 0 && chan == "") { std::cerr << " UHD output enabled, but neither frequency nor channel defined.\n"; - goto END_MAIN; + throw std::runtime_error("Configuration error"); } else if (outputuhd_conf.frequency == 0) { double freq; @@ -503,13 +503,13 @@ int main(int argc, char* argv[]) else if (chan == "13F") freq = 239200000; else { std::cerr << " UHD output: channel " << chan << " does not exist in table\n"; - goto END_MAIN; + throw std::out_of_range("UHD channel selection error"); } outputuhd_conf.frequency = freq; } else if (outputuhd_conf.frequency != 0 && chan != "") { std::cerr << " UHD output: cannot define both frequency and channel.\n"; - goto END_MAIN; + throw std::runtime_error("Configuration error"); } @@ -527,7 +527,7 @@ int main(int argc, char* argv[]) } else { std::cerr << "Error: UHD output: behaviour_refclk_lock_lost invalid." << std::endl; - goto END_MAIN; + throw std::runtime_error("Configuration error"); } useUHDOutput = 1; @@ -541,7 +541,7 @@ int main(int argc, char* argv[]) #endif else { std::cerr << "Error: Invalid output defined.\n"; - goto END_MAIN; + throw std::runtime_error("Configuration error"); } #if defined(HAVE_OUTPUT_UHD) @@ -564,7 +564,7 @@ int main(int argc, char* argv[]) catch (std::exception &e) { std::cerr << "Error: " << e.what() << "\n"; std::cerr << " Synchronised transmission enabled, but delay management specification is incomplete.\n"; - goto END_MAIN; + throw std::runtime_error("Configuration error"); } } @@ -618,13 +618,13 @@ int main(int argc, char* argv[]) printUsage(argv[0]); ret = -1; logger.level(error) << "Received invalid command line arguments"; - goto END_MAIN; + throw std::invalid_argument("Invalid command line options"); } if (!useFileOutput && !useUHDOutput && !useZeroMQOutput) { logger.level(error) << "Output not specified"; fprintf(stderr, "Must specify output !"); - goto END_MAIN; + throw std::runtime_error("Configuration error"); } // Print settings @@ -670,7 +670,7 @@ int main(int argc, char* argv[]) fprintf(stderr, "Unable to open input file!\n"); logger.level(error) << "Unable to open input file!"; ret = -1; - goto END_MAIN; + throw std::runtime_error("Unable to open input"); } inputReader = &inputFileReader; @@ -679,7 +679,7 @@ int main(int argc, char* argv[]) #if !defined(HAVE_ZEROMQ) fprintf(stderr, "Error, ZeroMQ input transport selected, but not compiled in!\n"); ret = -1; - goto END_MAIN; + throw std::runtime_error("Unable to open input"); #else // The URL might start with zmq+tcp:// if (inputName.substr(0, 4) == "zmq+") { @@ -695,20 +695,20 @@ int main(int argc, char* argv[]) { fprintf(stderr, "Error, invalid input transport %s selected!\n", inputTransport.c_str()); ret = -1; - goto END_MAIN; + throw std::runtime_error("Unable to open input"); } if (useFileOutput) { if (fileOutputFormat == "complexf") { - output = new OutputFile(outputName); + output = shared_ptr(new OutputFile(outputName)); } else if (fileOutputFormat == "s8") { // We must normalise the samples to the interval [-127.0; 127.0] normalise = 127.0f / normalise_factor; - format_converter = new FormatConverter(); + format_converter = shared_ptr(new FormatConverter()); - output = new OutputFile(outputName); + output = shared_ptr(new OutputFile(outputName)); } } #if defined(HAVE_OUTPUT_UHD) @@ -717,14 +717,8 @@ int main(int argc, char* argv[]) normalise = 1.0f / normalise_factor; outputuhd_conf.sampleRate = outputRate; - try { - output = new OutputUHD(outputuhd_conf, logger); - ((OutputUHD*)output)->enrol_at(rcs); - } - catch (std::exception& e) { - logger.level(error) << "UHD initialisation failed:" << e.what(); - goto END_MAIN; - } + output = shared_ptr(new OutputUHD(outputuhd_conf, logger)); + ((OutputUHD*)output.get())->enrol_at(rcs); } #endif #if defined(HAVE_ZEROMQ) @@ -732,15 +726,14 @@ int main(int argc, char* argv[]) /* We normalise the same way as for the UHD output */ normalise = 1.0f / normalise_factor; - output = new OutputZeroMQ(outputName); + output = shared_ptr(new OutputZeroMQ(outputName)); } #endif - flowgraph = new Flowgraph(); data.setLength(6144); - input = new InputMemory(&data); - modulator = new DabModulator(modconf, &rcs, logger, outputRate, clockRate, - dabMode, gainMode, digitalgain, normalise, filterTapsFilename); + shared_ptr input(new InputMemory(&data)); + shared_ptr modulator(new DabModulator(modconf, &rcs, logger, outputRate, clockRate, + dabMode, gainMode, digitalgain, normalise, filterTapsFilename)); flowgraph->connect(input, modulator); if (format_converter) { flowgraph->connect(modulator, format_converter); @@ -752,7 +745,7 @@ int main(int argc, char* argv[]) #if defined(HAVE_OUTPUT_UHD) if (useUHDOutput) { - ((OutputUHD*)output)->setETIReader(modulator->getEtiReader()); + ((OutputUHD*)output.get())->setETIReader(modulator->getEtiReader()); } #endif @@ -801,7 +794,6 @@ int main(int argc, char* argv[]) ret = -1; } -END_MAIN: //////////////////////////////////////////////////////////////////////// // Cleaning things //////////////////////////////////////////////////////////////////////// @@ -809,9 +801,6 @@ END_MAIN: fprintf(stderr, "%lu DAB frames encoded\n", frame); fprintf(stderr, "%f seconds encoded\n", (float)frame * 0.024f); - fprintf(stderr, "\nCleaning flowgraph...\n"); - delete flowgraph; - // Cif fprintf(stderr, "\nCleaning buffers...\n"); diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp index 2664a08..287280c 100644 --- a/src/DabModulator.cpp +++ b/src/DabModulator.cpp @@ -3,8 +3,10 @@ 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) 2015 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org */ /* This file is part of ODR-DabMod. @@ -50,6 +52,7 @@ #include "RemoteControl.h" #include "Log.h" +using namespace boost; DabModulator::DabModulator( struct modulator_offset_config& modconf, @@ -155,62 +158,65 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) //////////////////////////////////////////////////////////////// // CIF data initialisation //////////////////////////////////////////////////////////////// - FrameMultiplexer* cifMux = NULL; - PrbsGenerator* cifPrbs = NULL; - BlockPartitioner* cifPart = NULL; - QpskSymbolMapper* cifMap = NULL; - FrequencyInterleaver* cifFreq = NULL; - PhaseReference* cifRef = NULL; - DifferentialModulator* cifDiff = NULL; - NullSymbol* cifNull = NULL; - SignalMultiplexer* cifSig = NULL; - CicEqualizer* cifCicEq = NULL; - OfdmGenerator* cifOfdm = NULL; - GainControl* cifGain = NULL; - GuardIntervalInserter* cifGuard = NULL; - FIRFilter* cifFilter = NULL; - Resampler* cifRes = NULL; - - cifPrbs = new PrbsGenerator(864 * 8, 0x110); - cifMux = new FrameMultiplexer(myFicSizeOut + 864 * 8, - &myEtiReader.getSubchannels()); - cifPart = new BlockPartitioner(mode, myEtiReader.getFp()); - cifMap = new QpskSymbolMapper(myNbCarriers); - cifRef = new PhaseReference(mode); - cifFreq = new FrequencyInterleaver(mode); - cifDiff = new DifferentialModulator(myNbCarriers); - cifNull = new NullSymbol(myNbCarriers); - cifSig = new SignalMultiplexer( - (1 + myNbSymbols) * myNbCarriers * sizeof(complexf)); - + shared_ptr cifPrbs(new PrbsGenerator(864 * 8, 0x110)); + shared_ptr cifMux( + new FrameMultiplexer(myFicSizeOut + 864 * 8, + &myEtiReader.getSubchannels())); + + shared_ptr cifPart( + new BlockPartitioner(mode, myEtiReader.getFp())); + + shared_ptr cifMap(new QpskSymbolMapper(myNbCarriers)); + shared_ptr cifRef(new PhaseReference(mode)); + shared_ptr cifFreq(new FrequencyInterleaver(mode)); + shared_ptr cifDiff( + new DifferentialModulator(myNbCarriers)); + + shared_ptr cifNull(new NullSymbol(myNbCarriers)); + shared_ptr cifSig(new SignalMultiplexer( + (1 + myNbSymbols) * myNbCarriers * sizeof(complexf))); + + // TODO this needs a review + bool useCicEq = false; + unsigned cic_ratio = 1; if (myClockRate) { - unsigned ratio = myClockRate / myOutputRate; - ratio /= 4; // FPGA DUC + cic_ratio = myClockRate / myOutputRate; + cic_ratio /= 4; // FPGA DUC if (myClockRate == 400000000) { // USRP2 - if (ratio & 1) { // odd - cifCicEq = new CicEqualizer(myNbCarriers, - (float)mySpacing * (float)myOutputRate / 2048000.0f, - ratio); + if (cic_ratio & 1) { // odd + useCicEq = true; } // even, no filter - } else { - cifCicEq = new CicEqualizer(myNbCarriers, - (float)mySpacing * (float)myOutputRate / 2048000.0f, - ratio); + } + else { + useCicEq = true; } } - cifOfdm = new OfdmGenerator((1 + myNbSymbols), myNbCarriers, mySpacing); - cifGain = new GainControl(mySpacing, myGainMode, myDigGain, myNormalise); + shared_ptr cifCicEq(new CicEqualizer(myNbCarriers, + (float)mySpacing * (float)myOutputRate / 2048000.0f, + cic_ratio)); + + + shared_ptr cifOfdm( + new OfdmGenerator((1 + myNbSymbols), myNbCarriers, mySpacing)); + + shared_ptr cifGain( + new GainControl(mySpacing, myGainMode, myDigGain, myNormalise)); + cifGain->enrol_at(*myRCs); - cifGuard = new GuardIntervalInserter(myNbSymbols, mySpacing, - myNullSize, mySymSize); + shared_ptr cifGuard( + new GuardIntervalInserter(myNbSymbols, mySpacing, + myNullSize, mySymSize)); + + FIRFilter* cifFilter = NULL; if (myFilterTapsFilename != "") { cifFilter = new FIRFilter(myFilterTapsFilename); cifFilter->enrol_at(*myRCs); } - myOutput = new OutputMemory(); + shared_ptr myOutput(new OutputMemory(dataOut)); + Resampler* cifRes = NULL; if (myOutputRate != 2048000) { cifRes = new Resampler(2048000, myOutputRate, mySpacing); } else { @@ -222,10 +228,7 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) //////////////////////////////////////////////////////////////// // Processing FIC //////////////////////////////////////////////////////////////// - FicSource* fic = myEtiReader.getFic(); - PrbsGenerator* ficPrbs = NULL; - ConvEncoder* ficConv = NULL; - PuncturingEncoder* ficPunc = NULL; + shared_ptr fic(myEtiReader.getFic()); //////////////////////////////////////////////////////////////// // Data initialisation //////////////////////////////////////////////////////////////// @@ -241,13 +244,13 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) PDEBUG(" Framesize: %zu\n", fic->getFramesize()); // Configuring prbs generator - ficPrbs = new PrbsGenerator(myFicSizeIn, 0x110); + shared_ptr ficPrbs(new PrbsGenerator(myFicSizeIn, 0x110)); // Configuring convolutionnal encoder - ficConv = new ConvEncoder(myFicSizeIn); + shared_ptr ficConv(new ConvEncoder(myFicSizeIn)); // Configuring puncturing encoder - ficPunc = new PuncturingEncoder(); + shared_ptr ficPunc(new PuncturingEncoder()); std::vector rules = fic->get_rules(); std::vector::const_iterator rule; for (rule = rules.begin(); rule != rules.end(); ++rule) { @@ -267,16 +270,12 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) //////////////////////////////////////////////////////////////// // Configuring subchannels //////////////////////////////////////////////////////////////// - std::vector subchannels = + std::vector > subchannels = myEtiReader.getSubchannels(); - std::vector::const_iterator subchannel; + std::vector >::const_iterator subchannel; for (subchannel = subchannels.begin(); subchannel != subchannels.end(); ++subchannel) { - PrbsGenerator* subchPrbs = NULL; - ConvEncoder* subchConv = NULL; - PuncturingEncoder* subchPunc = NULL; - TimeInterleaver* subchInterleaver = NULL; //////////////////////////////////////////////////////////// // Data initialisation @@ -307,13 +306,17 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) (*subchannel)->protectionOption()); // Configuring prbs genrerator - subchPrbs = new PrbsGenerator(subchSizeIn, 0x110); + shared_ptr subchPrbs( + new PrbsGenerator(subchSizeIn, 0x110)); // Configuring convolutionnal encoder - subchConv = new ConvEncoder(subchSizeIn); + shared_ptr subchConv( + new ConvEncoder(subchSizeIn)); // Configuring puncturing encoder - subchPunc = new PuncturingEncoder(); + shared_ptr subchPunc( + new PuncturingEncoder()); + std::vector rules = (*subchannel)->get_rules(); std::vector::const_iterator rule; for (rule = rules.begin(); rule != rules.end(); ++rule) { @@ -326,7 +329,8 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) subchPunc->append_tail_rule(PuncturingRule(3, 0xcccccc)); // Configuring time interleaver - subchInterleaver = new TimeInterleaver(subchSizeOut); + shared_ptr subchInterleaver( + new TimeInterleaver(subchSizeOut)); myFlowgraph->connect(*subchannel, subchPrbs); myFlowgraph->connect(subchPrbs, subchConv); @@ -342,7 +346,7 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) myFlowgraph->connect(cifFreq, cifDiff); myFlowgraph->connect(cifNull, cifSig); myFlowgraph->connect(cifDiff, cifSig); - if (myClockRate) { + if (myClockRate) { // TODO review myFlowgraph->connect(cifSig, cifCicEq); myFlowgraph->connect(cifCicEq, cifOfdm); } else { @@ -352,18 +356,21 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) myFlowgraph->connect(cifGain, cifGuard); if (myFilterTapsFilename != "") { - myFlowgraph->connect(cifGuard, cifFilter); + shared_ptr cifFilterptr(cifFilter); + myFlowgraph->connect(cifGuard, cifFilterptr); if (cifRes != NULL) { - myFlowgraph->connect(cifFilter, cifRes); - myFlowgraph->connect(cifRes, myOutput); + shared_ptr res(cifRes); + myFlowgraph->connect(cifFilterptr, res); + myFlowgraph->connect(res, myOutput); } else { - myFlowgraph->connect(cifFilter, myOutput); + myFlowgraph->connect(cifFilterptr, myOutput); } } else { //no filtering if (cifRes != NULL) { - myFlowgraph->connect(cifGuard, cifRes); - myFlowgraph->connect(cifRes, myOutput); + shared_ptr res(cifRes); + myFlowgraph->connect(cifGuard, res); + myFlowgraph->connect(res, myOutput); } else { myFlowgraph->connect(cifGuard, myOutput); } @@ -374,6 +381,6 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) //////////////////////////////////////////////////////////////////// // Proccessing data //////////////////////////////////////////////////////////////////// - myOutput->setOutput(dataOut); return myFlowgraph->run(); } + diff --git a/src/DabModulator.h b/src/DabModulator.h index 84c9926..89ddd7c 100644 --- a/src/DabModulator.h +++ b/src/DabModulator.h @@ -3,8 +3,10 @@ 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) 2015 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org */ /* This file is part of ODR-DabMod. @@ -32,6 +34,7 @@ #include #include +#include #include "ModCodec.h" #include "EtiReader.h" @@ -88,5 +91,5 @@ protected: size_t myFicSizeIn; }; - #endif // DAB_MODULATOR_H + diff --git a/src/EtiReader.cpp b/src/EtiReader.cpp index fe54f55..7e0df72 100644 --- a/src/EtiReader.cpp +++ b/src/EtiReader.cpp @@ -2,7 +2,7 @@ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2014 + Copyright (C) 2014, 2015 Matthias P. Braendli, matthias.braendli@mpb.li http://opendigitalradio.org @@ -34,6 +34,7 @@ #include #include +using namespace boost; enum ETI_READER_STATE { EtiReaderStateNbFrame, @@ -69,9 +70,6 @@ EtiReader::~EtiReader() // if (myFicSource != NULL) { // delete myFicSource; // } -// for (unsigned i = 0; i < mySources.size(); ++i) { -// delete mySources[i]; -// } } @@ -93,13 +91,13 @@ unsigned EtiReader::getFp() } -const std::vector& EtiReader::getSubchannels() +const std::vector >& EtiReader::getSubchannels() { return mySources; } -int EtiReader::process(Buffer* dataIn) +int EtiReader::process(const Buffer* dataIn) { PDEBUG("EtiReader::process(dataIn: %p)\n", dataIn); PDEBUG(" state: %u\n", state); @@ -171,13 +169,12 @@ int EtiReader::process(Buffer* dataIn) (memcmp(&eti_stc[0], in, 4 * eti_fc.NST))) { PDEBUG("New stc!\n"); eti_stc.resize(eti_fc.NST); - for (unsigned i = 0; i < mySources.size(); ++i) { - delete mySources[i]; - } - mySources.resize(eti_fc.NST); memcpy(&eti_stc[0], in, 4 * eti_fc.NST); + + mySources.clear(); for (unsigned i = 0; i < eti_fc.NST; ++i) { - mySources[i] = new SubchannelSource(eti_stc[i]); + mySources.push_back(shared_ptr( + new SubchannelSource(eti_stc[i]))); PDEBUG("Sstc %u:\n", i); PDEBUG(" Stc%i.scid: %i\n", i, eti_stc[i].SCID); PDEBUG(" Stc%i.sad: %u\n", i, eti_stc[i].getStartAddress()); diff --git a/src/EtiReader.h b/src/EtiReader.h index 209b208..136bd1c 100644 --- a/src/EtiReader.h +++ b/src/EtiReader.h @@ -2,7 +2,7 @@ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2014 + Copyright (C) 2014, 2015 Matthias P. Braendli, matthias.braendli@mpb.li http://opendigitalradio.org @@ -41,6 +41,7 @@ #include #include #include +#include class EtiReader @@ -54,8 +55,8 @@ public: FicSource* getFic(); unsigned getMode(); unsigned getFp(); - const std::vector& getSubchannels(); - int process(Buffer* dataIn); + const std::vector >& getSubchannels(); + int process(const Buffer* dataIn); void calculateTimestamp(struct frame_timestamp& ts) { @@ -83,9 +84,9 @@ protected: eti_EOF eti_eof; eti_TIST eti_tist; FicSource* myFicSource; - std::vector mySources; + std::vector > mySources; TimestampDecoder myTimestampDecoder; - + private: size_t myCurrentFrame; bool time_ext_enabled; @@ -94,3 +95,4 @@ private: #endif // ETI_READER_H + diff --git a/src/Flowgraph.cpp b/src/Flowgraph.cpp index 373533b..22f604b 100644 --- a/src/Flowgraph.cpp +++ b/src/Flowgraph.cpp @@ -1,6 +1,11 @@ /* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) + + Copyright (C) 2015 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org */ /* This file is part of ODR-DabMod. @@ -38,19 +43,18 @@ #include #endif -#include - using namespace boost; typedef std::vector >::iterator NodeIterator; typedef std::vector >::iterator EdgeIterator; -Node::Node(ModPlugin* plugin) : +Node::Node(shared_ptr plugin) : myPlugin(plugin), myProcessTime(0) { - PDEBUG("Node::Node(plugin(%s): %p) @ %p\n", plugin->name(), plugin, this); + PDEBUG("Node::Node(plugin(%s): %p) @ %p\n", + plugin->name(), plugin.get(), this); } @@ -59,9 +63,6 @@ Node::~Node() { PDEBUG("Node::~Node() @ %p\n", this); - if (myPlugin != NULL) { - delete myPlugin; - } assert(myInputBuffers.size() == 0); assert(myOutputBuffers.size() == 0); } @@ -72,8 +73,8 @@ Edge::Edge(shared_ptr& srcNode, shared_ptr& dstNode) : myDstNode(dstNode) { PDEBUG("Edge::Edge(srcNode(%s): %p, dstNode(%s): %p) @ %p\n", - srcNode->plugin()->name(), srcNode, - dstNode->plugin()->name(), dstNode, + srcNode->plugin()->name(), srcNode.get(), + dstNode->plugin()->name(), dstNode.get(), this); myBuffer = shared_ptr(new Buffer()); @@ -112,7 +113,7 @@ Edge::~Edge() int Node::process() { PDEBUG("Edge::process()\n"); - PDEBUG(" Plugin name: %s (%p)\n", myPlugin->name(), myPlugin); + PDEBUG(" Plugin name: %s (%p)\n", myPlugin->name(), myPlugin.get()); // the plugin process() still wants vector // arguments. @@ -165,11 +166,10 @@ Flowgraph::~Flowgraph() } } - -void Flowgraph::connect(ModPlugin* input, ModPlugin* output) +void Flowgraph::connect(shared_ptr input, shared_ptr output) { PDEBUG("Flowgraph::connect(input(%s): %p, output(%s): %p)\n", - input->name(), input, output->name(), output); + input->name(), input.get(), output->name(), output.get()); NodeIterator inputNode; NodeIterator outputNode; @@ -237,3 +237,4 @@ bool Flowgraph::run() } return true; } + diff --git a/src/Flowgraph.h b/src/Flowgraph.h index 00b8d42..1129668 100644 --- a/src/Flowgraph.h +++ b/src/Flowgraph.h @@ -1,6 +1,11 @@ /* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) + + Copyright (C) 2015 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org */ /* This file is part of ODR-DabMod. @@ -38,12 +43,12 @@ class Node { public: - Node(ModPlugin* plugin); + Node(boost::shared_ptr plugin); ~Node(); Node(const Node&); Node& operator=(const Node&); - ModPlugin* plugin() { return myPlugin; } + boost::shared_ptr plugin() { return myPlugin; } std::vector > myInputBuffers; std::vector > myOutputBuffers; @@ -55,7 +60,7 @@ public: } protected: - ModPlugin* myPlugin; + boost::shared_ptr myPlugin; time_t myProcessTime; }; @@ -83,7 +88,8 @@ public: Flowgraph(const Flowgraph&); Flowgraph& operator=(const Flowgraph&); - void connect(ModPlugin* input, ModPlugin* output); + void connect(boost::shared_ptr input, + boost::shared_ptr output); bool run(); protected: diff --git a/src/FrameMultiplexer.cpp b/src/FrameMultiplexer.cpp index c5e58b7..843f72d 100644 --- a/src/FrameMultiplexer.cpp +++ b/src/FrameMultiplexer.cpp @@ -30,8 +30,11 @@ typedef std::complex complexf; +using namespace boost; -FrameMultiplexer::FrameMultiplexer(size_t framesize, const std::vector* subchannels) : +FrameMultiplexer::FrameMultiplexer( + size_t framesize, + const std::vector >* subchannels) : ModMux(ModFormat(framesize), ModFormat(framesize)), d_frameSize(framesize), mySubchannels(subchannels) @@ -76,7 +79,7 @@ int FrameMultiplexer::process(std::vector dataIn, Buffer* dataOut) ++in; // Write subchannel assert(mySubchannels->size() == dataIn.size() - 1); - std::vector::const_iterator subchannel = + std::vector >::const_iterator subchannel = mySubchannels->begin(); while (in != dataIn.end()) { assert((*subchannel)->framesizeCu() * 8 == (*in)->getLength()); @@ -88,3 +91,4 @@ int FrameMultiplexer::process(std::vector dataIn, Buffer* dataOut) return dataOut->getLength(); } + diff --git a/src/FrameMultiplexer.h b/src/FrameMultiplexer.h index f1bd587..ba571f6 100644 --- a/src/FrameMultiplexer.h +++ b/src/FrameMultiplexer.h @@ -29,7 +29,7 @@ #include "ModMux.h" #include "SubchannelSource.h" - +#include #include @@ -37,7 +37,8 @@ class FrameMultiplexer : public ModMux { public: - FrameMultiplexer(size_t frameSize, const std::vector* subchannels); + FrameMultiplexer(size_t frameSize, + const std::vector >* subchannels); virtual ~FrameMultiplexer(); FrameMultiplexer(const FrameMultiplexer&); FrameMultiplexer& operator=(const FrameMultiplexer&); @@ -48,8 +49,8 @@ public: protected: size_t d_frameSize; - const std::vector* mySubchannels; + const std::vector >* mySubchannels; }; - #endif // FRAME_MULTIPLEXER_H + diff --git a/src/OutputMemory.h b/src/OutputMemory.h index 2dd49c5..56cbc01 100644 --- a/src/OutputMemory.h +++ b/src/OutputMemory.h @@ -50,7 +50,7 @@ class OutputMemory : public ModOutput { public: - OutputMemory(Buffer* dataOut = NULL); + OutputMemory(Buffer* dataOut); virtual ~OutputMemory(); virtual int process(Buffer* dataIn, Buffer* dataOut); const char* name() { return "OutputMemory"; } -- cgit v1.2.3 From 1ada0901a8fa687576fa4953044fd43bc6c06f8a Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 22 Feb 2015 17:56:49 +0100 Subject: Move main flowgraph to distinct function --- src/DabMod.cpp | 193 ++++++++++++++++++++++++++++++---------------- src/InputReader.h | 2 + src/InputZeroMQReader.cpp | 11 +++ 3 files changed, 141 insertions(+), 65 deletions(-) diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 1f6eedf..8178a75 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -85,6 +85,30 @@ void signalHandler(int signalNb) running = 0; } +struct modulator_data +{ + modulator_data() : + inputReader(NULL), + framecount(0), + flowgraph(NULL), + rcs(NULL) {} + + InputReader* inputReader; + Buffer data; + uint64_t framecount; + + Flowgraph* flowgraph; + RemoteControllers* rcs; +}; + +enum run_modulator_state { + MOD_FAILURE, + MOD_NORMAL_END, + MOD_AGAIN +}; + +run_modulator_state run_modulator(modulator_data& m); + int main(int argc, char* argv[]) { int ret = 0; @@ -99,14 +123,12 @@ int main(int argc, char* argv[]) std::string fileOutputFormat = "complexf"; int useUHDOutput = 0; - uint64_t frame = 0; size_t outputRate = 2048000; size_t clockRate = 0; unsigned dabMode = 0; float digitalgain = 1.0f; float normalise = 1.0f; GainMode gainMode = GAIN_VAR; - Buffer data; /* UHD requires the input I and Q samples to be in the interval @@ -130,6 +152,8 @@ int main(int argc, char* argv[]) OutputUHDConfig outputuhd_conf; #endif + modulator_data m; + // To handle the timestamp offset of the modulator struct modulator_offset_config modconf; modconf.use_offset_file = false; @@ -141,13 +165,15 @@ int main(int argc, char* argv[]) shared_ptr output; RemoteControllers rcs; + m.rcs = &rcs; + + bool run_again = true; Logger logger; InputFileReader inputFileReader(logger); #if defined(HAVE_ZEROMQ) InputZeroMQReader inputZeroMQReader(logger); #endif - InputReader* inputReader; struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction)); @@ -673,7 +699,7 @@ int main(int argc, char* argv[]) throw std::runtime_error("Unable to open input"); } - inputReader = &inputFileReader; + m.inputReader = &inputFileReader; } else if (inputTransport == "zeromq") { #if !defined(HAVE_ZEROMQ) @@ -688,7 +714,7 @@ int main(int argc, char* argv[]) else { inputZeroMQReader.Open(inputName, inputMaxFramesQueued); } - inputReader = &inputZeroMQReader; + m.inputReader = &inputZeroMQReader; #endif } else @@ -698,59 +724,103 @@ int main(int argc, char* argv[]) throw std::runtime_error("Unable to open input"); } - if (useFileOutput) { - if (fileOutputFormat == "complexf") { - output = shared_ptr(new OutputFile(outputName)); - } - else if (fileOutputFormat == "s8") { - // We must normalise the samples to the interval [-127.0; 127.0] - normalise = 127.0f / normalise_factor; + while (run_again) { + Flowgraph flowgraph; - format_converter = shared_ptr(new FormatConverter()); + if (useFileOutput) { + if (fileOutputFormat == "complexf") { + output = shared_ptr(new OutputFile(outputName)); + } + else if (fileOutputFormat == "s8") { + // We must normalise the samples to the interval [-127.0; 127.0] + normalise = 127.0f / normalise_factor; - output = shared_ptr(new OutputFile(outputName)); + format_converter = shared_ptr(new FormatConverter()); + + output = shared_ptr(new OutputFile(outputName)); + } } - } #if defined(HAVE_OUTPUT_UHD) - else if (useUHDOutput) { - - normalise = 1.0f / normalise_factor; - - outputuhd_conf.sampleRate = outputRate; - output = shared_ptr(new OutputUHD(outputuhd_conf, logger)); - ((OutputUHD*)output.get())->enrol_at(rcs); - } + else if (useUHDOutput) { + normalise = 1.0f / normalise_factor; + outputuhd_conf.sampleRate = outputRate; + output = shared_ptr(new OutputUHD(outputuhd_conf, logger)); + ((OutputUHD*)output.get())->enrol_at(rcs); + } #endif #if defined(HAVE_ZEROMQ) - else if (useZeroMQOutput) { - /* We normalise the same way as for the UHD output */ - normalise = 1.0f / normalise_factor; - - output = shared_ptr(new OutputZeroMQ(outputName)); - } + else if (useZeroMQOutput) { + /* We normalise the same way as for the UHD output */ + normalise = 1.0f / normalise_factor; + output = shared_ptr(new OutputZeroMQ(outputName)); + } #endif - data.setLength(6144); - shared_ptr input(new InputMemory(&data)); - shared_ptr modulator(new DabModulator(modconf, &rcs, logger, outputRate, clockRate, - dabMode, gainMode, digitalgain, normalise, filterTapsFilename)); - flowgraph->connect(input, modulator); - if (format_converter) { - flowgraph->connect(modulator, format_converter); - flowgraph->connect(format_converter, output); - } - else { - flowgraph->connect(modulator, output); - } + m.flowgraph = &flowgraph; + m.data.setLength(6144); + + shared_ptr input(new InputMemory(&m.data)); + shared_ptr modulator( + new DabModulator(modconf, &rcs, logger, outputRate, clockRate, + dabMode, gainMode, digitalgain, normalise, filterTapsFilename)); + + flowgraph.connect(input, modulator); + if (format_converter) { + flowgraph.connect(modulator, format_converter); + flowgraph.connect(format_converter, output); + } + else { + flowgraph.connect(modulator, output); + } #if defined(HAVE_OUTPUT_UHD) - if (useUHDOutput) { - ((OutputUHD*)output.get())->setETIReader(modulator->getEtiReader()); - } + if (useUHDOutput) { + ((OutputUHD*)output.get())->setETIReader(modulator->getEtiReader()); + } #endif - inputReader->PrintInfo(); + m.inputReader->PrintInfo(); + + run_modulator_state st = run_modulator(m); + + switch (st) { + case MOD_FAILURE: + fprintf(stderr, "\nModulator failure.\n"); + run_again = false; + ret = 1; + break; + case MOD_NORMAL_END: + fprintf(stderr, "\nModulator stopped.\n"); + ret = 0; + run_again = false; + break; + case MOD_AGAIN: + fprintf(stderr, "\nRestart modulator\n"); + run_again = true; + running = true; + break; + } + fprintf(stderr, "\n\n"); + fprintf(stderr, "%lu DAB frames encoded\n", m.framecount); + fprintf(stderr, "%f seconds encoded\n", (float)m.framecount * 0.024f); + + fprintf(stderr, "\nCleaning flowgraph...\n"); + + m.data.setLength(0); + } + + //////////////////////////////////////////////////////////////////////// + // Cleaning things + //////////////////////////////////////////////////////////////////////// + + logger.level(info) << "Terminating"; + return ret; +} + +run_modulator_state run_modulator(modulator_data& m) +{ + run_modulator_state ret = MOD_FAILURE; try { while (running) { @@ -759,26 +829,26 @@ int main(int argc, char* argv[]) PDEBUG("*****************************************\n"); PDEBUG("* Starting main loop\n"); PDEBUG("*****************************************\n"); - while ((framesize = inputReader->GetNextFrame(data.getData())) > 0) { + while ((framesize = m.inputReader->GetNextFrame(m.data.getData())) > 0) { if (!running) { break; } - frame++; + m.framecount++; PDEBUG("*****************************************\n"); - PDEBUG("* Read frame %lu\n", frame); + PDEBUG("* Read frame %lu\n", m.framecount); PDEBUG("*****************************************\n"); //////////////////////////////////////////////////////////////// - // Proccessing data + // Processing data //////////////////////////////////////////////////////////////// - flowgraph->run(); + m.flowgraph->run(); /* Check every once in a while if the remote control * is still working */ - if (rcs.get_no_controllers() > 0 && (frame % 250) == 0) { - rcs.check_faults(); + if (m.rcs->get_no_controllers() > 0 && (m.framecount % 250) == 0) { + m.rcs->check_faults(); } } if (framesize == 0) { @@ -788,24 +858,17 @@ int main(int argc, char* argv[]) fprintf(stderr, "Input read error.\n"); } running = 0; + ret = MOD_NORMAL_END; } + } catch (std::overflow_error& e) { + // The ZeroMQ input has overflowed its buffer + fprintf(stderr, "overflow error: %s\n", e.what()); + ret = MOD_AGAIN; } catch (std::exception& e) { fprintf(stderr, "EXCEPTION: %s\n", e.what()); - ret = -1; + ret = MOD_FAILURE; } - //////////////////////////////////////////////////////////////////////// - // Cleaning things - //////////////////////////////////////////////////////////////////////// - fprintf(stderr, "\n\n"); - fprintf(stderr, "%lu DAB frames encoded\n", frame); - fprintf(stderr, "%f seconds encoded\n", (float)frame * 0.024f); - - // Cif - fprintf(stderr, "\nCleaning buffers...\n"); - - logger.level(info) << "Terminating"; - return ret; } diff --git a/src/InputReader.h b/src/InputReader.h index 3e3e000..ee7d657 100644 --- a/src/InputReader.h +++ b/src/InputReader.h @@ -138,6 +138,8 @@ struct InputZeroMQThreadData ThreadsafeQueue *in_messages; std::string uri; unsigned max_queued_frames; + + bool running; }; class InputZeroMQWorker diff --git a/src/InputZeroMQReader.cpp b/src/InputZeroMQReader.cpp index 01d8720..5fab447 100644 --- a/src/InputZeroMQReader.cpp +++ b/src/InputZeroMQReader.cpp @@ -80,6 +80,10 @@ int InputZeroMQReader::GetNextFrame(void* buffer) uint8_t* incoming; in_messages_.wait_and_pop(incoming); + if (! workerdata_.running) { + throw std::overflow_error("InputZeroMQ worker dead"); + } + memcpy(buffer, incoming, framesize); delete incoming; @@ -174,6 +178,7 @@ void InputZeroMQWorker::RecvProcess(struct InputZeroMQThreadData* workerdata) fprintf(stderr, "ZeroMQ buffer overfull !\n"); buffer_full = true; + throw std::runtime_error("ZMQ input full"); } queue_size = workerdata->in_messages->size(); @@ -195,15 +200,21 @@ void InputZeroMQWorker::RecvProcess(struct InputZeroMQThreadData* workerdata) catch (zmq::error_t& err) { fprintf(stderr, "ZeroMQ error in RecvProcess: '%s'\n", err.what()); } + catch (std::exception& err) { + } fprintf(stderr, "ZeroMQ input worker terminated\n"); subscriber.close(); + + workerdata->running = false; + workerdata->in_messages->notify(); } void InputZeroMQWorker::Start(struct InputZeroMQThreadData* workerdata) { running = true; + workerdata->running = true; recv_thread = boost::thread(&InputZeroMQWorker::RecvProcess, this, workerdata); } -- cgit v1.2.3 From 87b708657a78cac4690ba81967e5ca03d7faab09 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 22 Feb 2015 21:39:56 +0100 Subject: Restart full modulator on ZeroMQ input overrun --- src/DabMod.cpp | 82 +++++++++++++++++++++++++---------------------- src/InputReader.h | 1 + src/InputZeroMQReader.cpp | 9 +++++- src/OutputUHD.cpp | 4 ++- 4 files changed, 56 insertions(+), 40 deletions(-) diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 8178a75..3548f9d 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -172,7 +172,7 @@ int main(int argc, char* argv[]) Logger logger; InputFileReader inputFileReader(logger); #if defined(HAVE_ZEROMQ) - InputZeroMQReader inputZeroMQReader(logger); + shared_ptr inputZeroMQReader(new InputZeroMQReader(logger)); #endif struct sigaction sa; @@ -707,14 +707,8 @@ int main(int argc, char* argv[]) ret = -1; throw std::runtime_error("Unable to open input"); #else - // The URL might start with zmq+tcp:// - if (inputName.substr(0, 4) == "zmq+") { - inputZeroMQReader.Open(inputName.substr(4), inputMaxFramesQueued); - } - else { - inputZeroMQReader.Open(inputName, inputMaxFramesQueued); - } - m.inputReader = &inputZeroMQReader; + inputZeroMQReader->Open(inputName, inputMaxFramesQueued); + m.inputReader = inputZeroMQReader.get(); #endif } else @@ -724,38 +718,39 @@ int main(int argc, char* argv[]) throw std::runtime_error("Unable to open input"); } - while (run_again) { - Flowgraph flowgraph; - - if (useFileOutput) { - if (fileOutputFormat == "complexf") { - output = shared_ptr(new OutputFile(outputName)); - } - else if (fileOutputFormat == "s8") { - // We must normalise the samples to the interval [-127.0; 127.0] - normalise = 127.0f / normalise_factor; + if (useFileOutput) { + if (fileOutputFormat == "complexf") { + output = shared_ptr(new OutputFile(outputName)); + } + else if (fileOutputFormat == "s8") { + // We must normalise the samples to the interval [-127.0; 127.0] + normalise = 127.0f / normalise_factor; - format_converter = shared_ptr(new FormatConverter()); + format_converter = shared_ptr(new FormatConverter()); - output = shared_ptr(new OutputFile(outputName)); - } + output = shared_ptr(new OutputFile(outputName)); } + } #if defined(HAVE_OUTPUT_UHD) - else if (useUHDOutput) { - normalise = 1.0f / normalise_factor; - outputuhd_conf.sampleRate = outputRate; - output = shared_ptr(new OutputUHD(outputuhd_conf, logger)); - ((OutputUHD*)output.get())->enrol_at(rcs); - } + else if (useUHDOutput) { + normalise = 1.0f / normalise_factor; + outputuhd_conf.sampleRate = outputRate; + output = shared_ptr(new OutputUHD(outputuhd_conf, logger)); + ((OutputUHD*)output.get())->enrol_at(rcs); + } #endif #if defined(HAVE_ZEROMQ) - else if (useZeroMQOutput) { - /* We normalise the same way as for the UHD output */ - normalise = 1.0f / normalise_factor; - output = shared_ptr(new OutputZeroMQ(outputName)); - } + else if (useZeroMQOutput) { + /* We normalise the same way as for the UHD output */ + normalise = 1.0f / normalise_factor; + output = shared_ptr(new OutputZeroMQ(outputName)); + } #endif + + while (run_again) { + Flowgraph flowgraph; + m.flowgraph = &flowgraph; m.data.setLength(6144); @@ -789,16 +784,27 @@ int main(int argc, char* argv[]) run_again = false; ret = 1; break; +#if defined(HAVE_ZEROMQ) + case MOD_AGAIN: + fprintf(stderr, "\nRestart modulator\n"); + running = true; + if (inputTransport == "zeromq") { + run_again = true; + + // Create a new input reader + inputZeroMQReader = shared_ptr( + new InputZeroMQReader(logger)); + inputZeroMQReader->Open(inputName, inputMaxFramesQueued); + m.inputReader = inputZeroMQReader.get(); + } + break; +#endif case MOD_NORMAL_END: + default: fprintf(stderr, "\nModulator stopped.\n"); ret = 0; run_again = false; break; - case MOD_AGAIN: - fprintf(stderr, "\nRestart modulator\n"); - run_again = true; - running = true; - break; } fprintf(stderr, "\n\n"); diff --git a/src/InputReader.h b/src/InputReader.h index ee7d657..e45e36d 100644 --- a/src/InputReader.h +++ b/src/InputReader.h @@ -175,6 +175,7 @@ class InputZeroMQReader : public InputReader logger_(logger), in_messages_(10) { workerdata_.in_messages = &in_messages_; + workerdata_.running = false; } ~InputZeroMQReader() diff --git a/src/InputZeroMQReader.cpp b/src/InputZeroMQReader.cpp index 5fab447..7ac7d41 100644 --- a/src/InputZeroMQReader.cpp +++ b/src/InputZeroMQReader.cpp @@ -64,7 +64,14 @@ struct zmq_dab_message_t int InputZeroMQReader::Open(const std::string& uri, unsigned max_queued_frames) { - uri_ = uri; + // The URL might start with zmq+tcp:// + if (uri.substr(0, 4) == "zmq+") { + uri_ = uri.substr(4); + } + else { + uri_ = uri; + } + workerdata_.uri = uri; workerdata_.max_queued_frames = max_queued_frames; // launch receiver thread diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index d033700..efdf6df 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -496,7 +496,7 @@ void UHDWorker::process() md.time_spec = uhd::time_spec_t(tx_second, pps_offset); // md is defined, let's do some checks - if (md.time_spec.get_real_secs() + 0.2 < usrp_time) { + if (md.time_spec.get_real_secs() + timeout < usrp_time) { uwd->logger->level(warn) << "OutputUHD: Timestamp in the past! offset: " << md.time_spec.get_real_secs() - usrp_time << @@ -507,12 +507,14 @@ void UHDWorker::process() goto loopend; //skip the frame } +#if 0 // Let uhd handle this if (md.time_spec.get_real_secs() > usrp_time + TIMESTAMP_MARGIN_FUTURE) { uwd->logger->level(warn) << "OutputUHD: Timestamp too far in the future! offset: " << md.time_spec.get_real_secs() - usrp_time; usleep(20000); //sleep so as to fill buffers } +#endif if (md.time_spec.get_real_secs() > usrp_time + TIMESTAMP_ABORT_FUTURE) { uwd->logger->level(error) << -- cgit v1.2.3 From 3a7feed2e6e24b1e68ba44969fbcbd9f957fc446 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 22 Feb 2015 21:46:17 +0100 Subject: Change enable criteria for CicEq This needs a review, it's not clear if this is still relevant for recent USRPs. --- src/DabModulator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp index 287280c..667d885 100644 --- a/src/DabModulator.cpp +++ b/src/DabModulator.cpp @@ -346,7 +346,7 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) myFlowgraph->connect(cifFreq, cifDiff); myFlowgraph->connect(cifNull, cifSig); myFlowgraph->connect(cifDiff, cifSig); - if (myClockRate) { // TODO review + if (useCicEq) { myFlowgraph->connect(cifSig, cifCicEq); myFlowgraph->connect(cifCicEq, cifOfdm); } else { -- cgit v1.2.3 From 5971e74e6b23b9980af23ac35f3032970adc426b Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 27 Feb 2015 10:48:34 +0100 Subject: Remove incomplete OutputUHD iqbalance --- src/OutputUHD.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index efdf6df..54acf40 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -91,7 +91,6 @@ OutputUHD::OutputUHD( 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(iqbalance, "Set I/Q balance between 0 and 1.0"); uhd::set_thread_priority_safe(); @@ -707,11 +706,6 @@ void OutputUHD::set_parameter(const string& parameter, const string& value) myStaticDelayUs = newStaticDelayUs; } } - else if (parameter == "iqbalance") { - ss >> myConf.frequency; - myUsrp->set_tx_freq(myConf.frequency); - myConf.frequency = myUsrp->get_tx_freq(); - } else { stringstream ss; ss << "Parameter '" << parameter -- cgit v1.2.3 From b11eff2c8c913d470897e5395b240939ed46dc35 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 27 Feb 2015 13:52:54 +0100 Subject: Restart whole modulator on FCT discontinuity --- src/DabMod.cpp | 4 ++++ src/OutputUHD.cpp | 39 +++++++++++++++++++++++++++++++++------ src/OutputUHD.h | 27 ++++++++++++++++++--------- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 3548f9d..2489797 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -866,6 +866,10 @@ run_modulator_state run_modulator(modulator_data& m) running = 0; ret = MOD_NORMAL_END; } + } catch (fct_discontinuity_error& e) { + // The OutputUHD saw a FCT discontinuity + fprintf(stderr, "Stream discontinuity\n"); + ret = MOD_AGAIN; } catch (std::overflow_error& e) { // The ZeroMQ input has overflowed its buffer fprintf(stderr, "overflow error: %s\n", e.what()); diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index 54acf40..a877161 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -230,8 +230,6 @@ OutputUHD::OutputUHD( mySyncBarrier = b; uwd.sync_barrier = b; - worker.start(&uwd); - MDEBUG("OutputUHD:UHD ready.\n"); } @@ -288,6 +286,8 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) if (first_run) { myLogger.level(debug) << "OutputUHD: UHD initialising..."; + worker.start(&uwd); + uwd.bufsize = dataIn->getLength(); uwd.frame0.buf = malloc(uwd.bufsize); uwd.frame1.buf = malloc(uwd.bufsize); @@ -332,6 +332,19 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) } mySyncBarrier.get()->wait(); + if (!uwd.running) { + worker.stop(); + first_run = true; + if (uwd.failed_due_to_fct) { + throw fct_discontinuity_error(); + } + else { + myLogger.level(error) << + "OutputUHD: Error, UHD worker failed"; + throw std::runtime_error("UHD worker failed"); + } + } + // write into the our buffer while // the worker sends the other. @@ -374,6 +387,21 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) } +void UHDWorker::process_errhandler() +{ + try { + process(); + } + catch (fct_discontinuity_error& e) { + uwd->logger->level(warn) << e.what(); + uwd->failed_due_to_fct = true; + } + + uwd->running = false; + uwd->sync_barrier.get()->wait(); + uwd->logger->level(warn) << "UHD worker terminated"; +} + void UHDWorker::process() { int workerbuffer = 0; @@ -409,7 +437,7 @@ void UHDWorker::process() int expected_next_fct = -1; - while (running) { + while (uwd->running) { bool fct_discontinuity = false; md.has_time_spec = false; md.time_spec = uhd::time_spec_t(0.0); @@ -449,6 +477,7 @@ void UHDWorker::process() "OutputUHD: Incorrect expect fct " << frame->ts.fct; fct_discontinuity = true; + throw fct_discontinuity_error(); } } @@ -553,7 +582,7 @@ void UHDWorker::process() PDEBUG("UHDWorker::process:max_num_samps: %zu.\n", usrp_max_num_samps); - while (running && !uwd->muting && (num_acc_samps < sizeIn)) { + while (uwd->running && !uwd->muting && (num_acc_samps < sizeIn)) { size_t samps_to_send = std::min(sizeIn - num_acc_samps, usrp_max_num_samps); //ensure the the last packet has EOB set if the timestamps has been @@ -665,8 +694,6 @@ loopend: // swap buffers workerbuffer = (workerbuffer + 1) % 2; } - - uwd->logger->level(warn) << "UHD worker terminated"; } diff --git a/src/OutputUHD.h b/src/OutputUHD.h index c5d561b..d92c7a4 100644 --- a/src/OutputUHD.h +++ b/src/OutputUHD.h @@ -83,9 +83,20 @@ struct UHDWorkerFrameData { struct frame_timestamp ts; }; +struct fct_discontinuity_error : public std::exception +{ + const char* what () const throw () + { + return "FCT discontinuity detected"; + } +}; + enum refclk_lock_loss_behaviour_t { CRASH, IGNORE }; struct UHDWorkerData { + bool running; + bool failed_due_to_fct; + #if FAKE_UHD == 0 uhd::usrp::multi_usrp::sptr myUsrp; #endif @@ -130,28 +141,26 @@ struct UHDWorkerData { class UHDWorker { public: - UHDWorker () { - running = false; - } - void start(struct UHDWorkerData *uhdworkerdata) { - running = true; uwd = uhdworkerdata; - uhd_thread = boost::thread(&UHDWorker::process, this); + + uwd->running = true; + uwd->failed_due_to_fct = false; + uhd_thread = boost::thread(&UHDWorker::process_errhandler, this); } void stop() { - running = false; + uwd->running = false; uhd_thread.interrupt(); uhd_thread.join(); } + private: void process(); + void process_errhandler(); - private: struct UHDWorkerData *uwd; - bool running; boost::thread uhd_thread; uhd::tx_streamer::sptr myTxStream; -- cgit v1.2.3 From 1e2a6c6e367849335fd82efb4afc827fd4fe82a6 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 27 Feb 2015 14:16:58 +0100 Subject: Create custom exception for ZMQ overflow --- src/DabMod.cpp | 18 +++++++++--------- src/InputReader.h | 8 ++++++++ src/InputZeroMQReader.cpp | 2 +- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 2489797..6cf1b96 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -107,7 +107,7 @@ enum run_modulator_state { MOD_AGAIN }; -run_modulator_state run_modulator(modulator_data& m); +run_modulator_state run_modulator(Logger& logger, modulator_data& m); int main(int argc, char* argv[]) { @@ -776,7 +776,7 @@ int main(int argc, char* argv[]) m.inputReader->PrintInfo(); - run_modulator_state st = run_modulator(m); + run_modulator_state st = run_modulator(logger, m); switch (st) { case MOD_FAILURE: @@ -824,7 +824,7 @@ int main(int argc, char* argv[]) return ret; } -run_modulator_state run_modulator(modulator_data& m) +run_modulator_state run_modulator(Logger& logger, modulator_data& m) { run_modulator_state ret = MOD_FAILURE; try { @@ -858,24 +858,24 @@ run_modulator_state run_modulator(modulator_data& m) } } if (framesize == 0) { - fprintf(stderr, "End of file reached.\n"); + logger.level(info) << "End of file reached."; } else { - fprintf(stderr, "Input read error.\n"); + logger.level(error) << "Input read error."; } running = 0; ret = MOD_NORMAL_END; } } catch (fct_discontinuity_error& e) { // The OutputUHD saw a FCT discontinuity - fprintf(stderr, "Stream discontinuity\n"); + logger.level(warn) << e.what(); ret = MOD_AGAIN; - } catch (std::overflow_error& e) { + } catch (zmq_input_overflow& e) { // The ZeroMQ input has overflowed its buffer - fprintf(stderr, "overflow error: %s\n", e.what()); + logger.level(warn) << e.what(); ret = MOD_AGAIN; } catch (std::exception& e) { - fprintf(stderr, "EXCEPTION: %s\n", e.what()); + logger.level(error) << "Exception caught: " << e.what(); ret = MOD_FAILURE; } diff --git a/src/InputReader.h b/src/InputReader.h index e45e36d..dcf88cc 100644 --- a/src/InputReader.h +++ b/src/InputReader.h @@ -130,6 +130,14 @@ class InputFileReader : public InputReader // after 2**32 * 24ms ~= 3.3 years }; +struct zmq_input_overflow : public std::exception +{ + const char* what () const throw () + { + return "InputZMQ buffer overflow"; + } +}; + #if defined(HAVE_ZEROMQ) /* A ZeroMQ input. See www.zeromq.org for more info */ diff --git a/src/InputZeroMQReader.cpp b/src/InputZeroMQReader.cpp index 7ac7d41..51909c2 100644 --- a/src/InputZeroMQReader.cpp +++ b/src/InputZeroMQReader.cpp @@ -88,7 +88,7 @@ int InputZeroMQReader::GetNextFrame(void* buffer) in_messages_.wait_and_pop(incoming); if (! workerdata_.running) { - throw std::overflow_error("InputZeroMQ worker dead"); + throw zmq_input_overflow(); } memcpy(buffer, incoming, framesize); -- cgit v1.2.3 From af1bc23a677ce8924d65faacf222201d31dab910 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 22 Mar 2015 17:18:39 +0100 Subject: Fix compilation with disabled UHD --- src/DabMod.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 6cf1b96..83802ab 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -866,10 +866,12 @@ run_modulator_state run_modulator(Logger& logger, modulator_data& m) running = 0; ret = MOD_NORMAL_END; } +#if defined(HAVE_OUTPUT_UHD) } catch (fct_discontinuity_error& e) { // The OutputUHD saw a FCT discontinuity logger.level(warn) << e.what(); ret = MOD_AGAIN; +#endif } catch (zmq_input_overflow& e) { // The ZeroMQ input has overflowed its buffer logger.level(warn) << e.what(); -- cgit v1.2.3 From accdfad612a368542f2d833d0e3d30dc9541b955 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Tue, 7 Apr 2015 22:45:54 +0200 Subject: Fix configure help entry for UHD --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a73ee39..9a88fd9 100644 --- a/configure.ac +++ b/configure.ac @@ -77,7 +77,7 @@ AC_ARG_ENABLE([zeromq], # UHD support control AC_ARG_ENABLE([output_uhd], - [AS_HELP_STRING([--enable-output-uhd], [Enable UHD output])], + [AS_HELP_STRING([--disable-output-uhd], [Disable UHD output])], [], [enable_output_uhd=yes]) AS_IF([test "x$enable_kiss" = "xno"], -- cgit v1.2.3 From 20544fb077beae2ec25eadf73292f091207f1ad2 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 10 Apr 2015 09:09:03 +0200 Subject: Add detail when config file parser fails --- src/DabMod.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 83802ab..75e76e0 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -351,7 +351,8 @@ int main(int argc, char* argv[]) } catch (boost::property_tree::ini_parser::ini_parser_error &e) { - fprintf(stderr, "Error, cannot read configuration file '%s'\n", configuration_file.c_str()); + std::cerr << "Error, cannot read configuration file '" << configuration_file.c_str() << "'" << std::endl; + std::cerr << " " << e.what() << std::endl; throw std::runtime_error("Cannot read configuration file"); } -- cgit v1.2.3 From c4fa1521c1c727e50859df93a29c65913368c923 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 10 Apr 2015 09:31:02 +0200 Subject: Simplify flowgraph print --- src/Flowgraph.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Flowgraph.cpp b/src/Flowgraph.cpp index 22f604b..3844e86 100644 --- a/src/Flowgraph.cpp +++ b/src/Flowgraph.cpp @@ -150,17 +150,15 @@ Flowgraph::~Flowgraph() if (myProcessTime) { fprintf(stderr, "Process time:\n"); - } - std::vector >::const_iterator node; - for (node = nodes.begin(); node != nodes.end(); ++node) { - if (myProcessTime) { + + std::vector >::const_iterator node; + for (node = nodes.begin(); node != nodes.end(); ++node) { fprintf(stderr, " %30s: %10u us (%2.2f %%)\n", (*node)->plugin()->name(), (unsigned)(*node)->processTime(), (*node)->processTime() * 100.0 / myProcessTime); } - } - if (myProcessTime) { + fprintf(stderr, " %30s: %10u us (100.00 %%)\n", "total", (unsigned)myProcessTime); } -- cgit v1.2.3 From 56a0a84466ca661179b534de52f728af450800a8 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 10 Apr 2015 11:00:48 +0200 Subject: Add check for FCT validity --- src/OutputUHD.cpp | 8 +++++++- src/TimestampDecoder.cpp | 4 ++-- src/TimestampDecoder.h | 11 ++++++----- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index a877161..e8950a2 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -471,10 +471,16 @@ void UHDWorker::process() /* Verify that the FCT value is correct. If we miss one transmission * frame we must interrupt UHD and resync to the timestamps */ + if (frame->ts.fct == -1) { + uwd->logger->level(info) << + "OutputUHD: dropping one frame with invalid FCT"; + goto loopend; + } if (expected_next_fct != -1) { if (expected_next_fct != (int)frame->ts.fct) { uwd->logger->level(warn) << - "OutputUHD: Incorrect expect fct " << frame->ts.fct; + "OutputUHD: Incorrect expect fct " << frame->ts.fct << + ", expected " << expected_next_fct; fct_discontinuity = true; throw fct_discontinuity_error(); diff --git a/src/TimestampDecoder.cpp b/src/TimestampDecoder.cpp index 96c84c0..6063048 100644 --- a/src/TimestampDecoder.cpp +++ b/src/TimestampDecoder.cpp @@ -69,7 +69,7 @@ void TimestampDecoder::calculateTimestamp(struct frame_timestamp& ts) ts.timestamp_sec = 0; ts.timestamp_pps_offset = 0; ts.timestamp_refresh = false; - ts.fct = 0; + ts.fct = -1; } else { //fprintf(stderr, ". %zu ", queue_timestamps.size()); @@ -191,7 +191,7 @@ void TimestampDecoder::updateTimestampEti( int framephase, uint16_t mnsc, double pps, - uint32_t fct) + int32_t fct) { updateTimestampPPS(pps); pushMNSCData(framephase, mnsc); diff --git a/src/TimestampDecoder.h b/src/TimestampDecoder.h index 0c393e4..8c6b362 100644 --- a/src/TimestampDecoder.h +++ b/src/TimestampDecoder.h @@ -55,7 +55,7 @@ struct modulator_offset_config struct frame_timestamp { // Which frame count does this timestamp apply to - uint32_t fct; + int32_t fct; uint32_t timestamp_sec; double timestamp_pps_offset; @@ -101,9 +101,10 @@ struct frame_timestamp void print(const char* t) { fprintf(stderr, - "%s \n", + "%s \n", t, this->timestamp_valid ? "valid" : "invalid", - this->timestamp_sec, this->timestamp_pps_offset); + this->timestamp_sec, this->timestamp_pps_offset, + this->fct); } }; @@ -140,7 +141,7 @@ class TimestampDecoder int framephase, uint16_t mnsc, double pps, - uint32_t fct); + int32_t fct); /* Update the modulator timestamp offset according to the modconf */ @@ -167,7 +168,7 @@ class TimestampDecoder struct tm temp_time; uint32_t time_secs; - uint32_t latestFCT; + int32_t latestFCT; double time_pps; double timestamp_offset; int inhibit_second_update; -- cgit v1.2.3 From c126ec3bfc44ab62017e7a75a1a1f49855f46f9a Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 10 Apr 2015 11:19:54 +0200 Subject: 'underfull' sounds wrong --- src/InputZeroMQReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/InputZeroMQReader.cpp b/src/InputZeroMQReader.cpp index 51909c2..f8c15c4 100644 --- a/src/InputZeroMQReader.cpp +++ b/src/InputZeroMQReader.cpp @@ -199,7 +199,7 @@ void InputZeroMQWorker::RecvProcess(struct InputZeroMQThreadData* workerdata) } if (queue_size < 5) { - fprintf(stderr, "ZeroMQ buffer underfull: %zu elements !\n", + fprintf(stderr, "ZeroMQ buffer low: %zu elements !\n", queue_size); } } -- cgit v1.2.3 From 5c3d2648abaedc18e36f2ba99bd70aec0df3b1be Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 10 Apr 2015 11:58:37 +0200 Subject: ZMQ output: Add REP socket type --- doc/example.ini | 13 ++++++++++++- src/DabMod.cpp | 21 ++++++++++++++++++--- src/OutputZeroMQ.cpp | 28 +++++++++++++++++++++++----- src/OutputZeroMQ.h | 5 +++-- 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/doc/example.ini b/doc/example.ini index 3c51142..ee9d567 100644 --- a/doc/example.ini +++ b/doc/example.ini @@ -112,7 +112,7 @@ enabled=0 filtertapsfile=simple_taps.txt [output] -; choose output: possible values: uhd, file +; choose output: possible values: uhd, file, zmq output=uhd [fileoutput] @@ -193,6 +193,17 @@ pps_source=none ; possible values: ignore, crash behaviour_refclk_lock_lost=ignore +; section defining ZeroMQ output properties +[zmqoutput] + +; on which port to listen for connections +; please see the Transports section in man zmq +; for more informat io the syntax +listen=tcp://*:54001 + +; what ZMQ socket type to use. Valid values: PUB, REP +; Please see man zmq_socket for documentation +socket_type=pub ; Used for SFN with the UHD output [delaymanagement] diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 75e76e0..304d252 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -47,6 +47,7 @@ #include "RemoteControl.h" #include +#include #include #include #include @@ -119,6 +120,7 @@ int main(int argc, char* argv[]) std::string outputName; int useZeroMQOutput = 0; + std::string zmqOutputSocketType = ""; int useFileOutput = 0; std::string fileOutputFormat = "complexf"; int useUHDOutput = 0; @@ -563,6 +565,7 @@ int main(int argc, char* argv[]) #if defined(HAVE_ZEROMQ) else if (output_selected == "zmq") { outputName = pt.get("zmqoutput.listen"); + zmqOutputSocketType = pt.get("zmqoutput.socket_type"); useZeroMQOutput = 1; } #endif @@ -676,8 +679,10 @@ int main(int argc, char* argv[]) #endif else if (useZeroMQOutput) { fprintf(stderr, " ZeroMQ\n" - " Listening on: %s\n", - outputName.c_str()); + " Listening on: %s\n" + " Socket type : %s\n", + outputName.c_str(), + zmqOutputSocketType.c_str()); } fprintf(stderr, " Sampling rate: "); @@ -744,7 +749,17 @@ int main(int argc, char* argv[]) else if (useZeroMQOutput) { /* We normalise the same way as for the UHD output */ normalise = 1.0f / normalise_factor; - output = shared_ptr(new OutputZeroMQ(outputName)); + if (zmqOutputSocketType == "pub") { + output = make_shared(outputName, ZMQ_PUB); + } + else if (zmqOutputSocketType == "rep") { + output = make_shared(outputName, ZMQ_REP); + } + else { + std::stringstream ss; + ss << "ZeroMQ output socket type " << zmqOutputSocketType << " invalid"; + throw std::invalid_argument(ss.str()); + } } #endif diff --git a/src/OutputZeroMQ.cpp b/src/OutputZeroMQ.cpp index 793e473..da4473e 100644 --- a/src/OutputZeroMQ.cpp +++ b/src/OutputZeroMQ.cpp @@ -32,19 +32,31 @@ #if defined(HAVE_ZEROMQ) -OutputZeroMQ::OutputZeroMQ(std::string endpoint, Buffer* dataOut) +OutputZeroMQ::OutputZeroMQ(std::string endpoint, int type, Buffer* dataOut) : ModOutput(ModFormat(1), ModFormat(0)), + m_type(type), m_zmq_context(1), - m_zmq_pub_sock(m_zmq_context, ZMQ_PUB), + m_zmq_sock(m_zmq_context, type), m_endpoint(endpoint) { PDEBUG("OutputZeroMQ::OutputZeroMQ(%p) @ %p\n", dataOut, this); std::stringstream ss; - ss << "OutputZeroMQ(" << m_endpoint << ")"; + ss << "OutputZeroMQ(" << m_endpoint << " "; + + if (type == ZMQ_PUB) { + ss << "ZMQ_PUB"; + } + else if (type == ZMQ_REP) { + ss << "ZMQ_REP"; + } + else { + throw std::invalid_argument("ZMQ socket type unknown"); + } + ss << ")"; m_name = ss.str(); - m_zmq_pub_sock.bind(m_endpoint.c_str()); + m_zmq_sock.bind(m_endpoint.c_str()); } OutputZeroMQ::~OutputZeroMQ() @@ -58,7 +70,13 @@ int OutputZeroMQ::process(Buffer* dataIn, Buffer* dataOut) "(dataIn: %p, dataOut: %p)\n", dataIn, dataOut); - m_zmq_pub_sock.send(dataIn->getData(), dataIn->getLength()); + if (m_type == ZMQ_REP) { + // A ZMQ_REP socket requires a request first + zmq::message_t msg; + m_zmq_sock.recv(&msg); + } + + m_zmq_sock.send(dataIn->getData(), dataIn->getLength()); return dataIn->getLength(); } diff --git a/src/OutputZeroMQ.h b/src/OutputZeroMQ.h index a80eab4..85f85a7 100644 --- a/src/OutputZeroMQ.h +++ b/src/OutputZeroMQ.h @@ -39,14 +39,15 @@ class OutputZeroMQ : public ModOutput { public: - OutputZeroMQ(std::string endpoint, Buffer* dataOut = NULL); + OutputZeroMQ(std::string endpoint, int type, Buffer* dataOut = NULL); virtual ~OutputZeroMQ(); virtual int process(Buffer* dataIn, Buffer* dataOut); const char* name() { return m_name.c_str(); } protected: + int m_type; // zmq socket type zmq::context_t m_zmq_context; // handle for the zmq context - zmq::socket_t m_zmq_pub_sock; // handle for the zmq publisher socket + zmq::socket_t m_zmq_sock; // handle for the zmq publisher socket std::string m_endpoint; // On which port to listen: e.g. // tcp://*:58300 -- cgit v1.2.3 From b042d58100282b480834b283fb40f3b5390327e8 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 10 Apr 2015 12:54:40 +0200 Subject: Use make_shared in DabMod.cpp --- src/DabMod.cpp | 11 +++++------ src/OutputUHD.cpp | 28 ++++++++++++++-------------- src/OutputUHD.h | 6 +++--- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 304d252..b713d30 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -726,22 +726,22 @@ int main(int argc, char* argv[]) if (useFileOutput) { if (fileOutputFormat == "complexf") { - output = shared_ptr(new OutputFile(outputName)); + output = make_shared(outputName); } else if (fileOutputFormat == "s8") { // We must normalise the samples to the interval [-127.0; 127.0] normalise = 127.0f / normalise_factor; - format_converter = shared_ptr(new FormatConverter()); + format_converter = make_shared(); - output = shared_ptr(new OutputFile(outputName)); + output = make_shared(outputName); } } #if defined(HAVE_OUTPUT_UHD) else if (useUHDOutput) { normalise = 1.0f / normalise_factor; outputuhd_conf.sampleRate = outputRate; - output = shared_ptr(new OutputUHD(outputuhd_conf, logger)); + output = make_shared(outputuhd_conf, &logger); ((OutputUHD*)output.get())->enrol_at(rcs); } #endif @@ -808,8 +808,7 @@ int main(int argc, char* argv[]) run_again = true; // Create a new input reader - inputZeroMQReader = shared_ptr( - new InputZeroMQReader(logger)); + inputZeroMQReader = make_shared(logger); inputZeroMQReader->Open(inputName, inputMaxFramesQueued); m.inputReader = inputZeroMQReader.get(); } diff --git a/src/OutputUHD.cpp b/src/OutputUHD.cpp index e8950a2..dbf8b9d 100644 --- a/src/OutputUHD.cpp +++ b/src/OutputUHD.cpp @@ -47,8 +47,8 @@ using namespace std; typedef std::complex complexf; OutputUHD::OutputUHD( - OutputUHDConfig& config, - Logger& logger) : + const OutputUHDConfig& config, + Logger *logger) : ModOutput(ModFormat(1), ModFormat(0)), RemoteControllable("uhd"), myLogger(logger), @@ -152,18 +152,18 @@ OutputUHD::OutputUHD( myConf.muteNoTimestamps ? "enabled" : "disabled"); if (myConf.enableSync && (myConf.pps_src == "none")) { - myLogger.level(warn) << + myLogger->level(warn) << "OutputUHD: WARNING:" " you are using synchronous transmission without PPS input!"; struct timespec now; if (clock_gettime(CLOCK_REALTIME, &now)) { perror("OutputUHD:Error: could not get time: "); - myLogger.level(error) << "OutputUHD: could not get time"; + myLogger->level(error) << "OutputUHD: could not get time"; } else { myUsrp->set_time_now(uhd::time_spec_t(now.tv_sec)); - myLogger.level(info) << "OutputUHD: Setting USRP time to " << + myLogger->level(info) << "OutputUHD: Setting USRP time to " << uhd::time_spec_t(now.tv_sec).get_real_secs(); } } @@ -174,7 +174,7 @@ OutputUHD::OutputUHD( struct timespec now; time_t seconds; if (clock_gettime(CLOCK_REALTIME, &now)) { - myLogger.level(error) << "OutputUHD: could not get time :" << + myLogger->level(error) << "OutputUHD: could not get time :" << strerror(errno); throw std::runtime_error("OutputUHD: could not get time."); } @@ -185,7 +185,7 @@ OutputUHD::OutputUHD( while (seconds + 1 > now.tv_sec) { usleep(1); if (clock_gettime(CLOCK_REALTIME, &now)) { - myLogger.level(error) << "OutputUHD: could not get time :" << + myLogger->level(error) << "OutputUHD: could not get time :" << strerror(errno); throw std::runtime_error("OutputUHD: could not get time."); } @@ -195,12 +195,12 @@ OutputUHD::OutputUHD( usleep(200000); // 200ms, we want the PPS to be later myUsrp->set_time_unknown_pps(uhd::time_spec_t(seconds + 2)); - myLogger.level(info) << "OutputUHD: Setting USRP time next pps to " << + myLogger->level(info) << "OutputUHD: Setting USRP time next pps to " << uhd::time_spec_t(seconds + 2).get_real_secs(); } usleep(1e6); - myLogger.log(info, "OutputUHD: USRP time %f\n", + myLogger->log(info, "OutputUHD: USRP time %f\n", myUsrp->get_time_now().get_real_secs()); } @@ -214,7 +214,7 @@ OutputUHD::OutputUHD( uwd.sampleRate = myConf.sampleRate; uwd.sourceContainsTimestamp = false; uwd.muteNoTimestamps = myConf.muteNoTimestamps; - uwd.logger = &myLogger; + uwd.logger = myLogger; uwd.refclk_lock_loss_behaviour = myConf.refclk_lock_loss_behaviour; if (myConf.refclk_src == "internal") { @@ -284,7 +284,7 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) // We will only wait on the barrier on the subsequent calls to // OutputUHD::process if (first_run) { - myLogger.level(debug) << "OutputUHD: UHD initialising..."; + myLogger->level(debug) << "OutputUHD: UHD initialising..."; worker.start(&uwd); @@ -319,13 +319,13 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) lastLen = uwd.bufsize; first_run = false; - myLogger.level(debug) << "OutputUHD: UHD initialising complete"; + myLogger->level(debug) << "OutputUHD: UHD initialising complete"; } else { if (lastLen != dataIn->getLength()) { // I expect that this never happens. - myLogger.level(emerg) << + myLogger->level(emerg) << "OutputUHD: Fatal error, input length changed from " << lastLen << " to " << dataIn->getLength(); throw std::runtime_error("Non-constant input length!"); @@ -339,7 +339,7 @@ int OutputUHD::process(Buffer* dataIn, Buffer* dataOut) throw fct_discontinuity_error(); } else { - myLogger.level(error) << + myLogger->level(error) << "OutputUHD: Error, UHD worker failed"; throw std::runtime_error("UHD worker failed"); } diff --git a/src/OutputUHD.h b/src/OutputUHD.h index d92c7a4..aed80f6 100644 --- a/src/OutputUHD.h +++ b/src/OutputUHD.h @@ -200,8 +200,8 @@ class OutputUHD: public ModOutput, public RemoteControllable { public: OutputUHD( - OutputUHDConfig& config, - Logger& logger); + const OutputUHDConfig& config, + Logger *logger); ~OutputUHD(); int process(Buffer* dataIn, Buffer* dataOut); @@ -227,7 +227,7 @@ class OutputUHD: public ModOutput, public RemoteControllable { protected: - Logger& myLogger; + Logger *myLogger; EtiReader *myEtiReader; OutputUHDConfig myConf; uhd::usrp::multi_usrp::sptr myUsrp; -- cgit v1.2.3 From 34e0324637fe188085130701a2235108cf391d23 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 10 Apr 2015 15:24:46 +0200 Subject: Only print closing message if really closing file --- src/InputReader.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/InputReader.h b/src/InputReader.h index dcf88cc..13d49b8 100644 --- a/src/InputReader.h +++ b/src/InputReader.h @@ -91,9 +91,9 @@ class InputFileReader : public InputReader ~InputFileReader() { - fprintf(stderr, "\nClosing input file...\n"); - if (inputfile_ != NULL) { + fprintf(stderr, "\nClosing input file...\n"); + fclose(inputfile_); } } -- cgit v1.2.3 From f7866047042030e657eb2fa0cd6cf2ad383d61bd Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 10 Apr 2015 15:28:55 +0200 Subject: Fix license text in usage screen --- src/Utils.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 5c80eee..8698f6e 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -93,20 +93,22 @@ void printVersion(void) " ODR-DabMod is copyright (C) Her Majesty the Queen in Right of Canada,\n" " 2009, 2010, 2011, 2012 Communications Research Centre (CRC),\n" " and\n" - " Copyright (C) 2014 Matthias P. Braendli, matthias.braendli@mpb.li\n" + " Copyright (C) 2014, 2015 Matthias P. Braendli, matthias.braendli@mpb.li\n" "\n" " http://opendigitalradio.org\n" "\n" - " This program is available free of charge and is licensed to you on a\n" - " non-exclusive basis; you may not redistribute it.\n" + " ODR-DabMod is free software: you can redistribute it and/or modify it\n" + " under the terms of the GNU General Public License as published by the\n" + " Free Software Foundation, either version 3 of the License, or (at your\n" + " option) any later version.\n" "\n" - " This program is provided \"AS IS\" in the hope that it will be useful, but\n" - " WITHOUT ANY WARRANTY with respect to its accurancy or usefulness; witout\n" - " even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n" - " PURPOSE and NONINFRINGEMENT.\n" + " ODR-DabMod is distributed in the hope that it will be useful, but\n" + " WITHOUT ANY WARRANTY; without even the implied warranty of\n" + " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" + " General Public License for more details.\n" "\n" - " In no event shall CRC be LIABLE for any LOSS, DAMAGE or COST that may be\n" - " incurred in connection with the use of this software.\n" + " You should have received a copy of the GNU General Public License along\n" + " with ODR-DabMod. If not, see .\n" "\n" #if USE_KISS_FFT "ODR-DabMod makes use of the following open source packages:\n" -- cgit v1.2.3 From 8270567bc62db8f94a6e142b3b170a3bb943c090 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 10 Apr 2015 15:31:15 +0200 Subject: Avoid having exceptions triggering abort() --- src/DabMod.cpp | 18 +++++++++++++++++- src/Utils.cpp | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/DabMod.cpp b/src/DabMod.cpp index b713d30..ec1a4cd 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -110,7 +110,7 @@ enum run_modulator_state { run_modulator_state run_modulator(Logger& logger, modulator_data& m); -int main(int argc, char* argv[]) +int launch_modulator(int argc, char* argv[]) { int ret = 0; bool loop = false; @@ -899,3 +899,19 @@ run_modulator_state run_modulator(Logger& logger, modulator_data& m) return ret; } +int main(int argc, char* argv[]) +{ + try { + return launch_modulator(argc, argv); + } + catch (std::invalid_argument& e) { + std::string what(e.what()); + if (not what.empty()) { + std::cerr << "Modulator error: " << what << std::endl; + } + } + catch (std::runtime_error& e) { + std::cerr << "Modulator runtime error: " << e.what() << std::endl; + } +} + diff --git a/src/Utils.cpp b/src/Utils.cpp index 8698f6e..8b97602 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -79,7 +79,7 @@ void printUsage(char* progName) fprintf(out, "-h: Print this help.\n"); fprintf(out, "-l: Loop file when reach end of file.\n"); fprintf(out, "-m mode: Set DAB mode: (0: auto, 1-4: force).\n"); - fprintf(out, "-r rate: Set output sampling rate (default: 2048000).\n"); + fprintf(out, "-r rate: Set output sampling rate (default: 2048000).\n\n"); } -- cgit v1.2.3 From e2d14763b766b2154940a47acb3dffb65d0973d3 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 10 Apr 2015 16:39:14 +0200 Subject: Add validity check for eti_fc --- src/EtiReader.cpp | 8 ++++++++ src/EtiReader.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/EtiReader.cpp b/src/EtiReader.cpp index 7e0df72..0e4182d 100644 --- a/src/EtiReader.cpp +++ b/src/EtiReader.cpp @@ -61,6 +61,7 @@ EtiReader::EtiReader(struct modulator_offset_config& modconf, PDEBUG("EtiReader::EtiReader()\n"); myCurrentFrame = 0; + eti_fc_valid = false; } EtiReader::~EtiReader() @@ -81,12 +82,18 @@ FicSource* EtiReader::getFic() unsigned EtiReader::getMode() { + if (not eti_fc_valid) { + throw std::runtime_error("Trying to access Mode before it is ready!"); + } return eti_fc.MID; } unsigned EtiReader::getFp() { + if (not eti_fc_valid) { + throw std::runtime_error("Trying to access FP before it is ready!"); + } return eti_fc.FP; } @@ -144,6 +151,7 @@ int EtiReader::process(const Buffer* dataIn) return dataIn->getLength() - input_size; } memcpy(&eti_fc, in, 4); + eti_fc_valid = true; input_size -= 4; framesize -= 4; in += 4; diff --git a/src/EtiReader.h b/src/EtiReader.h index 136bd1c..b893f01 100644 --- a/src/EtiReader.h +++ b/src/EtiReader.h @@ -91,6 +91,7 @@ private: size_t myCurrentFrame; bool time_ext_enabled; unsigned long timestamp_seconds; + bool eti_fc_valid; }; -- cgit v1.2.3 From 81775f47227c5d08a05b43ffb3855bff0a237c1d Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 10 Apr 2015 17:14:08 +0200 Subject: Prepare release v0.5.2 --- AUTHORS | 7 +++++++ ChangeLog | 12 ++++++++++++ README.md | 22 ++++++++++++++-------- configure.ac | 2 +- 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/AUTHORS b/AUTHORS index dfefa5a..6da1706 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,3 +10,10 @@ Matthias P. Braendli - Improvements in logging (log to file, to syslog) - ZeroMQ ETI input - Telnet remote-control + - ZeroMQ I/Q output + - I/Q conversion to signed 8-bit + - ARM support + +Jörgen Scott + - ZeroMQ remote control + - Static delay offset diff --git a/ChangeLog b/ChangeLog index d13be34..c119b10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,18 @@ This file contains information about the changes done to the ODR-DabMod in this repository +2015-04-10: Matthias P. Braendli + (v0.5.2) + * odr-dabmod: + Merge static delay parameter and ZeroMQ remote control. + Add max_frames_queued option for ZeroMQ input. + Restart modulator on FCT discontinuity or ZeroMQ input + buffer overrun. + Improve error messages and documentation. + Add ZeroMQ output REP socket type for interconnection with + GNURadio. + Fix license text in usage view. + 2015-01-24: Matthias P. Braendli (v0.5.1) * odr-dabmod: diff --git a/README.md b/README.md index 292bba5..cab4637 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,30 @@ OVERVIEW ======== -ODR-DabMod is a fork of CRC-DabMod, which was developed by the Communications -Research Center Canada. It has been forked by the Opendigitalradio project. - ODR-DabMod is a DAB (Digital Audio Broadcasting) modulator compliant to ETSI EN 300 401. -In addition to the features of CRC-DabMod, this fork contains: +ODR-DabMod is a fork of CRC-DabMod, which was developed by the +Communications Research Center Canada and whose development has ceased. +The Opendigitalradio association now continues this project. + +Short list of features: +- Reads ETI, outputs compliant COFDM I/Q +- Supports native DAB sample rate and can also + resample to other rates +- supports all four DAB transmission modes - Configuration file support, see doc/example.ini - Integrated UHD output for USRP devices - Tested for B200, B100, USRP2, USRP1 - With WBX daughterboard (where appropriate) - Timestamping support required for SFN -- A FIR filter (previously done in GNURadio by crc-dwap.py) +- A FIR filter for improved spectrum mask - Improvements in logging (log to file, to syslog) - ETI sources: file (Raw, Framed and Streamed) and ZeroMQ - A Telnet and ZeroMQ remote-control that can be used to change some parameters during runtime -- 8-bit signed I/Q output format +- 8-bit signed I/Q output format, useful for the HackRF +- ZeroMQ PUB and REP output. The src/ directory contains the source code of ODR-DabMod. @@ -41,6 +47,6 @@ CONTACT Matthias P. Braendli Pascal Charest +With thanks to other contributors listed in AUTHORS + http://opendigitalradio.org/ -http://mmbtools.crc.ca/ -http://mpb.li/ diff --git a/configure.ac b/configure.ac index 9a88fd9..821ba1f 100644 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,7 @@ # along with ODR-DabMod. If not, see . AC_PREREQ(2.59) -AC_INIT([ODR-DabMod], [0.5.1], [matthias.braendli@mpb.li]) +AC_INIT([ODR-DabMod], [0.5.2], [matthias.braendli@mpb.li]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_SYSTEM -- cgit v1.2.3