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(-) (limited to 'doc') 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~ (limited to 'doc') 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 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(-) (limited to 'doc') 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 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(-) (limited to 'doc') 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~ (limited to 'doc') 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(-) (limited to 'doc') 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 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(-) (limited to 'doc') 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 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 (limited to 'doc') 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(-) (limited to 'doc') 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(-) (limited to 'doc') 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 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(-) (limited to 'doc') 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 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(-) (limited to 'doc') 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