diff options
44 files changed, 477 insertions, 187 deletions
diff --git a/docs/doxygen/other/logger.dox b/docs/doxygen/other/logger.dox index ae6a744d00..c8e4a5daa2 100644 --- a/docs/doxygen/other/logger.dox +++ b/docs/doxygen/other/logger.dox @@ -212,6 +212,24 @@ This creates a pointer called LOG (which is instantiated as a log4cpp:LoggerPtr in the macro) that we can now use locally as the input to our logging macros like 'GR_LOG_INFO(LOG, "message")'. +\subsection using_logging Using Logging in Out of Tree Modules + +In order to use the logging interface in an out of tree module based on a +gr_modtool template module, several CMake modifications are required. +Without these changes, logging will be disabled. + +GrMiscUtils.cmake module must be included in the OOT module top level +CMakeLists.Texts file, and the GR_LOGGING() function provided by GrMiscUtils +must be called from the same top level CMakeLists.txt file. This will +set the appropriate build environment and during that process, attempt +to find the log4cpp package using the FindLog4Cpp.cmake module. +This module is not included in the module by gr_modtool, but is part of +the GNU Radio codebase and can be copied directly into the cmake/Modules/ +directory of the OOT module. + +Once these CMake changes are made, the GR logging interface will function +as documented on this page. + \section logPy Logging from Python The logging capability has been brought out python via swig. The configuration diff --git a/gnuradio-runtime/include/gnuradio/py_feval.h b/gnuradio-runtime/include/gnuradio/py_feval.h index cef168c8f0..89491af0b4 100644 --- a/gnuradio-runtime/include/gnuradio/py_feval.h +++ b/gnuradio-runtime/include/gnuradio/py_feval.h @@ -23,6 +23,7 @@ #ifndef INCLUDED_GR_PY_FEVAL_H #define INCLUDED_GR_PY_FEVAL_H +#include <Python.h> #include <pmt/pmt.h> #include <gnuradio/feval.h> diff --git a/gnuradio-runtime/include/gnuradio/sys_pri.h b/gnuradio-runtime/include/gnuradio/sys_pri.h index adceb91b9d..d251455a11 100644 --- a/gnuradio-runtime/include/gnuradio/sys_pri.h +++ b/gnuradio-runtime/include/gnuradio/sys_pri.h @@ -23,7 +23,7 @@ #define INCLUDED_GNURADIO_SYS_PRI_H #include <gnuradio/api.h> -#include <realtime.h> +#include <gnuradio/realtime.h> /* * A single place to define real-time priorities used by the system itself @@ -31,10 +31,10 @@ namespace gr { struct GR_RUNTIME_API sys_pri { - static rt_sched_param python(); // python code - static rt_sched_param normal(); // normal blocks - static rt_sched_param gcell_event_handler(); - static rt_sched_param usrp2_backend(); // thread that services the ethernet + static struct GR_RUNTIME_API rt_sched_param python(); // python code + static struct GR_RUNTIME_API rt_sched_param normal(); // normal blocks + static struct GR_RUNTIME_API rt_sched_param gcell_event_handler(); + static struct GR_RUNTIME_API rt_sched_param usrp2_backend(); // thread that services the ethernet }; } /* namespace gr */ diff --git a/gnuradio-runtime/include/gnuradio/xoroshiro128p.h b/gnuradio-runtime/include/gnuradio/xoroshiro128p.h new file mode 100644 index 0000000000..b3e6dcb12d --- /dev/null +++ b/gnuradio-runtime/include/gnuradio/xoroshiro128p.h @@ -0,0 +1,103 @@ +/* + * Copyright 2018 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +// Built on XOROSHIRO128+ by David Blackman and Sebastiano Vigna who put this +// under CC-0, colloquially known as "public domain (or as close you get to that +// in your local legislation)" see +// http://xoroshiro.di.unimi.it/xoroshiro128plus.c +// Conversion to a local state (original used global state) done by Marcus +// Müller, 2018. +#ifndef INCLUDED_XOROSHIRO128P_H +#define INCLUDED_XOROSHIRO128P_H +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +/*! \brief rotating left shift helper + * According to the original authors, this will on most platforms reduce to a single instruction + */ +static inline uint64_t rotl(const uint64_t x, const int k) { + return (x << k) | (x >> (64 - k)); +} + + +/*! \brief generate the next random number and update the state. + * This is the workhorse, here! + */ +static inline uint64_t xoroshiro128p_next(uint64_t *state) { + const uint64_t s0 = state[0]; + uint64_t s1 = state[1]; + const uint64_t result = s0 + s1; + + s1 ^= s0; + state[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b + state[1] = rotl(s1, 36); // c + + return result; +} + + +/*! \brief Advance the internal state by 2^64 steps; useful when coordinating multiple independent RNGs + This is the jump function for the generator. It is equivalent + to 2^64 calls to next(); it can be used to generate 2^64 + non-overlapping subsequences for parallel computations. */ +static inline void xoroshiro128p_jump(uint64_t *state) { + static const uint64_t JUMP[] = { 0xbeac0467eba5facb, 0xd86b048b86aa9922 }; + + uint64_t s0 = 0; + uint64_t s1 = 0; + for(unsigned int i = 0; i < sizeof (JUMP) / sizeof (*JUMP); ++i) { + for(unsigned int b = 0; b < 64; ++b) { + if (JUMP[i] & UINT64_C(1) << b) { + s0 ^= state[0]; + s1 ^= state[1]; + } + xoroshiro128p_next(state); + } + } + + state[0] = s0; + state[1] = s1; +} + +/*! \brief step of the SPLITMIX64 RNG; only used internally for seeding + * This RNG isn't as good as XOROSHIRO128+, so it's only used to initialize a 128 bit state from a seed. + */ +static inline uint64_t splitmix64_next(uint64_t *state) { + uint64_t z = (*state += 0x9e3779b97f4a7c15); + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + return z ^ (z >> 31); +} + +/*! \brief Seed the 128 bit state from a 64 bit seed + */ +static inline void xoroshiro128p_seed(uint64_t *state, const uint64_t seed) { + state[0] = seed; + state[1] = splitmix64_next(state); + xoroshiro128p_jump(state); +} +#ifdef __cplusplus +} +#endif +#endif // Include guard diff --git a/gnuradio-runtime/lib/math/random.cc b/gnuradio-runtime/lib/math/random.cc index 401ba89735..cedaf4b97f 100644 --- a/gnuradio-runtime/lib/math/random.cc +++ b/gnuradio-runtime/lib/math/random.cc @@ -73,9 +73,12 @@ namespace gr { void random::reseed(unsigned int seed) { - if(seed==0) d_seed = static_cast<unsigned int>(std::time(0)); - else d_seed = seed; - d_rng->seed(d_seed); + d_seed = seed; + if (d_seed == 0){ + d_rng->seed(); + } else { + d_rng->seed(d_seed); + } // reinstantiate generators. Otherwise reseed doesn't take effect. delete d_generator; d_generator = new boost::variate_generator<boost::mt19937&, boost::uniform_real<float> > (*d_rng,*d_uniform); // create number generator in [0,1) from boost.random @@ -138,11 +141,12 @@ namespace gr { float random::laplacian() { - float z = ran1()-0.5; - if(z>0) return -logf(1-2*z); - else return logf(1+2*z); + float z = ran1(); + if (z > 0.5f){ + return -logf(2.0f * (1.0f - z) ); + } + return logf(2 * z); } - /* * Copied from The KC7WW / OH2BNS Channel Simulator * FIXME Need to check how good this is at some point diff --git a/gnuradio-runtime/lib/pmt/pmt.cc b/gnuradio-runtime/lib/pmt/pmt.cc index 3b92481549..0fe4dbde8e 100644 --- a/gnuradio-runtime/lib/pmt/pmt.cc +++ b/gnuradio-runtime/lib/pmt/pmt.cc @@ -1158,12 +1158,12 @@ equal(const pmt_t& x, const pmt_t& y) return false; size_t len_x, len_y; - if (memcmp(xv->uniform_elements(len_x), - yv->uniform_elements(len_y), - len_x) == 0) + const void *x_m = xv->uniform_elements(len_x); + const void *y_m = yv->uniform_elements(len_y); + if (memcmp(x_m, y_m, len_x) == 0) return true; - return true; + return false; } // FIXME add other cases here... diff --git a/gnuradio-runtime/python/gnuradio/eng_notation.py b/gnuradio-runtime/python/gnuradio/eng_notation.py index d23f9005f0..12332aef7d 100644 --- a/gnuradio-runtime/python/gnuradio/eng_notation.py +++ b/gnuradio-runtime/python/gnuradio/eng_notation.py @@ -36,29 +36,30 @@ scale_factor['p'] = 1e-12 scale_factor['f'] = 1e-15 scale_factor['a'] = 1e-18 -def num_to_str (n): +def num_to_str (n, precision=6): '''Convert a number to a string in engineering notation. E.g., 5e-9 -> 5n''' m = abs(n) + format_spec = '%.' + repr(int(precision)) + 'g' if m >= 1e9: - return "%gG" % (n * 1e-9) + return '%sG' % float(format_spec % (n * 1e-9)) elif m >= 1e6: - return "%gM" % (n * 1e-6) + return '%sM' % float(format_spec % (n * 1e-6)) elif m >= 1e3: - return "%gk" % (n * 1e-3) + return '%sk' % float(format_spec % (n * 1e-3)) elif m >= 1: - return "%g" % (n) + return '%s' % float(format_spec % (n)) elif m >= 1e-3: - return "%gm" % (n * 1e3) + return '%sm' % float(format_spec % (n * 1e3)) elif m >= 1e-6: - return "%gu" % (n * 1e6) # where's that mu when you need it (unicode?) + return '%su' % float(format_spec % (n * 1e6)) elif m >= 1e-9: - return "%gn" % (n * 1e9) + return '%sn' % float(format_spec % (n * 1e9)) elif m >= 1e-12: - return "%gp" % (n * 1e12) + return '%sp' % float(format_spec % (n * 1e12)) elif m >= 1e-15: - return "%gf" % (n * 1e15) + return '%sf' % float(format_spec % (n * 1e15)) else: - return "%g" % (n) + return '%s' % float(format_spec % (n)) def str_to_num (value): diff --git a/gr-analog/include/gnuradio/analog/fastnoise_source_X.h.t b/gr-analog/include/gnuradio/analog/fastnoise_source_X.h.t index 850633979c..f588299604 100644 --- a/gr-analog/include/gnuradio/analog/fastnoise_source_X.h.t +++ b/gr-analog/include/gnuradio/analog/fastnoise_source_X.h.t @@ -29,6 +29,8 @@ #include <gnuradio/analog/noise_type.h> #include <gnuradio/sync_block.h> +#include <vector> + namespace gr { namespace analog { @@ -62,6 +64,7 @@ namespace gr { long seed = 0, long samples=1024*16); virtual @TYPE@ sample() = 0; virtual @TYPE@ sample_unbiased() = 0; + virtual const std::vector<@TYPE@>& samples() const = 0; /*! * Set the noise type. Nominally from the diff --git a/gr-analog/lib/fastnoise_source_X_impl.cc.t b/gr-analog/lib/fastnoise_source_X_impl.cc.t index 940918b11b..72c6cb0582 100644 --- a/gr-analog/lib/fastnoise_source_X_impl.cc.t +++ b/gr-analog/lib/fastnoise_source_X_impl.cc.t @@ -27,6 +27,7 @@ #endif #include "@IMPL_NAME@.h" +#include <gnuradio/xoroshiro128p.h> #include <gnuradio/io_signature.h> #include <stdexcept> @@ -46,13 +47,13 @@ namespace gr { io_signature::make(1, 1, sizeof(@TYPE@))), d_type(type), #if @IS_COMPLEX@ // complex? - d_ampl(ampl/sqrtf(2.0f)), + d_ampl(ampl/sqrtf(2.0f)) #else - d_ampl(ampl), + d_ampl(ampl) #endif - d_rng(seed) { d_samples.resize(samples); + xoroshiro128p_seed(d_state, (uint64_t) seed); generate(); } @@ -144,32 +145,27 @@ namespace gr { @TYPE@ @IMPL_NAME@::sample() { -#ifdef HAVE_RAND48 - size_t idx = lrand48() % d_samples.size(); -#else - size_t idx = rand() % d_samples.size(); -#endif + size_t idx = xoroshiro128p_next(d_state) % d_samples.size(); return d_samples[idx]; } -#ifndef FASTNOISE_RANDOM_SIGN -#ifndef HAVE_RAND48 -#define FASTNOISE_RANDOM_SIGN ((rand()%2==0)?1:-1) -#else -#define FASTNOISE_RANDOM_SIGN ((lrand48()%2==0)?1:-1) -#endif -#endif - @TYPE@ @IMPL_NAME@::sample_unbiased() { + uint64_t random_int = xoroshiro128p_next(d_state); #if @IS_COMPLEX@ gr_complex s(sample()); - return gr_complex(FASTNOISE_RANDOM_SIGN * s.real(), - FASTNOISE_RANDOM_SIGN * s.imag()); + float re = (random_int & (UINT64_C(1)<<23)) ? (- s.real()) : (s.real()); + float im = (random_int & (UINT64_C(1)<<42)) ? (- s.real()) : (s.real()); + return gr_complex(re, im); #else - return FASTNOISE_RANDOM_SIGN * sample(); + float s = sample(); + return (random_int & (1<<23)) ? (-s) : s; #endif } + const std::vector<@TYPE@>& @IMPL_NAME@::samples() const + { + return d_samples; + } } /* namespace analog */ } /* namespace gr */ diff --git a/gr-analog/lib/fastnoise_source_X_impl.h.t b/gr-analog/lib/fastnoise_source_X_impl.h.t index 8ad1e4f8fe..ef0465729d 100644 --- a/gr-analog/lib/fastnoise_source_X_impl.h.t +++ b/gr-analog/lib/fastnoise_source_X_impl.h.t @@ -38,6 +38,7 @@ namespace gr { float d_ampl; gr::random d_rng; std::vector<@TYPE@> d_samples; + uint64_t d_state[2]; public: @IMPL_NAME@(noise_type_t type, float ampl, long seed, long samples); @@ -49,6 +50,7 @@ namespace gr { void set_type(noise_type_t type); void set_amplitude(float ampl); void generate(); + const std::vector<@TYPE@>& samples() const; noise_type_t type() const { return d_type; } float amplitude() const { return d_ampl; } diff --git a/gr-analog/python/analog/qa_fastnoise.py b/gr-analog/python/analog/qa_fastnoise.py index 91e1cb87b7..f712d66ca7 100644 --- a/gr-analog/python/analog/qa_fastnoise.py +++ b/gr-analog/python/analog/qa_fastnoise.py @@ -20,32 +20,120 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr, gr_unittest, analog +from gnuradio import gr, gr_unittest, analog, blocks +import numpy + class test_fastnoise_source(gr_unittest.TestCase): def setUp (self): - self.tb = gr.top_block () + + self.num = 2**22 + self.num_items = 10**6 + self.default_args = {"samples": self.num, "seed": 43, "ampl": 1} def tearDown (self): - self.tb = None + pass + + def run_test_real(self, form): + """ Run test case with float input/output + """ + tb = gr.top_block() + src = analog.fastnoise_source_f(type=form, **self.default_args) + head = blocks.head(nitems=self.num_items, sizeof_stream_item=gr.sizeof_float) + sink = blocks.vector_sink_f() + tb.connect(src, head, sink) + tb.run() + return numpy.array(sink.data()) + + def run_test_complex(self, form): + """ Run test case with complex input/output + """ + tb = gr.top_block() + src = analog.fastnoise_source_c(type=form, **self.default_args) + head = blocks.head(nitems=self.num_items, sizeof_stream_item=gr.sizeof_gr_complex) + sink = blocks.vector_sink_c() + tb.connect(src, head, sink) + tb.run() + return numpy.array(sink.data()) + + def test_001_real_uniform_moments(self): + + data = self.run_test_real(analog.GR_UNIFORM) + + self.assertAlmostEqual(min(data), -1, places=4) + self.assertAlmostEqual(max(data), 1, places=4) + + # mean, variance + self.assertAlmostEqual(data.mean(), 0, places=2) + self.assertAlmostEqual(data.var(), (1-(-1))**2./12, places=3) + + def test_001_real_gaussian_moments(self): + data = self.run_test_real(analog.GR_GAUSSIAN) + + # mean, variance + self.assertAlmostEqual(data.mean(), 0, places=2) + self.assertAlmostEqual(data.var(), 1, places=2) - def test_001(self): - # Just confirm that we can instantiate a noise source - op = analog.fastnoise_source_f(analog.GR_GAUSSIAN, 10, 10) + def test_001_real_laplacian_moments(self): + data = self.run_test_real(analog.GR_LAPLACIAN) - def test_002(self): - # Test get methods - set_type = analog.GR_GAUSSIAN - set_ampl = 10 - op = analog.fastnoise_source_f(set_type, set_ampl, 10) - get_type = op.type() - get_ampl = op.amplitude() + # mean, variance + self.assertAlmostEqual(data.mean(), 0, places=2) + self.assertAlmostEqual(data.var(), 2, places=2) - self.assertEqual(get_type, set_type) - self.assertEqual(get_ampl, set_ampl) + def test_001_complex_uniform_moments(self): + data = self.run_test_complex(analog.GR_UNIFORM) + # mean, variance + self.assertAlmostEqual(data.real.mean(), 0, places=2) + self.assertAlmostEqual(data.real.var(), 0.5*(1-(-1))**2./12, places=3) + self.assertAlmostEqual(data.imag.mean(), 0, places=2) + self.assertAlmostEqual(data.imag.var(), 0.5*(1-(-1))**2./12, places=3) + + def test_001_complex_gaussian_moments(self): + data = self.run_test_complex(analog.GR_GAUSSIAN) + + # mean, variance + self.assertAlmostEqual(data.real.mean(), 0, places=2) + self.assertAlmostEqual(data.real.var(), 0.5, places=2) + + self.assertAlmostEqual(data.imag.mean(), 0, places=2) + self.assertAlmostEqual(data.imag.var(), 0.5, places=2) + + def test_002_real_uniform_reproducibility(self): + data1 = self.run_test_real(analog.GR_UNIFORM) + data2 = self.run_test_real(analog.GR_UNIFORM) + + # It's pseudoramdo thus must be equal + self.assertTrue(numpy.array_equal(data1, data2)) + + def test_002_real_gaussian_reproducibility(self): + data1 = self.run_test_real(analog.GR_GAUSSIAN) + data2 = self.run_test_real(analog.GR_GAUSSIAN) + + self.assertTrue(numpy.array_equal(data1, data2)) + + def test_003_real_uniform_pool(self): + src = analog.fastnoise_source_f(type=analog.GR_UNIFORM, **self.default_args) + src2 = analog.fastnoise_source_f(type=analog.GR_UNIFORM, **self.default_args) + self.assertTrue(numpy.array_equal(numpy.array(src.samples()), numpy.array(src2.samples()))) + def test_003_real_gaussian_pool(self): + src = analog.fastnoise_source_f(type=analog.GR_GAUSSIAN, **self.default_args) + src2 = analog.fastnoise_source_f(type=analog.GR_GAUSSIAN, **self.default_args) + self.assertTrue(numpy.array_equal(numpy.array(src.samples()), numpy.array(src2.samples()))) + def test_003_cmplx_gaussian_pool(self): + src = analog.fastnoise_source_c(type=analog.GR_GAUSSIAN, **self.default_args) + src2 = analog.fastnoise_source_c(type=analog.GR_GAUSSIAN, **self.default_args) + self.assertTrue(numpy.array_equal(numpy.array(src.samples()), numpy.array(src2.samples()))) + def test_003_cmplx_uniform_pool(self): + src = analog.fastnoise_source_c(type=analog.GR_UNIFORM, **self.default_args) + src2 = analog.fastnoise_source_c(type=analog.GR_UNIFORM, **self.default_args) + self.assertTrue(numpy.array_equal(numpy.array(src.samples()), numpy.array(src2.samples()))) + def test_003_real_laplacian_pool(self): + src = analog.fastnoise_source_f(type=analog.GR_LAPLACIAN, **self.default_args) + src2 = analog.fastnoise_source_f(type=analog.GR_LAPLACIAN, **self.default_args) + self.assertTrue(numpy.array_equal(numpy.array(src.samples()), numpy.array(src2.samples()))) if __name__ == '__main__': gr_unittest.run(test_fastnoise_source, "test_fastnoise_source.xml") - diff --git a/gr-blocks/lib/ConfigChecks.cmake b/gr-blocks/lib/ConfigChecks.cmake index 222a221dc1..1effaa8360 100644 --- a/gr-blocks/lib/ConfigChecks.cmake +++ b/gr-blocks/lib/ConfigChecks.cmake @@ -89,10 +89,3 @@ CHECK_CXX_SOURCE_COMPILES(" " HAVE_COSF ) GR_ADD_COND_DEF(HAVE_COSF) - -CHECK_CXX_SOURCE_COMPILES(" - #include <stdlib.h> - int main(){srand48(0); drand48(); lrand48(); return 0;} - " HAVE_RAND48 -) -GR_ADD_COND_DEF(HAVE_RAND48) diff --git a/gr-blocks/lib/test_tag_variable_rate_ff_impl.cc b/gr-blocks/lib/test_tag_variable_rate_ff_impl.cc index ec239c9fa7..cca86ad832 100644 --- a/gr-blocks/lib/test_tag_variable_rate_ff_impl.cc +++ b/gr-blocks/lib/test_tag_variable_rate_ff_impl.cc @@ -26,10 +26,12 @@ #include "test_tag_variable_rate_ff_impl.h" #include <gnuradio/io_signature.h> +#include <gnuradio/xoroshiro128p.h> #include <string.h> #include <iostream> #include <iomanip> #include <stdexcept> +#include <stdint.h> using namespace pmt; @@ -57,11 +59,7 @@ namespace gr { d_new_in = 0; d_last_out = 0; -#ifdef HAVE_RAND48 - srand48(time(NULL)); -#else - srand(time(NULL)); -#endif + xoroshiro128p_seed(d_rng_state, 4 /* chosen by fair dice roll */); } test_tag_variable_rate_ff_impl::~test_tag_variable_rate_ff_impl() @@ -82,11 +80,7 @@ namespace gr { GR_LOG_DEBUG(d_logger, boost::format("noutput_items: %1%") % noutput_items); if(d_update_once) { -#ifdef HAVE_RAND48 - if(drand48() > 0.5) { -#else - if (rand() > RAND_MAX / 2) { -#endif + if (xoroshiro128p_next(d_rng_state) > (UINT64_MAX / 2)){ d_rrate += d_update_step; } else { @@ -103,11 +97,7 @@ namespace gr { while(i < ninput_items[0]) { if(!d_update_once) { -#ifdef HAVE_RAND48 - if(drand48() > 0.5) { -#else - if (rand() > RAND_MAX / 2) { -#endif + if (xoroshiro128p_next(d_rng_state) > (UINT64_MAX / 2)){ d_rrate += d_update_step; } else { diff --git a/gr-blocks/lib/test_tag_variable_rate_ff_impl.h b/gr-blocks/lib/test_tag_variable_rate_ff_impl.h index 0335ab6e66..a02bce1ccf 100644 --- a/gr-blocks/lib/test_tag_variable_rate_ff_impl.h +++ b/gr-blocks/lib/test_tag_variable_rate_ff_impl.h @@ -36,6 +36,7 @@ namespace gr { double d_accum; double d_rrate; uint64_t d_old_in, d_new_in, d_last_out; + uint64_t d_rng_state[2]; public: test_tag_variable_rate_ff_impl(bool update_once=false, diff --git a/gr-channels/lib/selective_fading_model_impl.cc b/gr-channels/lib/selective_fading_model_impl.cc index dfd7b74ca9..3594ec4aa0 100644 --- a/gr-channels/lib/selective_fading_model_impl.cc +++ b/gr-channels/lib/selective_fading_model_impl.cc @@ -95,7 +95,7 @@ namespace gr { gr_complex ff_H(d_faders[j]->next_sample()); for(size_t k=0; k<d_taps.size(); k++){ float dist = k-d_delays[j]; - float interpmag = d_sintable.sinc(2*M_PI*dist); + float interpmag = d_sintable.sinc(M_PI*dist); d_taps[k] += ff_H * interpmag * d_mags[j]; } } diff --git a/gr-digital/lib/chunks_to_symbols_XX_impl.cc.t b/gr-digital/lib/chunks_to_symbols_XX_impl.cc.t index b08bdde08f..5ccc40a3ae 100644 --- a/gr-digital/lib/chunks_to_symbols_XX_impl.cc.t +++ b/gr-digital/lib/chunks_to_symbols_XX_impl.cc.t @@ -62,37 +62,29 @@ namespace gr { void @IMPL_NAME@::set_vector_from_pmt(std::vector<gr_complex> &symbol_table, pmt::pmt_t &symbol_table_pmt) { - symbol_table.resize(0); - for (unsigned int i=0; i<pmt::length(symbol_table_pmt); i++) { - symbol_table.push_back(pmt::c32vector_ref(symbol_table_pmt, i)); - } + size_t length; + const gr_complex *elements = pmt::c32vector_elements(symbol_table_pmt, length); + symbol_table.assign(elements, elements + length); } void @IMPL_NAME@::set_vector_from_pmt(std::vector<float> &symbol_table, pmt::pmt_t &symbol_table_pmt) { - symbol_table.resize(0); - for (unsigned int i=0; i<pmt::length(symbol_table_pmt); i++) { - float f = pmt::f32vector_ref(symbol_table_pmt, i); - symbol_table.push_back(f); - } + size_t length; + const float *elements = pmt::f32vector_elements(symbol_table_pmt, length); + symbol_table.assign(elements, elements + length); } - + void @IMPL_NAME@::handle_set_symbol_table(pmt::pmt_t symbol_table_pmt) { - std::vector<@O_TYPE@> symbol_table; - set_vector_from_pmt(symbol_table, symbol_table_pmt); - set_symbol_table(symbol_table); + set_vector_from_pmt(d_symbol_table, symbol_table_pmt); } - void @IMPL_NAME@::set_symbol_table(const std::vector<@O_TYPE@> &symbol_table) { - d_symbol_table.resize(0); - for (unsigned int i=0; i<symbol_table.size(); i++) { - d_symbol_table.push_back(symbol_table[i]); - } + gr::thread::scoped_lock lock(d_setlock); + d_symbol_table = symbol_table; } int @@ -100,6 +92,7 @@ namespace gr { gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { + gr::thread::scoped_lock lock(d_setlock); assert(noutput_items % d_D == 0); assert(input_items.size() == output_items.size()); int nstreams = input_items.size(); @@ -114,7 +107,6 @@ namespace gr { // per stream processing for(int i = 0; i < noutput_items / d_D; i++) { - std::vector<tag_t> tags_now; tchecker.get_tags(tags_now, i+nitems_read(m)); for (unsigned int j=0; j<tags_now.size(); j++) { diff --git a/gr-filter/grc/filter_pfb_channelizer.xml b/gr-filter/grc/filter_pfb_channelizer.xml index 446acf0591..9b119dcdc1 100644 --- a/gr-filter/grc/filter_pfb_channelizer.xml +++ b/gr-filter/grc/filter_pfb_channelizer.xml @@ -33,7 +33,7 @@ self.$(id).declare_sample_delay($samp_delay) <type>real_vector</type> </param> <param> - <name>Over Sample Ratio</name> + <name>Oversampling Ratio</name> <key>osr</key> <value>1.0</value> <type>real</type> diff --git a/gr-filter/include/gnuradio/filter/pfb_arb_resampler.h b/gr-filter/include/gnuradio/filter/pfb_arb_resampler.h index 2af56e5f7f..cd4f940df5 100644 --- a/gr-filter/include/gnuradio/filter/pfb_arb_resampler.h +++ b/gr-filter/include/gnuradio/filter/pfb_arb_resampler.h @@ -86,7 +86,7 @@ namespace gr { * attenuation_dB=ATT, window=filter.firdes.WIN_BLACKMAN_hARRIS)</EM></B> * * The theory behind this block can be found in Chapter 7.5 of - * the following book. + * the following book: * * <B><EM>f. harris, "Multirate Signal Processing for Communication * Systems", Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B> @@ -399,7 +399,7 @@ namespace gr { * attenuation_dB=ATT, window=filter.firdes.WIN_BLACKMAN_hARRIS)</EM></B> * * The theory behind this block can be found in Chapter 7.5 of - * the following book. + * the following book: * * <B><EM>f. harris, "Multirate Signal Processing for Communication * Systems", Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B> diff --git a/gr-filter/include/gnuradio/filter/pfb_arb_resampler_fff.h b/gr-filter/include/gnuradio/filter/pfb_arb_resampler_fff.h index aadfb778dc..fa2f98cb19 100644 --- a/gr-filter/include/gnuradio/filter/pfb_arb_resampler_fff.h +++ b/gr-filter/include/gnuradio/filter/pfb_arb_resampler_fff.h @@ -86,7 +86,7 @@ namespace gr { * attenuation_dB=ATT, window=filter.firdes.WIN_BLACKMAN_hARRIS)</EM></B> * * The theory behind this block can be found in Chapter 7.5 of the - * following book. + * following book: * * <B><EM>f. harris, "Multirate Signal Processing for Communication * Systems", Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B> diff --git a/gr-filter/include/gnuradio/filter/pfb_channelizer_ccf.h b/gr-filter/include/gnuradio/filter/pfb_channelizer_ccf.h index 91ef57e728..92e0097d16 100644 --- a/gr-filter/include/gnuradio/filter/pfb_channelizer_ccf.h +++ b/gr-filter/include/gnuradio/filter/pfb_channelizer_ccf.h @@ -42,8 +42,8 @@ namespace gr { * <EM>fs</EM> divided by the number of channels, <EM>M</EM>. * * The PFB channelizer code takes the taps generated above and builds - * a set of filters. The set contains <EM>M</EM> number of filters - * and each filter contains ceil(taps.size()/decim) number of taps. + * a set of filters. The set contains <EM>M</EM>filters + * and each filter contains ceil(taps.size()/decim) taps. * Each tap from the filter prototype is sequentially inserted into * the next filter. When all of the input taps are used, the remaining * filters in the filterbank are filled out with 0's to make sure each @@ -77,12 +77,12 @@ namespace gr { * bandwidth of <EM>TB</EM>. We can also specify the out-of-band * attenuation to use, <EM>ATT</EM>, and the filter window * function (a Blackman-harris window in this case). The first input - * is the gain of the filter, which we specify here as unity. + * is the gain of the filter, which we specify here as unity. * - * <B><EM>self._taps = filter.firdes.low_pass_2(1, fs, BW, TB, - * attenuation_dB=ATT, window=filter.firdes.WIN_BLACKMAN_hARRIS)</EM></B> + * <B><EM>self._taps = filter.firdes.low_pass_2(1, fs, BW, TB, + * attenuation_dB=ATT, window=filter.firdes.WIN_BLACKMAN_hARRIS)</EM></B> * - * The filter output can also be overs ampled. The over sampling rate + * The filter output can also be oversampled. The oversampling rate * is the ratio of the the actual output sampling rate to the normal * output sampling rate. It must be rationally related to the number * of channels as N/i for i in [1,N], which gives an outputsample rate @@ -96,7 +96,7 @@ namespace gr { * so the output rate would be 1200 Hz. * * The theory behind this block can be found in Chapter 6 of - * the following book. + * the following book: * * <B><EM>f. harris, "Multirate Signal Processing for Communication * Systems," Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B> @@ -121,7 +121,7 @@ namespace gr { * channels <EM>M</EM> * \param taps (vector/list of floats) The prototype filter to * populate the filterbank. - * \param oversample_rate (float) The over sampling rate is the + * \param oversample_rate (float) The oversampling rate is the * ratio of the the actual output * sampling rate to the normal * output sampling rate. It must @@ -135,7 +135,7 @@ namespace gr { * * For example, for 6 channels * with fs = 6000 Hz, the normal - * rateis 6000/6 = 1000 + * rate is 6000/6 = 1000 * Hz. Allowable oversampling * rates are 6/6, 6/5, 6/4, 6/3, * 6/2, and 6/1 where the output diff --git a/gr-filter/include/gnuradio/filter/pfb_decimator_ccf.h b/gr-filter/include/gnuradio/filter/pfb_decimator_ccf.h index 5f0f2700b7..e0dd3125cd 100644 --- a/gr-filter/include/gnuradio/filter/pfb_decimator_ccf.h +++ b/gr-filter/include/gnuradio/filter/pfb_decimator_ccf.h @@ -73,16 +73,16 @@ namespace gr { * attenuation_dB=ATT, window=filter.firdes.WIN_BLACKMAN_hARRIS)</EM></B> * * The PFB decimator code takes the taps generated above and - * builds a set of filters. The set contains <EM>decim</EM> number - * of filters and each filter contains ceil(taps.size()/decim) - * number of taps. Each tap from the filter prototype is + * builds a set of filters. The set contains <EM>decim</EM> + * filters and each filter contains ceil(taps.size()/decim) + * taps. Each tap from the filter prototype is * sequentially inserted into the next filter. When all of the * input taps are used, the remaining filters in the filterbank * are filled out with 0's to make sure each filter has the same * number of taps. * * The theory behind this block can be found in Chapter 6 of - * the following book. + * the following book: * * <B><EM>f. harris, "Multirate Signal Processing for Communication * Systems," Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B> diff --git a/gr-filter/include/gnuradio/filter/pfb_interpolator_ccf.h b/gr-filter/include/gnuradio/filter/pfb_interpolator_ccf.h index 7624f9ef25..ea43d1354d 100644 --- a/gr-filter/include/gnuradio/filter/pfb_interpolator_ccf.h +++ b/gr-filter/include/gnuradio/filter/pfb_interpolator_ccf.h @@ -61,15 +61,15 @@ namespace gr { * * The PFB interpolator code takes the taps generated above and * builds a set of filters. The set contains <EM>interp</EM> - * number of filters and each filter contains - * ceil(taps.size()/interp) number of taps. Each tap from the + * filters and each filter contains + * ceil(taps.size()/interp) taps. Each tap from the * filter prototype is sequentially inserted into the next * filter. When all of the input taps are used, the remaining * filters in the filterbank are filled out with 0's to make sure * each filter has the same number of taps. * * The theory behind this block can be found in Chapter 7.1 of the - * following book. + * following book: * * <B><EM>f. harris, "Multirate Signal Processing for Communication * Systems</EM>," Upper Saddle River, NJ: Prentice Hall, diff --git a/gr-filter/include/gnuradio/filter/polyphase_filterbank.h b/gr-filter/include/gnuradio/filter/polyphase_filterbank.h index f3bedd811b..715574e0c7 100644 --- a/gr-filter/include/gnuradio/filter/polyphase_filterbank.h +++ b/gr-filter/include/gnuradio/filter/polyphase_filterbank.h @@ -46,9 +46,9 @@ namespace gr { * <EM>M</EM>. * * The PFB channelizer code takes the taps generated above and - * builds a set of filters. The set contains <EM>M</EM> number - * of filters and each filter contains ceil(taps.size()/decim) - * number of taps. Each tap from the filter prototype is + * builds a set of filters. The set contains <EM>M</EM> + * filters and each filter contains ceil(taps.size()/decim) + * taps. Each tap from the filter prototype is * sequentially inserted into the next filter. When all of the * input taps are used, the remaining filters in the filterbank * are filled out with 0's to make sure each filter has the same @@ -86,11 +86,11 @@ namespace gr { * input is the gain of the filter, which we specify here as * unity. * - * <B><EM>self._taps = filter.firdes.low_pass_2(1, fs, BW, TB, - * attenuation_dB=ATT, window=filter.firdes.WIN_BLACKMAN_hARRIS)</EM></B> + * <B><EM>self._taps = filter.firdes.low_pass_2(1, fs, BW, TB, + * attenuation_dB=ATT, window=filter.firdes.WIN_BLACKMAN_hARRIS)</EM></B> * * More on the theory of polyphase filterbanks can be found in - * the following book. + * the following book: * * <B><EM>f. harris, "Multirate Signal Processing for * Communication Systems," Upper Saddle River, NJ: diff --git a/gr-qtgui/grc/qtgui_ber_sink_b.xml b/gr-qtgui/grc/qtgui_ber_sink_b.xml index da3fc6ebf8..851502a774 100644 --- a/gr-qtgui/grc/qtgui_ber_sink_b.xml +++ b/gr-qtgui/grc/qtgui_ber_sink_b.xml @@ -47,7 +47,7 @@ for i in xrange($num_curves): self.$(id).set_line_alpha(i, alphas[i]) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> <param> <name>esno</name> diff --git a/gr-qtgui/grc/qtgui_check_box.xml b/gr-qtgui/grc/qtgui_check_box.xml index 67c8848a22..a02c83e3cf 100644 --- a/gr-qtgui/grc/qtgui_check_box.xml +++ b/gr-qtgui/grc/qtgui_check_box.xml @@ -20,7 +20,8 @@ self._$(id)_choices_inv = dict((v,k) for k,v in self._$(id)_choices.iteritems()) self._$(id)_callback = lambda i: Qt.QMetaObject.invokeMethod($(win), "setChecked", Qt.Q_ARG("bool", self._$(id)_choices_inv[i])) self._$(id)_callback(self.$id) $(win).stateChanged.connect(lambda i: self.set_$(id)(self._$(id)_choices[bool(i)])) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>self.set_$(id)($value)</callback> <callback>self._$(id)_callback($id)</callback> <param> diff --git a/gr-qtgui/grc/qtgui_chooser.xml b/gr-qtgui/grc/qtgui_chooser.xml index f018354dd4..b91566ae74 100644 --- a/gr-qtgui/grc/qtgui_chooser.xml +++ b/gr-qtgui/grc/qtgui_chooser.xml @@ -86,7 +86,8 @@ self._$(id)_callback(self.$id) self._$(id)_button_group.buttonClicked[int].connect( lambda i: self.set_$(id)(self._$(id)_options[i])) #end if -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>self.set_$(id)($value)</callback> <callback>self._$(id)_callback($id)</callback> <param> diff --git a/gr-qtgui/grc/qtgui_const_sink_x.xml b/gr-qtgui/grc/qtgui_const_sink_x.xml index 755f12f964..6bf31d5190 100644 --- a/gr-qtgui/grc/qtgui_const_sink_x.xml +++ b/gr-qtgui/grc/qtgui_const_sink_x.xml @@ -51,7 +51,8 @@ for i in xrange(#if $type.t == 'message' then 1 else $nconnections#): self.$(id).set_line_alpha(i, alphas[i]) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_resize($width, $height)</callback> <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> diff --git a/gr-qtgui/grc/qtgui_edit_box_msg.xml b/gr-qtgui/grc/qtgui_edit_box_msg.xml index c7c758a612..276cfe9801 100644 --- a/gr-qtgui/grc/qtgui_edit_box_msg.xml +++ b/gr-qtgui/grc/qtgui_edit_box_msg.xml @@ -13,7 +13,7 @@ <make>#set $win = 'self._%s_win'%$id qtgui.edit_box_msg($(type.t), $value, $label, $is_pair, $is_static, $key) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> <param> <name>Type</name> diff --git a/gr-qtgui/grc/qtgui_entry.xml b/gr-qtgui/grc/qtgui_entry.xml index cce2edb4b2..ab35aec858 100644 --- a/gr-qtgui/grc/qtgui_entry.xml +++ b/gr-qtgui/grc/qtgui_entry.xml @@ -21,9 +21,12 @@ self._$(id)_line_edit = Qt.QLineEdit(str(self.$id)) self._$(id)_tool_bar.addWidget(self._$(id)_line_edit) self._$(id)_line_edit.returnPressed.connect( lambda: self.set_$(id)($(type.conv)(str(self._$(id)_line_edit.text().toAscii())))) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>self.set_$(id)($value)</callback> + <callback>Qt.QMetaObject.invokeMethod(self._$(id)_line_edit, "setText", Qt.Q_ARG("QString", $(type.str)($id)))</callback> + <param> <name>Label</name> <key>label</key> diff --git a/gr-qtgui/grc/qtgui_freq_sink_x.xml b/gr-qtgui/grc/qtgui_freq_sink_x.xml index 009a184327..5c6595cb33 100644 --- a/gr-qtgui/grc/qtgui_freq_sink_x.xml +++ b/gr-qtgui/grc/qtgui_freq_sink_x.xml @@ -54,7 +54,8 @@ for i in xrange(#if $type.t == 'message' then 1 else $nconnections#): self.$(id).set_line_alpha(i, alphas[i]) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_frequency_range($fc, $bw)</callback> <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> diff --git a/gr-qtgui/grc/qtgui_histogram_sink_x.xml b/gr-qtgui/grc/qtgui_histogram_sink_x.xml index a789d2e4fa..8bf9662b74 100644 --- a/gr-qtgui/grc/qtgui_histogram_sink_x.xml +++ b/gr-qtgui/grc/qtgui_histogram_sink_x.xml @@ -53,8 +53,8 @@ for i in xrange(#if $type.t == 'message' then 1 else $nconnections#): self.$(id).set_line_alpha(i, alphas[i]) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win)) - </make> +$(gui_hint() % $win)</make> + <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> <callback>set_color($which, $color)</callback> diff --git a/gr-qtgui/grc/qtgui_label.xml b/gr-qtgui/grc/qtgui_label.xml index d67f3d7500..90b77fa968 100644 --- a/gr-qtgui/grc/qtgui_label.xml +++ b/gr-qtgui/grc/qtgui_label.xml @@ -26,8 +26,7 @@ else: $(win).addWidget(Qt.QLabel($label+": ")) self._$(id)_label = Qt.QLabel(str(self._$(id)_formatter(self.$id))) self._$(id)_tool_bar.addWidget(self._$(id)_label) -$(gui_hint()($win)) - </make> +$(gui_hint() % $win)</make> <callback>self.set_$(id)(self._$(id)_formatter($value))</callback> <callback>Qt.QMetaObject.invokeMethod(self._$(id)_label, "setText", Qt.Q_ARG("QString", $id))</callback> diff --git a/gr-qtgui/grc/qtgui_number_sink.xml b/gr-qtgui/grc/qtgui_number_sink.xml index d10b7325c0..264baae667 100644 --- a/gr-qtgui/grc/qtgui_number_sink.xml +++ b/gr-qtgui/grc/qtgui_number_sink.xml @@ -41,7 +41,8 @@ for i in xrange($nconnections): self.$(id).enable_autoscale($autoscale) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_update_time($update_time)</callback> <param_tab_order> diff --git a/gr-qtgui/grc/qtgui_push_button.xml b/gr-qtgui/grc/qtgui_push_button.xml index a535bb6473..e4f598e725 100644 --- a/gr-qtgui/grc/qtgui_push_button.xml +++ b/gr-qtgui/grc/qtgui_push_button.xml @@ -18,8 +18,10 @@ $win = Qt.QPushButton($label) self._$(id)_choices = {'Pressed': $pressed, 'Released': $released} $(win).pressed.connect(lambda: self.set_$(id)(self._$(id)_choices['Pressed'])) $(win).released.connect(lambda: self.set_$(id)(self._$(id)_choices['Released'])) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>self.set_$(id)($value)</callback> + <param> <name>Label</name> <key>label</key> diff --git a/gr-qtgui/grc/qtgui_range.xml b/gr-qtgui/grc/qtgui_range.xml index 71b614cc5e..0999311a0b 100644 --- a/gr-qtgui/grc/qtgui_range.xml +++ b/gr-qtgui/grc/qtgui_range.xml @@ -17,7 +17,8 @@ #end if $(range) = Range($start, $stop, $step, $value, $min_len) $(win) = RangeWidget($range, self.set_$(id), $label, "$widget", $rangeType) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>self.set_$(id)($value)</callback> <param> diff --git a/gr-qtgui/grc/qtgui_sink_x.xml b/gr-qtgui/grc/qtgui_sink_x.xml index 7488ea59d8..4dbf0e6375 100644 --- a/gr-qtgui/grc/qtgui_sink_x.xml +++ b/gr-qtgui/grc/qtgui_sink_x.xml @@ -25,7 +25,7 @@ qtgui.$(type.fcn)( ) self.$(id).set_update_time(1.0/$rate) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win)) +$(gui_hint() % $win) self.$(id).enable_rf_freq($showrf) diff --git a/gr-qtgui/grc/qtgui_tab_widget.xml b/gr-qtgui/grc/qtgui_tab_widget.xml index 1bbadc8e51..fc8ad0553a 100644 --- a/gr-qtgui/grc/qtgui_tab_widget.xml +++ b/gr-qtgui/grc/qtgui_tab_widget.xml @@ -21,7 +21,8 @@ self.$(id)_grid_layout_$(i) = Qt.QGridLayout() self.$(id)_layout_$(i).addLayout(self.$(id)_grid_layout_$(i)) $(win).addTab(self.$(id)_widget_$(i), $label) #end for -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <param> <name>Num Tabs</name> <key>num_tabs</key> diff --git a/gr-qtgui/grc/qtgui_time_raster_x.xml b/gr-qtgui/grc/qtgui_time_raster_x.xml index 0359dc3b71..2d2f3cbff4 100644 --- a/gr-qtgui/grc/qtgui_time_raster_x.xml +++ b/gr-qtgui/grc/qtgui_time_raster_x.xml @@ -41,7 +41,8 @@ for i in xrange(#if $type.t == 'message' then 1 else $nconnections#): self.$(id).set_line_alpha(i, alphas[i]) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_num_rows($nrows)</callback> <callback>set_num_cols($ncols)</callback> <callback>set_multiplier($mult)</callback> diff --git a/gr-qtgui/grc/qtgui_time_sink_x.xml b/gr-qtgui/grc/qtgui_time_sink_x.xml index b44a8fe52d..a263e6ef98 100644 --- a/gr-qtgui/grc/qtgui_time_sink_x.xml +++ b/gr-qtgui/grc/qtgui_time_sink_x.xml @@ -75,7 +75,8 @@ for i in xrange(#if $type.t == 'message' then 1 else $nconnections#): #end if self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_time_domain_axis($min, $max)</callback> <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> diff --git a/gr-qtgui/grc/qtgui_vector_sink_f.xml b/gr-qtgui/grc/qtgui_vector_sink_f.xml index 9f40d57729..1c17b8256a 100644 --- a/gr-qtgui/grc/qtgui_vector_sink_f.xml +++ b/gr-qtgui/grc/qtgui_vector_sink_f.xml @@ -46,7 +46,8 @@ for i in xrange($nconnections): self.$(id).set_line_alpha(i, alphas[i]) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_update_time($update_time)</callback> <callback>set_title($title)</callback> <callback>set_color($which, $color)</callback> diff --git a/gr-qtgui/grc/qtgui_waterfall_sink_x.xml b/gr-qtgui/grc/qtgui_waterfall_sink_x.xml index cdecd5cce1..206318e30d 100644 --- a/gr-qtgui/grc/qtgui_waterfall_sink_x.xml +++ b/gr-qtgui/grc/qtgui_waterfall_sink_x.xml @@ -47,7 +47,8 @@ for i in xrange(#if $type.t == 'message' then 1 else $nconnections#): self.$(id).set_intensity_range($int_min, $int_max) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) -$(gui_hint()($win))</make> +$(gui_hint() % $win)</make> + <callback>set_frequency_range($fc, $bw)</callback> <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> diff --git a/grc/core/Param.py b/grc/core/Param.py index 00c9e7d827..01697919d0 100644 --- a/grc/core/Param.py +++ b/grc/core/Param.py @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import ast import weakref import re +import textwrap from . import Constants from .Constants import VECTOR_TYPES, COMPLEX_TYPES, REAL_TYPES, INT_TYPES @@ -212,7 +213,7 @@ class Param(Element): self._value = value or '' self._default = value self._init = False - self._hostage_cells = list() + self.hostage_cells = set() self.template_arg = TemplateArg(self) def get_types(self): @@ -395,7 +396,6 @@ class Param(Element): self._init = True self._lisitify_flag = False self._stringify_flag = False - self._hostage_cells = list() t = self.get_type() v = self.get_value() @@ -533,38 +533,10 @@ class Param(Element): # GUI Position/Hint ######################### elif t == 'gui_hint': - if ':' in v: - tab, pos = v.split(':') - elif '@' in v: - tab, pos = v, '' - else: - tab, pos = '', v - - if '@' in tab: - tab, index = tab.split('@') + if (self.get_parent().get_state() == Constants.BLOCK_DISABLED): + return '' else: - index = '?' - - # TODO: Problem with this code. Produces bad tabs - widget_str = ({ - (True, True): 'self.%(tab)s_grid_layout_%(index)s.addWidget(%(widget)s, %(pos)s)', - (True, False): 'self.%(tab)s_layout_%(index)s.addWidget(%(widget)s)', - (False, True): 'self.top_grid_layout.addWidget(%(widget)s, %(pos)s)', - (False, False): 'self.top_layout.addWidget(%(widget)s)', - }[bool(tab), bool(pos)]) % {'tab': tab, 'index': index, 'widget': '%s', 'pos': pos} - - # FIXME: Move replace(...) into the make template of the qtgui blocks - # Return a string here - class GuiHint(object): - def __init__(self, ws): - self._ws = ws - - def __call__(self, w): - return (self._ws.replace('addWidget', 'addLayout') if 'layout' in w else self._ws) % w - - def __str__(self): - return self._ws - return GuiHint(widget_str) + return self.parse_gui_hint(v) ######################### # Grid Position Type ######################### @@ -590,12 +562,12 @@ class Param(Element): # Calculate hostage cells for r in range(row_span): for c in range(col_span): - self._hostage_cells.append((my_parent, (row+r, col+c))) + self.hostage_cells.append((my_parent, (row + r, col + c))) # Avoid collisions params = filter(lambda p: p is not self, self.get_all_params('grid_pos')) for param in params: for parent, cell in param._hostage_cells: - if (parent, cell) in self._hostage_cells: + if (parent, cell) in self.hostage_cells: raise Exception('Another graphical element is using parent "{0}", cell "{1}".'.format(str(parent), str(cell))) return e ######################### @@ -753,3 +725,113 @@ class Param(Element): n['key'] = self.get_key() n['value'] = self.get_value() return n + + ############################################## + # GUI Hint + ############################################## + def parse_gui_hint(self, v): + """ + Parse/validate gui hint value. + + Args: + v: gui_hint string from a block's 'gui_hint' param + + Returns: + string of python code for positioning GUI elements in pyQT + """ + self.hostage_cells.clear() + + # Parsing + if ':' in v: + tab, pos = v.split(':') + elif ',' in v: + tab, pos = '', v + else: + tab, pos = v, '' + + if '@' in tab: + tab, index = tab.split('@') + else: + index = '0' + index = int(index) + + # Validation + def parse_pos(): + e = self.get_parent().get_parent().evaluate(pos) + + if not isinstance(e, (list, tuple)) or len(e) not in (2, 4) or not all(isinstance(ei, int) for ei in e): + raise Exception('Invalid GUI Hint entered: {e!r} (Must be a list of {{2,4}} non-negative integers).'.format(e=e)) + + if len(e) == 2: + row, col = e + row_span = col_span = 1 + else: + row, col, row_span, col_span = e + + if (row < 0) or (col < 0): + raise Exception('Invalid GUI Hint entered: {e!r} (non-negative integers only).'.format(e=e)) + + if (row_span < 1) or (col_span < 1): + raise Exception('Invalid GUI Hint entered: {e!r} (positive row/column span required).'.format(e=e)) + + return row, col, row_span, col_span + + def validate_tab(): + enabled_blocks = self.get_parent().get_parent().iter_enabled_blocks() + tabs = (block for block in enabled_blocks + if block.get_key() == 'qtgui_tab_widget' and block.get_id() == tab) + tab_block = next(iter(tabs), None) + if not tab_block: + raise Exception('Invalid tab name entered: {tab} (Tab name not found).'.format(tab=tab)) + + tab_index_size = int(tab_block.get_param('num_tabs').get_value()) + if index >= tab_index_size: + raise Exception('Invalid tab index entered: {tab}@{index} (Index out of range).'.format( + tab=tab, index=index)) + + # Collision Detection + def collision_detection(row, col, row_span, col_span): + my_parent = '{tab}@{index}'.format(tab=tab, index=index) if tab else 'main' + # Calculate hostage cells + for r in range(row, row + row_span): + for c in range(col, col + col_span): + self.hostage_cells.add((my_parent, (r, c))) + + for other in self.get_all_params('gui_hint'): + if other is self: + continue + collision = next(iter(self.hostage_cells & other.hostage_cells), None) + if collision: + raise Exception('Block {block!r} is also using parent {parent!r}, cell {cell!r}.'.format( + block=other.get_parent().get_id(), parent=collision[0], cell=collision[1] + )) + + # Code Generation + if tab: + validate_tab() + layout = '{tab}_grid_layout_{index}'.format(tab=tab, index=index) + else: + layout = 'top_grid_layout' + + widget = '%s' # to be fill-out in the mail template + + if pos: + row, col, row_span, col_span = parse_pos() + collision_detection(row, col, row_span, col_span) + + widget_str = textwrap.dedent(""" + self.{layout}.addWidget({widget}, {row}, {col}, {row_span}, {col_span}) + for r in range({row}, {row_end}): + self.{layout}.setRowStretch(r, 1) + for c in range({col}, {col_end}): + self.{layout}.setColumnStretch(c, 1) + """.strip('\n')).format( + layout=layout, widget=widget, + row=row, row_span=row_span, row_end=row+row_span, + col=col, col_span=col_span, col_end=col+col_span, + ) + + else: + widget_str = 'self.{layout}.addWidget({widget})'.format(layout=layout, widget=widget) + + return widget_str diff --git a/grc/core/generator/Generator.py b/grc/core/generator/Generator.py index 3b82be9084..f42392e485 100644 --- a/grc/core/generator/Generator.py +++ b/grc/core/generator/Generator.py @@ -399,6 +399,6 @@ class QtHierBlockGenerator(HierBlockGenerator): block_n['make'] += ( "\n#set $win = 'self.%s' % $id" - "\n${gui_hint()($win)}" + "\n${gui_hint() % $win}" ) return n diff --git a/grc/gui/BlockTreeWindow.py b/grc/gui/BlockTreeWindow.py index 900cbd3151..258b8b787f 100644 --- a/grc/gui/BlockTreeWindow.py +++ b/grc/gui/BlockTreeWindow.py @@ -58,7 +58,8 @@ undocumented#slurp CAT_MARKUP_TMPL = """ #set $name = $cat[-1] #if len($cat) > 1 -Category: $cat[-1] +#silent from xml.sax.saxutils import escape +Category: #echo escape($cat[-1]) ## #elif $name == 'Core' Module: Core |