diff options
260 files changed, 14146 insertions, 7137 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 5203e6d4ce..3641ab4b5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,8 +46,8 @@ message(STATUS "Build type set to ${CMAKE_BUILD_TYPE}.") # Set the version information here set(VERSION_INFO_MAJOR_VERSION 3) set(VERSION_INFO_API_COMPAT 7) -set(VERSION_INFO_MINOR_VERSION 9) -set(VERSION_INFO_MAINT_VERSION 2) +set(VERSION_INFO_MINOR_VERSION 10) +set(VERSION_INFO_MAINT_VERSION git) include(GrVersion) #setup version info # Append -O2 optimization flag for Debug builds diff --git a/cmake/Modules/GrVersion.cmake b/cmake/Modules/GrVersion.cmake index bafd0a7326..dceac67bab 100644 --- a/cmake/Modules/GrVersion.cmake +++ b/cmake/Modules/GrVersion.cmake @@ -41,7 +41,13 @@ if(GIT_FOUND AND EXISTS ${CMAKE_SOURCE_DIR}/.git) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) else() - set(GIT_DESCRIBE "v${MAJOR_VERSION}.${API_COMPAT}.x-xxx-xunknown") + if(NOT GR_GIT_COUNT) + set(GR_GIT_COUNT "compat-xxx") + endif() + if(NOT GR_GIT_HASH) + set(GR_GIT_HASH "xunknown") + endif() + set(GIT_DESCRIBE "v${MAJOR_VERSION}.${API_COMPAT}-${GR_GIT_COUNT}-${GR_GIT_HASH}") endif() ######################################################################## diff --git a/docs/exploring-gnuradio/fm_tx.grc b/docs/exploring-gnuradio/fm_tx.grc index 2f047bf09b..bb13417a6b 100644 --- a/docs/exploring-gnuradio/fm_tx.grc +++ b/docs/exploring-gnuradio/fm_tx.grc @@ -792,6 +792,10 @@ <value>75e3</value> </param> <param> + <key>fh</key> + <value>0.925 * tx_rate/2.0</value> + </param> + <param> <key>affinity</key> <value></value> </param> diff --git a/gnuradio-runtime/include/gnuradio/block.h b/gnuradio-runtime/include/gnuradio/block.h index c6185d9f2d..a484ccf429 100644 --- a/gnuradio-runtime/include/gnuradio/block.h +++ b/gnuradio-runtime/include/gnuradio/block.h @@ -80,7 +80,9 @@ namespace gr { * History is the number of x_i's that are examined to produce one y_i. * This comes in handy for FIR filters, where we use history to * ensure that our input contains the appropriate "history" for the - * filter. History should be equal to the number of filter taps. + * filter. History should be equal to the number of filter taps. First + * history samples (when there are no previous samples) are + * initialized with zeroes. */ unsigned history() const; void set_history(unsigned history); diff --git a/gnuradio-runtime/include/gnuradio/block_detail.h b/gnuradio-runtime/include/gnuradio/block_detail.h index 916c0a46c1..a71030b439 100644 --- a/gnuradio-runtime/include/gnuradio/block_detail.h +++ b/gnuradio-runtime/include/gnuradio/block_detail.h @@ -100,6 +100,13 @@ namespace gr { // Return the number of items written on output stream which_output uint64_t nitems_written(unsigned int which_output); + // sets nitems_read and nitems_written to 0 for all input/output + // buffers. + void reset_nitem_counters(); + + // Clears all tags from the input buffers. + void clear_tags(); + /*! * \brief Adds a new tag to the given output stream. * diff --git a/gnuradio-runtime/include/gnuradio/buffer.h b/gnuradio-runtime/include/gnuradio/buffer.h index 5da383dc8f..914661b318 100644 --- a/gnuradio-runtime/include/gnuradio/buffer.h +++ b/gnuradio-runtime/include/gnuradio/buffer.h @@ -100,6 +100,8 @@ namespace gr { uint64_t nitems_written() { return d_abs_write_offset; } + void reset_nitem_counter() { d_abs_write_offset = 0; } + size_t get_sizeof_item() { return d_sizeof_item; } /*! @@ -288,6 +290,8 @@ namespace gr { uint64_t nitems_read() { return d_abs_read_offset; } + void reset_nitem_counter() { d_abs_read_offset = 0; } + size_t get_sizeof_item() { return d_buffer->get_sizeof_item(); } /*! diff --git a/gnuradio-runtime/lib/block_detail.cc b/gnuradio-runtime/lib/block_detail.cc index 9463e8d13b..484d849652 100644 --- a/gnuradio-runtime/lib/block_detail.cc +++ b/gnuradio-runtime/lib/block_detail.cc @@ -162,6 +162,26 @@ namespace gr { } void + block_detail::reset_nitem_counters() + { + for(unsigned int i = 0; i < d_ninputs; i++) { + d_input[i]->reset_nitem_counter(); + } + for(unsigned int o = 0; o < d_noutputs; o++) { + d_output[o]->reset_nitem_counter(); + } + } + + void + block_detail::clear_tags() + { + for(unsigned int i = 0; i < d_ninputs; i++) { + uint64_t max_time = 0xFFFFFFFFFFFFFFFF; // from now to the end of time + d_input[i]->buffer()->prune_tags(max_time); + } + } + + void block_detail::add_item_tag(unsigned int which_output, const tag_t &tag) { if(!pmt::is_symbol(tag.key)) { diff --git a/gnuradio-runtime/lib/flat_flowgraph.cc b/gnuradio-runtime/lib/flat_flowgraph.cc index 81c1184cfa..03e67eb2c2 100644 --- a/gnuradio-runtime/lib/flat_flowgraph.cc +++ b/gnuradio-runtime/lib/flat_flowgraph.cc @@ -177,6 +177,13 @@ namespace gr { catch(std::bad_alloc&) { b = make_buffer(nitems, item_size, grblock); } + + // Set the max noutput items size here to make sure it's always + // set in the block and available in the start() method. + // But don't overwrite if the user has set this externally. + if(!grblock->is_set_max_noutput_items()) + grblock->set_max_noutput_items(nitems); + return b; } @@ -225,9 +232,10 @@ namespace gr { std::cout << "merge: allocating new detail for block " << (*p) << std::endl; block->set_detail(allocate_block_detail(block)); } - else + else { if(FLAT_FLOWGRAPH_DEBUG) std::cout << "merge: reusing original detail for block " << (*p) << std::endl; + } } // Calculate the old edges that will be going away, and clear the @@ -311,6 +319,9 @@ namespace gr { // Now deal with the fact that the block details might have // changed numbers of inputs and outputs vs. in the old // flowgraph. + + block->detail()->reset_nitem_counters(); + block->detail()->clear_tags(); } } diff --git a/gr-analog/examples/fmtest.py b/gr-analog/examples/fmtest.py index 327da8eacb..7ed08cafbe 100755 --- a/gr-analog/examples/fmtest.py +++ b/gr-analog/examples/fmtest.py @@ -48,7 +48,8 @@ class fmtx(gr.hier_block2): gr.io_signature(1, 1, gr.sizeof_float), gr.io_signature(1, 1, gr.sizeof_gr_complex)) - fmtx = analog.nbfm_tx(audio_rate, if_rate, max_dev=5e3, tau=75e-6) + fmtx = analog.nbfm_tx(audio_rate, if_rate, max_dev=5e3, + tau=75e-6, fh=0.925*if_rate/2.0) # Local oscillator lo = analog.sig_source_c(if_rate, # sample rate diff --git a/gr-analog/grc/analog_fm_preemph.xml b/gr-analog/grc/analog_fm_preemph.xml index fb898b87f3..a754ce9c6f 100644 --- a/gr-analog/grc/analog_fm_preemph.xml +++ b/gr-analog/grc/analog_fm_preemph.xml @@ -8,7 +8,7 @@ <name>FM Preemphasis</name> <key>analog_fm_preemph</key> <import>from gnuradio import analog</import> - <make>analog.fm_preemph(fs=$samp_rate, tau=$tau)</make> + <make>analog.fm_preemph(fs=$samp_rate, tau=$tau, fh=$fh)</make> <param> <name>Sample Rate</name> <key>samp_rate</key> @@ -20,6 +20,12 @@ <value>75e-6</value> <type>real</type> </param> + <param> + <name>High Corner Freq</name> + <key>fh</key> + <value>-1.0</value> + <type>real</type> + </param> <sink> <name>in</name> <type>float</type> diff --git a/gr-analog/grc/analog_nbfm_tx.xml b/gr-analog/grc/analog_nbfm_tx.xml index ea13b8f1c9..bc80fffbcb 100644 --- a/gr-analog/grc/analog_nbfm_tx.xml +++ b/gr-analog/grc/analog_nbfm_tx.xml @@ -13,6 +13,7 @@ quad_rate=$quad_rate, tau=$tau, max_dev=$max_dev, + fh=$fh, )</make> <callback>set_max_deviation($max_dev)</callback> @@ -42,6 +43,13 @@ <type>real</type> </param> + <param> + <name>Preemphasis High Corner Freq</name> + <key>fh</key> + <value>-1.0</value> + <type>real</type> + </param> + <check>($quad_rate)%($audio_rate) == 0</check> <sink> diff --git a/gr-analog/grc/analog_wfm_tx.xml b/gr-analog/grc/analog_wfm_tx.xml index 89844f9ef3..507c2ea894 100644 --- a/gr-analog/grc/analog_wfm_tx.xml +++ b/gr-analog/grc/analog_wfm_tx.xml @@ -13,6 +13,7 @@ quad_rate=$quad_rate, tau=$tau, max_dev=$max_dev, + fh=$fh, )</make> <param> <name>Audio Rate</name> @@ -36,6 +37,12 @@ <value>75e3</value> <type>real</type> </param> + <param> + <name>Preemphasis High Corner Freq</name> + <key>fh</key> + <value>-1.0</value> + <type>real</type> + </param> <check>($quad_rate)%($audio_rate) == 0</check> <sink> <name>in</name> diff --git a/gr-analog/lib/CMakeLists.txt b/gr-analog/lib/CMakeLists.txt index 918f894abe..a75d70337b 100644 --- a/gr-analog/lib/CMakeLists.txt +++ b/gr-analog/lib/CMakeLists.txt @@ -110,17 +110,6 @@ GR_LIBRARY_FOO(gnuradio-analog RUNTIME_COMPONENT "analog_runtime" DEVEL_COMPONEN add_dependencies(gnuradio-analog analog_generated_includes analog_generated_swigs gnuradio-filter) if(ENABLE_STATIC_LIBS) - if(ENABLE_GR_CTRLPORT) - # Remove GR_CTRLPORT set this target's definitions. - # Makes sure we don't try to use ControlPort stuff in source files - GET_DIRECTORY_PROPERTY(STATIC_DEFS COMPILE_DEFINITIONS) - list(REMOVE_ITEM STATIC_DEFS "GR_CTRLPORT") - SET_PROPERTY(DIRECTORY PROPERTY COMPILE_DEFINITIONS "${STATIC_DEFS}") - - # readd it to the target since we removed it from the directory-wide list. - SET_PROPERTY(TARGET gnuradio-analog APPEND PROPERTY COMPILE_DEFINITIONS "GR_CTRLPORT") - endif(ENABLE_GR_CTRLPORT) - add_library(gnuradio-analog_static STATIC ${analog_sources}) add_dependencies(gnuradio-analog_static diff --git a/gr-analog/lib/frequency_modulator_fc_impl.cc b/gr-analog/lib/frequency_modulator_fc_impl.cc index 812eb8bf0b..56fa0f7c17 100644 --- a/gr-analog/lib/frequency_modulator_fc_impl.cc +++ b/gr-analog/lib/frequency_modulator_fc_impl.cc @@ -76,5 +76,27 @@ namespace gr { return noutput_items; } + void + frequency_modulator_fc_impl::setup_rpc() + { +#ifdef GR_CTRLPORT + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<frequency_modulator_fc, float>( + alias(), "sensitivity", + &frequency_modulator_fc::sensitivity, + pmt::mp(-1024.0f), pmt::mp(1024.0f), pmt::mp(0.0f), + "", "Sensitivity", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_set<frequency_modulator_fc, float>( + alias(), "sensitivity", + &frequency_modulator_fc::set_sensitivity, + pmt::mp(-1024.0f), pmt::mp(1024.0f), pmt::mp(0.0f), + "", "sensitivity", + RPC_PRIVLVL_MIN, DISPNULL))); +#endif /* GR_CTRLPORT */ + + } } /* namespace analog */ } /* namespace gr */ diff --git a/gr-analog/lib/frequency_modulator_fc_impl.h b/gr-analog/lib/frequency_modulator_fc_impl.h index 9f5310ce97..9f595d1ddb 100644 --- a/gr-analog/lib/frequency_modulator_fc_impl.h +++ b/gr-analog/lib/frequency_modulator_fc_impl.h @@ -41,6 +41,8 @@ namespace gr { void set_sensitivity(float sens) { d_sensitivity = sens; } float sensitivity() const { return d_sensitivity; } + void setup_rpc(); + int work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); diff --git a/gr-analog/lib/sig_source_X_impl.cc.t b/gr-analog/lib/sig_source_X_impl.cc.t index 227d4ba46e..017177eae0 100644 --- a/gr-analog/lib/sig_source_X_impl.cc.t +++ b/gr-analog/lib/sig_source_X_impl.cc.t @@ -53,7 +53,7 @@ namespace gr { d_frequency(frequency), d_ampl(ampl), d_offset(offset) { set_frequency(frequency); - + message_port_register_in(pmt::mp("freq")); set_msg_handler(pmt::mp("freq"), boost::bind(&@IMPL_NAME@::set_frequency_msg, this, _1)); } @@ -62,6 +62,36 @@ namespace gr { { } + void + @IMPL_NAME@::set_frequency_msg(pmt::pmt_t msg) + { + // Accepts either a number that is assumed to be the new + // frequency or a key:value pair message where the key must be + // "freq" and the value is the new frequency. + + if(pmt::is_number(msg)) { + set_frequency(pmt::to_double(msg)); + } + else if(pmt::is_pair(msg)) { + pmt::pmt_t key = pmt::car(msg); + pmt::pmt_t val = pmt::cdr(msg); + if(pmt::eq(key, pmt::intern("freq"))) { + if(pmt::is_number(val)) { + set_frequency(pmt::to_double(val)); + } + } + else { + GR_LOG_WARN(d_logger, boost::format("Set Frequency Message must have " + "the key = 'freq'; got '%1%'.") \ + % pmt::write_string(key)); + } + } + else { + GR_LOG_WARN(d_logger, "Set Frequency Message must be either a number or a " + "key:value pair where the key is 'freq'."); + } + } + int @IMPL_NAME@::work(int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gr-analog/lib/sig_source_X_impl.h.t b/gr-analog/lib/sig_source_X_impl.h.t index bd3609df16..f5dfd5c4f6 100644 --- a/gr-analog/lib/sig_source_X_impl.h.t +++ b/gr-analog/lib/sig_source_X_impl.h.t @@ -59,7 +59,7 @@ namespace gr { void set_sampling_freq(double sampling_freq); void set_waveform(gr_waveform_t waveform); - void set_frequency_msg(pmt::pmt_t msg){ set_frequency(pmt::to_double(msg)); }; + void set_frequency_msg(pmt::pmt_t msg); void set_frequency(double frequency); void set_amplitude(double ampl); void set_offset(@TYPE@ offset); diff --git a/gr-analog/python/analog/fm_emph.py b/gr-analog/python/analog/fm_emph.py index d2a38d4aff..bfa4742ace 100644 --- a/gr-analog/python/analog/fm_emph.py +++ b/gr-analog/python/analog/fm_emph.py @@ -21,17 +21,78 @@ from gnuradio import gr, filter import math +import cmath # -# 1 -# H(s) = ------- -# 1 + s +# An analog deemphasis filter: # -# tau is the RC time constant. -# critical frequency: w_p = 1/tau +# R +# o------/\/\/\/---+----o +# | +# = C +# | +# --- # -# We prewarp and use the bilinear z-transform to get our IIR coefficients. -# See "Digital Signal Processing: A Practical Approach" by Ifeachor and Jervis +# Has this transfer function: +# +# 1 1 +# ---- --- +# RC tau +# H(s) = ---------- = ---------- +# 1 1 +# s + ---- s + --- +# RC tau +# +# And has its -3 dB response, due to the pole, at +# +# |H(j w_c)|^2 = 1/2 => s = j w_c = j (1/(RC)) +# +# Historically, this corner frequency of analog audio deemphasis filters +# been specified by the RC time constant used, called tau. +# So w_c = 1/tau. +# +# FWIW, for standard tau values, some standard analog components would be: +# tau = 75 us = (50K)(1.5 nF) = (50 ohms)(1.5 uF) +# tau = 50 us = (50K)(1.0 nF) = (50 ohms)(1.0 uF) +# +# In specifying tau for this digital deemphasis filter, tau specifies +# the *digital* corner frequency, w_c, desired. +# +# The digital deemphasis filter design below, uses the +# "bilinear transformation" method of designing digital filters: +# +# 1. Convert digitial specifications into the analog domain, by prewarping +# digital frequency specifications into analog frequencies. +# +# w_a = (2/T)tan(wT/2) +# +# 2. Use an analog filter design technique to design the filter. +# +# 3. Use the bilinear transformation to convert the analog filter design to a +# digital filter design. +# +# H(z) = H(s)| +# s = (2/T)(1-z^-1)/(1+z^-1) +# +# +# w_ca 1 1 - (-1) z^-1 +# H(z) = ---- * ----------- * ----------------------- +# 2 fs -w_ca -w_ca +# 1 - ----- 1 + ----- +# 2 fs 2 fs +# 1 - ----------- z^-1 +# -w_ca +# 1 - ----- +# 2 fs +# +# We use this design technique, because it is an easy way to obtain a filter +# design with the -6 dB/octave roll-off required of the deemphasis filter. +# +# Jackson, Leland B., _Digital_Filters_and_Signal_Processing_Second_Edition_, +# Kluwer Academic Publishers, 1989, pp 201-212 +# +# Orfanidis, Sophocles J., _Introduction_to_Signal_Processing_, Prentice Hall, +# 1996, pp 573-583 # @@ -51,15 +112,24 @@ class fm_deemph(gr.hier_block2): gr.io_signature(1, 1, gr.sizeof_float), # Input signature gr.io_signature(1, 1, gr.sizeof_float)) # Output signature - w_p = 1/tau - w_pp = math.tan(w_p / (fs * 2)) # prewarped analog freq + # Digital corner frequency + w_c = 1.0 / tau + + # Prewarped analog corner frequency + w_ca = 2.0 * fs * math.tan(w_c / (2.0 * fs)) - a1 = (w_pp - 1)/(w_pp + 1) - b0 = w_pp/(1 + w_pp) - b1 = b0 + # Resulting digital pole, zero, and gain term from the bilinear + # transformation of H(s) = w_ca / (s + w_ca) to + # H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1) + k = -w_ca / (2.0 * fs) + z1 = -1.0 + p1 = (1.0 + k) / (1.0 - k) + b0 = -k / (1.0 - k) - btaps = [b0, b1] - ataps = [1, a1] + btaps = [ b0 * 1.0, b0 * -z1 ] + ataps = [ 1.0, -p1 ] + + # Since H(s = 0) = 1.0, then H(z = 1) = 1.0 and has 0 dB gain at DC if 0: print "btaps =", btaps @@ -67,26 +137,17 @@ class fm_deemph(gr.hier_block2): global plot1 plot1 = gru.gnuplot_freqz(gru.freqz(btaps, ataps), fs, True) - deemph = filter.iir_filter_ffd(btaps, ataps) + deemph = filter.iir_filter_ffd(btaps, ataps, False) self.connect(self, deemph, self) # -# 1 + s*t1 -# H(s) = ---------- -# 1 + s*t2 -# -# I think this is the right transfer function. -# +# An analog preemphasis filter, that flattens out again at the high end: # -# This fine ASCII rendition is based on Figure 5-15 -# in "Digital and Analog Communication Systems", Leon W. Couch II -# -# -# R1 +# C # +-----||------+ # | | # o------+ +-----+--------o -# | C1 | | +# | R1 | | # +----/\/\/\/--+ \ # / # \ R2 @@ -95,28 +156,94 @@ class fm_deemph(gr.hier_block2): # | # o--------------------------+--------o # -# f1 = 1/(2*pi*t1) = 1/(2*pi*R1*C) +# (This fine ASCII rendition is based on Figure 5-15 +# in "Digital and Analog Communication Systems", Leon W. Couch II) +# +# Has this transfer function: # -# 1 R1 + R2 -# f2 = ------- = ------------ -# 2*pi*t2 2*pi*R1*R2*C +# 1 +# s + --- +# R1C +# H(s) = ------------------ +# 1 R1 +# s + --- (1 + --) +# R1C R2 # -# t1 is 75us in US, 50us in EUR -# f2 should be higher than our audio bandwidth. # +# It has a corner due to the numerator, where the rise starts, at # -# The Bode plot looks like this: +# |Hn(j w_cl)|^2 = 2*|Hn(0)|^2 => s = j w_cl = j (1/(R1C)) # +# It has a corner due to the denominator, where it levels off again, at # -# /---------------- -# / -# / <-- slope = 20dB/decade -# / -# -------------/ -# f1 f2 +# |Hn(j w_ch)|^2 = 1/2*|Hd(0)|^2 => s = j w_ch = j (1/(R1C) * (1 + R1/R2)) # -# We prewarp and use the bilinear z-transform to get our IIR coefficients. -# See "Digital Signal Processing: A Practical Approach" by Ifeachor and Jervis +# Historically, the corner frequency of analog audio preemphasis filters +# been specified by the R1C time constant used, called tau. +# +# So +# w_cl = 1/tau = 1/R1C; f_cl = 1/(2*pi*tau) = 1/(2*pi*R1*C) +# w_ch = 1/tau2 = (1+R1/R2)/R1C; f_ch = 1/(2*pi*tau2) = (1+R1/R2)/(2*pi*R1*C) +# +# and note f_ch = f_cl * (1 + R1/R2). +# +# For broadcast FM audio, tau is 75us in the United States and 50us in Europe. +# f_ch should be higher than our digital audio bandwidth. +# +# The Bode plot looks like this: +# +# +# /---------------- +# / +# / <-- slope = 20dB/decade +# / +# -------------/ +# f_cl f_ch +# +# In specifying tau for this digital preemphasis filter, tau specifies +# the *digital* corner frequency, w_cl, desired. +# +# The digital preemphasis filter design below, uses the +# "bilinear transformation" method of designing digital filters: +# +# 1. Convert digitial specifications into the analog domain, by prewarping +# digital frequency specifications into analog frequencies. +# +# w_a = (2/T)tan(wT/2) +# +# 2. Use an analog filter design technique to design the filter. +# +# 3. Use the bilinear transformation to convert the analog filter design to a +# digital filter design. +# +# H(z) = H(s)| +# s = (2/T)(1-z^-1)/(1+z^-1) +# +# +# -w_cla +# 1 + ------ +# 2 fs +# 1 - ------------ z^-1 +# -w_cla -w_cla +# 1 - ------ 1 - ------ +# 2 fs 2 fs +# H(z) = ------------ * ----------------------- +# -w_cha -w_cha +# 1 - ------ 1 + ------ +# 2 fs 2 fs +# 1 - ------------ z^-1 +# -w_cha +# 1 - ------ +# 2 fs +# +# We use this design technique, because it is an easy way to obtain a filter +# design with the 6 dB/octave rise required of the premphasis filter. +# +# Jackson, Leland B., _Digital_Filters_and_Signal_Processing_Second_Edition_, +# Kluwer Academic Publishers, 1989, pp 201-212 +# +# Orfanidis, Sophocles J., _Introduction_to_Signal_Processing_, Prentice Hall, +# 1996, pp 573-583 # @@ -124,21 +251,52 @@ class fm_preemph(gr.hier_block2): """ FM Preemphasis IIR filter. """ - def __init__(self, fs, tau=75e-6): + def __init__(self, fs, tau=75e-6, fh=-1.0): """ Args: fs: sampling frequency in Hz (float) tau: Time constant in seconds (75us in US, 50us in EUR) (float) + fh: High frequency at which to flatten out (< 0 means default of 0.925*fs/2.0) (float) """ - gr.hier_block2.__init__(self, "fm_deemph", + gr.hier_block2.__init__(self, "fm_preemph", gr.io_signature(1, 1, gr.sizeof_float), # Input signature gr.io_signature(1, 1, gr.sizeof_float)) # Output signature - # FIXME make this compute the right answer + # Set fh to something sensible, if needed. + # N.B. fh == fs/2.0 or fh == 0.0 results in a pole on the unit circle + # at z = -1.0 or z = 1.0 respectively. That makes the filter unstable + # and useless. + if fh <= 0.0 or fh >= fs/2.0: + fh = 0.925 * fs/2.0 + + # Digital corner frequencies + w_cl = 1.0 / tau + w_ch = 2.0 * math.pi * fh + + # Prewarped analog corner frequencies + w_cla = 2.0 * fs * math.tan(w_cl / (2.0 * fs)) + w_cha = 2.0 * fs * math.tan(w_ch / (2.0 * fs)) + + # Resulting digital pole, zero, and gain term from the bilinear + # transformation of H(s) = (s + w_cla) / (s + w_cha) to + # H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1) + kl = -w_cla / (2.0 * fs) + kh = -w_cha / (2.0 * fs) + z1 = (1.0 + kl) / (1.0 - kl) + p1 = (1.0 + kh) / (1.0 - kh) + b0 = (1.0 - kl) / (1.0 - kh) + + # Since H(s = infinity) = 1.0, then H(z = -1) = 1.0 and + # this filter has 0 dB gain at fs/2.0. + # That isn't what users are going to expect, so adjust with a + # gain, g, so that H(z = 1) = 1.0 for 0 dB gain at DC. + w_0dB = 2.0 * math.pi * 0.0 + g = abs(1.0 - p1 * cmath.rect(1.0, -w_0dB)) \ + / (b0 * abs(1.0 - z1 * cmath.rect(1.0, -w_0dB))) - btaps = [1] - ataps = [1] + btaps = [ g * b0 * 1.0, g * b0 * -z1 ] + ataps = [ 1.0, -p1 ] if 0: print "btaps =", btaps @@ -146,5 +304,5 @@ class fm_preemph(gr.hier_block2): global plot2 plot2 = gru.gnuplot_freqz(gru.freqz(btaps, ataps), fs, True) - preemph = filter.iir_filter_ffd(btaps, ataps) + preemph = filter.iir_filter_ffd(btaps, ataps, False) self.connect(self, preemph, self) diff --git a/gr-analog/python/analog/nbfm_tx.py b/gr-analog/python/analog/nbfm_tx.py index ffd539ec55..aa6c1eccc7 100644 --- a/gr-analog/python/analog/nbfm_tx.py +++ b/gr-analog/python/analog/nbfm_tx.py @@ -29,7 +29,7 @@ except ImportError: import analog_swig as analog class nbfm_tx(gr.hier_block2): - def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=5e3): + def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=5e3, fh=-1.0): """ Narrow Band FM Transmitter. @@ -41,6 +41,7 @@ class nbfm_tx(gr.hier_block2): quad_rate: sample rate of output stream (integer) tau: preemphasis time constant (default 75e-6) (float) max_dev: maximum deviation in Hz (default 5e3) (float) + fh: high frequency at which to flatten preemphasis; < 0 means default of 0.925*quad_rate/2.0 (float) quad_rate must be an integer multiple of audio_rate. """ @@ -71,7 +72,7 @@ class nbfm_tx(gr.hier_block2): #print "len(interp_taps) =", len(interp_taps) self.interpolator = filter.interp_fir_filter_fff (interp_factor, interp_taps) - self.preemph = fm_preemph(quad_rate, tau=tau) + self.preemph = fm_preemph(quad_rate, tau=tau, fh=fh) k = 2 * math.pi * max_dev / quad_rate self.modulator = analog.frequency_modulator_fc(k) diff --git a/gr-analog/python/analog/wfm_tx.py b/gr-analog/python/analog/wfm_tx.py index be662310db..a1b589350d 100644 --- a/gr-analog/python/analog/wfm_tx.py +++ b/gr-analog/python/analog/wfm_tx.py @@ -30,7 +30,7 @@ except ImportError: import analog_swig as analog class wfm_tx(gr.hier_block2): - def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=75e3): + def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=75e3, fh=-1.0): """ Wide Band FM Transmitter. @@ -42,6 +42,7 @@ class wfm_tx(gr.hier_block2): quad_rate: sample rate of output stream (integer) tau: preemphasis time constant (default 75e-6) (float) max_dev: maximum deviation in Hz (default 75e3) (float) + fh: high frequency at which to flatten preemphasis; < 0 means default of 0.925*quad_rate/2.0 (float) quad_rate must be an integer multiple of audio_rate. """ @@ -71,7 +72,7 @@ class wfm_tx(gr.hier_block2): print "len(interp_taps) =", len(interp_taps) self.interpolator = filter.interp_fir_filter_fff (interp_factor, interp_taps) - self.preemph = fm_preemph(quad_rate, tau=tau) + self.preemph = fm_preemph(quad_rate, tau=tau, fh=fh) k = 2 * math.pi * max_dev / quad_rate self.modulator = analog.frequency_modulator_fc (k) diff --git a/gr-blocks/CMakeLists.txt b/gr-blocks/CMakeLists.txt index 13b41a2e3c..685f5736fb 100644 --- a/gr-blocks/CMakeLists.txt +++ b/gr-blocks/CMakeLists.txt @@ -87,6 +87,7 @@ add_subdirectory(lib) #endif(ENABLE_TESTING) if(ENABLE_PYTHON) add_subdirectory(python/blocks) + add_subdirectory(python/grc_gnuradio) add_subdirectory(swig) add_subdirectory(grc) add_subdirectory(doc) diff --git a/grc/blocks/blks2_error_rate.xml b/gr-blocks/grc/blks2_error_rate.xml index 91a303206d..8be018243f 100644 --- a/grc/blocks/blks2_error_rate.xml +++ b/gr-blocks/grc/blks2_error_rate.xml @@ -8,6 +8,7 @@ <block> <name>Error Rate</name> <key>blks2_error_rate</key> + <category>Deprecated</category> <import>from grc_gnuradio import blks2 as grc_blks2</import> <make>grc_blks2.error_rate( type=$type, diff --git a/grc/blocks/blks2_selector.xml b/gr-blocks/grc/blks2_selector.xml index 2d89df1860..580fdd9d8c 100644 --- a/grc/blocks/blks2_selector.xml +++ b/gr-blocks/grc/blks2_selector.xml @@ -8,6 +8,7 @@ <block> <name>Selector</name> <key>blks2_selector</key> + <category>Deprecated</category> <import>from grc_gnuradio import blks2 as grc_blks2</import> <make>grc_blks2.selector( item_size=$type.size*$vlen, diff --git a/grc/blocks/blks2_tcp_sink.xml b/gr-blocks/grc/blks2_tcp_sink.xml index cfe7b42d84..46b10a7790 100644 --- a/grc/blocks/blks2_tcp_sink.xml +++ b/gr-blocks/grc/blks2_tcp_sink.xml @@ -7,6 +7,7 @@ <block> <name>TCP Sink</name> <key>blks2_tcp_sink</key> + <category>Deprecated</category> <import>from grc_gnuradio import blks2 as grc_blks2</import> <make>grc_blks2.tcp_sink( itemsize=$type.size*$vlen, diff --git a/grc/blocks/blks2_tcp_source.xml b/gr-blocks/grc/blks2_tcp_source.xml index 6bf742aa00..6a59522f3f 100644 --- a/grc/blocks/blks2_tcp_source.xml +++ b/gr-blocks/grc/blks2_tcp_source.xml @@ -7,6 +7,7 @@ <block> <name>TCP Source</name> <key>blks2_tcp_source</key> + <category>Deprecated</category> <import>from grc_gnuradio import blks2 as grc_blks2</import> <make>grc_blks2.tcp_source( itemsize=$type.size*$vlen, diff --git a/grc/blocks/blks2_valve.xml b/gr-blocks/grc/blks2_valve.xml index 47c553523f..d879ff655f 100644 --- a/grc/blocks/blks2_valve.xml +++ b/gr-blocks/grc/blks2_valve.xml @@ -8,6 +8,7 @@ <block> <name>Valve</name> <key>blks2_valve</key> + <category>Deprecated</category> <import>from grc_gnuradio import blks2 as grc_blks2</import> <make>grc_blks2.valve(item_size=$type.size*$vlen, open=bool($open))</make> <callback>set_open(bool($open))</callback> diff --git a/gr-blocks/grc/blocks_block_tree.xml b/gr-blocks/grc/blocks_block_tree.xml index f35815b4dd..bfab41aeb6 100644 --- a/gr-blocks/grc/blocks_block_tree.xml +++ b/gr-blocks/grc/blocks_block_tree.xml @@ -29,7 +29,7 @@ <cat> <name></name> <!-- Blank for Root Name --> <cat> - <name>Audio</name> + <name>Audio</name> <block>blocks_wavfile_source</block> <block>blocks_wavfile_sink</block> </cat> @@ -230,4 +230,9 @@ <name>Variables</name> <block>variable_tag_object</block> </cat> + <cat> + <name>Misc</name> + <block>xmlrpc_server</block> + <block>xmlrpc_client</block> + </cat> </cat> diff --git a/gr-blocks/grc/blocks_repeat.xml b/gr-blocks/grc/blocks_repeat.xml index c6c17c9900..793d0148b2 100644 --- a/gr-blocks/grc/blocks_repeat.xml +++ b/gr-blocks/grc/blocks_repeat.xml @@ -9,6 +9,7 @@ <key>blocks_repeat</key> <import>from gnuradio import blocks</import> <make>blocks.repeat($type.size*$vlen, $interp)</make> + <callback>set_interpolation($interp)</callback> <param> <name>Type</name> <key>type</key> diff --git a/grc/blocks/xmlrpc_client.xml b/gr-blocks/grc/xmlrpc_client.xml index dc4d154d14..dc4d154d14 100644 --- a/grc/blocks/xmlrpc_client.xml +++ b/gr-blocks/grc/xmlrpc_client.xml diff --git a/grc/blocks/xmlrpc_server.xml b/gr-blocks/grc/xmlrpc_server.xml index 602d444161..602d444161 100644 --- a/grc/blocks/xmlrpc_server.xml +++ b/gr-blocks/grc/xmlrpc_server.xml diff --git a/gr-blocks/include/gnuradio/blocks/repeat.h b/gr-blocks/include/gnuradio/blocks/repeat.h index 622b066017..b34bda1ec5 100644 --- a/gr-blocks/include/gnuradio/blocks/repeat.h +++ b/gr-blocks/include/gnuradio/blocks/repeat.h @@ -32,6 +32,10 @@ namespace gr { /*! * \brief repeat each input \p repeat times * \ingroup stream_operators_blk + * + * Message Ports: + * * interpolation (in): + * Takes a pmt_pair(pmt::mp("interpolation"), pmt_long interp), setting the interpolation to interp. */ class BLOCKS_API repeat : virtual public sync_interpolator { @@ -46,6 +50,20 @@ namespace gr { * \param repeat number of times to repeat the input */ static sptr make(size_t itemsize, int repeat); + + /*! + * \brief Return current interpolation + */ + virtual int interpolation() const = 0; + + /*! + * \brief sets the interpolation + * + * Call this method in a callback to adjust the interpolation at run time. + * + * \param interp interpolation to be set + */ + virtual void set_interpolation(int interp) = 0; }; } /* namespace blocks */ diff --git a/gr-blocks/include/gnuradio/blocks/vector_sink_X.h.t b/gr-blocks/include/gnuradio/blocks/vector_sink_X.h.t index 527ebf7dff..a4ef38fd04 100644 --- a/gr-blocks/include/gnuradio/blocks/vector_sink_X.h.t +++ b/gr-blocks/include/gnuradio/blocks/vector_sink_X.h.t @@ -43,6 +43,7 @@ namespace gr { static sptr make(int vlen = 1); + //! Clear the data and tags containers. virtual void reset() = 0; virtual std::vector<@TYPE@> data() const = 0; virtual std::vector<tag_t> tags() const = 0; diff --git a/gr-blocks/include/gnuradio/blocks/vector_source_X.h.t b/gr-blocks/include/gnuradio/blocks/vector_source_X.h.t index d5298e8b47..b0ca6b869f 100644 --- a/gr-blocks/include/gnuradio/blocks/vector_source_X.h.t +++ b/gr-blocks/include/gnuradio/blocks/vector_source_X.h.t @@ -76,6 +76,7 @@ namespace gr { virtual void rewind() = 0; virtual void set_data(const std::vector<@TYPE@> &data, const std::vector<tag_t> &tags=std::vector<tag_t>()) = 0; + virtual void set_repeat(bool repeat) = 0; }; } /* namespace blocks */ diff --git a/gr-blocks/lib/repeat_impl.cc b/gr-blocks/lib/repeat_impl.cc index 9c2ccc63c8..fb62265134 100644 --- a/gr-blocks/lib/repeat_impl.cc +++ b/gr-blocks/lib/repeat_impl.cc @@ -43,6 +43,26 @@ namespace gr { d_itemsize(itemsize), d_interp(interp) { + message_port_register_in(pmt::mp("interpolation")); + set_msg_handler(pmt::mp("interpolation"), + boost::bind(&repeat_impl::msg_set_interpolation, this, _1)); + } + + void + repeat_impl::msg_set_interpolation(pmt::pmt_t msg) + { + // Dynamization by Kevin McQuiggin: + d_interp = pmt::to_long(pmt::cdr(msg)); + sync_interpolator::set_interpolation(d_interp); + } + void + repeat_impl::set_interpolation(int interp) + { + // This ensures that interpolation is only changed between calls to work + // (and not in the middle of an ongoing work) + _post( pmt::mp("interpolation"), /* port */ + pmt::cons(pmt::mp("interpolation"), pmt::from_long(interp)) /* pair */ + ); } int diff --git a/gr-blocks/lib/repeat_impl.h b/gr-blocks/lib/repeat_impl.h index 1942729194..486a47a1ad 100644 --- a/gr-blocks/lib/repeat_impl.h +++ b/gr-blocks/lib/repeat_impl.h @@ -36,9 +36,15 @@ namespace gr { public: repeat_impl(size_t itemsize, int d_interp); + int interpolation() const { return d_interp; } + void set_interpolation(int interp); + + int work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + private: + void msg_set_interpolation(pmt::pmt_t msg); }; } /* namespace blocks */ diff --git a/gr-blocks/lib/tuntap_pdu_impl.cc b/gr-blocks/lib/tuntap_pdu_impl.cc index 45995e4803..391b33937a 100644 --- a/gr-blocks/lib/tuntap_pdu_impl.cc +++ b/gr-blocks/lib/tuntap_pdu_impl.cc @@ -76,6 +76,14 @@ namespace gr { if (d_fd <= 0) throw std::runtime_error("gr::tuntap_pdu::make: tun_alloc failed (are you running as root?)"); + int err = set_mtu(dev_cstr, MTU); + if(err < 0) + std::cerr << boost::format( + "gr::tuntap_pdu: failed to set MTU to %d.\n" + "You should use ifconfig to set the MTU. E.g.,\n" + " $ sudo ifconfig %s mtu %d\n" + ) % MTU % dev % MTU << std::endl; + std::cout << boost::format( "Allocated virtual ethernet interface: %s\n" "You must now use ifconfig to set its IP address. E.g.,\n" @@ -140,6 +148,31 @@ namespace gr { */ return fd; } + + int + tuntap_pdu_impl::set_mtu(const char *dev, int MTU) + { + struct ifreq ifr; + int sfd, err; + + /* MTU must be set by passing a socket fd to ioctl; + * create an arbitrary socket for this purpose + */ + if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return sfd; + + /* preparation of the struct ifr, of type "struct ifreq" */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; /* address family */ + ifr.ifr_mtu = MTU; + + /* try to set MTU */ + if ((err = ioctl(sfd, SIOCSIFMTU, (void *) &ifr)) < 0) + return err; + + return MTU; + } #endif } /* namespace blocks */ diff --git a/gr-blocks/lib/tuntap_pdu_impl.h b/gr-blocks/lib/tuntap_pdu_impl.h index 360f954630..3a53e3acb5 100644 --- a/gr-blocks/lib/tuntap_pdu_impl.h +++ b/gr-blocks/lib/tuntap_pdu_impl.h @@ -40,6 +40,7 @@ namespace gr { std::string d_dev; bool d_istunflag; int tun_alloc(char *dev, int flags); + int set_mtu(const char *dev, int MTU); public: tuntap_pdu_impl(std::string dev, int MTU, bool istunflag); diff --git a/gr-blocks/lib/vector_sink_X_impl.h.t b/gr-blocks/lib/vector_sink_X_impl.h.t index b5d3bd6432..86f0e8773c 100644 --- a/gr-blocks/lib/vector_sink_X_impl.h.t +++ b/gr-blocks/lib/vector_sink_X_impl.h.t @@ -41,7 +41,7 @@ namespace gr { @NAME_IMPL@(int vlen); ~@NAME_IMPL@(); - void reset() { d_data.clear(); } + void reset() { d_data.clear(); d_tags.clear(); } std::vector<@TYPE@> data() const; std::vector<tag_t> tags() const; diff --git a/gr-blocks/lib/vector_source_X_impl.h.t b/gr-blocks/lib/vector_source_X_impl.h.t index 2641c6661b..bc9b329d8f 100644 --- a/gr-blocks/lib/vector_source_X_impl.h.t +++ b/gr-blocks/lib/vector_source_X_impl.h.t @@ -50,6 +50,7 @@ namespace gr { void rewind() { d_offset=0; } void set_data(const std::vector<@TYPE@> &data, const std::vector<tag_t> &tags); + void set_repeat(bool repeat) { d_repeat=repeat; }; int work(int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gr-blocks/python/blocks/qa_block_behavior.py b/gr-blocks/python/blocks/qa_block_behavior.py new file mode 100644 index 0000000000..a21e423b21 --- /dev/null +++ b/gr-blocks/python/blocks/qa_block_behavior.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# +# Copyright 2016 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. +# + +from gnuradio import gr, gr_unittest, blocks + +class test_block_behavior(gr_unittest.TestCase): + + def setUp(self): + self.tb = gr.top_block() + + def tearDown(self): + self.tb = None + + def test_000(self): + ''' + Tests the max noutput sizes set by the scheduler. When creating + the block, there is no block_detail and so the max buffer size + is 0. When the top_block is run, it builds the detail and + buffers and sets the max value. test_0001 tests when the + max_noutput_items is set by hand. + + ''' + + src = blocks.null_source(gr.sizeof_float) + op = blocks.head(gr.sizeof_float, 100) + snk = blocks.null_sink(gr.sizeof_float) + + maxn_pre = op.max_noutput_items() + + self.tb.connect(src, op, snk) + self.tb.run() + + maxn_post = op.max_noutput_items() + + self.assertEqual(maxn_pre, 0) + self.assertEqual(maxn_post, 16384) + + def test_001(self): + ''' + Tests the max noutput size when being explicitly set. + ''' + + src = blocks.null_source(gr.sizeof_float) + op = blocks.head(gr.sizeof_float, 100) + snk = blocks.null_sink(gr.sizeof_float) + + op.set_max_noutput_items(1024) + + maxn_pre = op.max_noutput_items() + + self.tb.connect(src, op, snk) + self.tb.run() + + maxn_post = op.max_noutput_items() + + self.assertEqual(maxn_pre, 1024) + self.assertEqual(maxn_post, 1024) + +if __name__ == '__main__': + gr_unittest.run(test_block_behavior, "test_block_behavior.xml") diff --git a/gr-blocks/python/blocks/qa_vector_sink_source.py b/gr-blocks/python/blocks/qa_vector_sink_source.py index 5dab7014cd..026713f5f4 100755 --- a/gr-blocks/python/blocks/qa_vector_sink_source.py +++ b/gr-blocks/python/blocks/qa_vector_sink_source.py @@ -46,6 +46,7 @@ class test_vector_sink_source(gr_unittest.TestCase): self.tb = None def test_001(self): + # Test that sink has data set in source for the simplest case src_data = [float(x) for x in range(16)] expected_result = tuple(src_data) @@ -58,6 +59,7 @@ class test_vector_sink_source(gr_unittest.TestCase): self.assertEqual(expected_result, result_data) def test_002(self): + # Test vectors (the gnuradio vector I/O type) src_data = [float(x) for x in range(16)] expected_result = tuple(src_data) @@ -70,11 +72,14 @@ class test_vector_sink_source(gr_unittest.TestCase): self.assertEqual(expected_result, result_data) def test_003(self): + # Test that we can only make vectors (the I/O type) if the input + # vector has sufficient size src_data = [float(x) for x in range(16)] expected_result = tuple(src_data) self.assertRaises(RuntimeError, lambda : blocks.vector_source_f(src_data, False, 3)) def test_004(self): + # Test sending and receiving tagged streams src_data = [float(x) for x in range(16)] expected_result = tuple(src_data) src_tags = tuple([make_tag('key', 'val', 0, 'src')]) @@ -92,6 +97,7 @@ class test_vector_sink_source(gr_unittest.TestCase): self.assertTrue(compare_tags(expected_tags[0], result_tags[0])) def test_005(self): + # Test that repeat works (with tagged streams) length = 16 src_data = [float(x) for x in range(length)] expected_result = tuple(src_data + src_data) @@ -112,6 +118,36 @@ class test_vector_sink_source(gr_unittest.TestCase): self.assertTrue(compare_tags(expected_tags[0], result_tags[0])) self.assertTrue(compare_tags(expected_tags[1], result_tags[1])) + def test_006(self): + # Test set_data + src_data = [float(x) for x in range(16)] + expected_result = tuple(src_data) + + src = blocks.vector_source_f((3,1,4)) + dst = blocks.vector_sink_f() + src.set_data(src_data) + + self.tb.connect(src, dst) + self.tb.run() + result_data = dst.data() + self.assertEqual(expected_result, result_data) + + def test_007(self): + # Test set_repeat + src_data = [float(x) for x in range(16)] + expected_result = tuple(src_data) + + src = blocks.vector_source_f(src_data, True) + dst = blocks.vector_sink_f() + src.set_repeat(False) + + self.tb.connect(src, dst) + # will timeout if set_repeat does not work + self.tb.run() + result_data = dst.data() + self.assertEqual(expected_result, result_data) + + if __name__ == '__main__': gr_unittest.run(test_vector_sink_source, "test_vector_sink_source.xml") diff --git a/grc/grc_gnuradio/CMakeLists.txt b/gr-blocks/python/grc_gnuradio/CMakeLists.txt index e992a60a39..9ff1240997 100644 --- a/grc/grc_gnuradio/CMakeLists.txt +++ b/gr-blocks/python/grc_gnuradio/CMakeLists.txt @@ -18,18 +18,20 @@ # Boston, MA 02110-1301, USA. ######################################################################## + +include(GrPython) + GR_PYTHON_INSTALL( FILES __init__.py DESTINATION ${GR_PYTHON_DIR}/grc_gnuradio - COMPONENT "grc" + COMPONENT "blocks_python" ) GR_PYTHON_INSTALL(FILES blks2/__init__.py blks2/error_rate.py - blks2/packet.py blks2/selector.py blks2/tcp.py DESTINATION ${GR_PYTHON_DIR}/grc_gnuradio/blks2 - COMPONENT "grc" + COMPONENT "blocks_python" ) diff --git a/grc/grc_gnuradio/README b/gr-blocks/python/grc_gnuradio/README index 897eed65ca..897eed65ca 100644 --- a/grc/grc_gnuradio/README +++ b/gr-blocks/python/grc_gnuradio/README diff --git a/grc/grc_gnuradio/__init__.py b/gr-blocks/python/grc_gnuradio/__init__.py index 8b13789179..8b13789179 100644 --- a/grc/grc_gnuradio/__init__.py +++ b/gr-blocks/python/grc_gnuradio/__init__.py diff --git a/grc/grc_gnuradio/blks2/__init__.py b/gr-blocks/python/grc_gnuradio/blks2/__init__.py index e6941ab91b..d3c8210834 100644 --- a/grc/grc_gnuradio/blks2/__init__.py +++ b/gr-blocks/python/grc_gnuradio/blks2/__init__.py @@ -19,8 +19,12 @@ # from selector import selector, valve -from packet import options, packet_encoder, packet_decoder, \ - packet_mod_b, packet_mod_s, packet_mod_i, packet_mod_f, packet_mod_c, \ - packet_demod_b, packet_demod_s, packet_demod_i, packet_demod_f, packet_demod_c from error_rate import error_rate from tcp import tcp_source, tcp_sink + +try: + from packet import options, packet_encoder, packet_decoder, \ + packet_mod_b, packet_mod_s, packet_mod_i, packet_mod_f, packet_mod_c, \ + packet_demod_b, packet_demod_s, packet_demod_i, packet_demod_f, packet_demod_c +except ImportError: + pass # only available if gr-digital is install diff --git a/grc/grc_gnuradio/blks2/error_rate.py b/gr-blocks/python/grc_gnuradio/blks2/error_rate.py index 9bf387030a..9bf387030a 100644 --- a/grc/grc_gnuradio/blks2/error_rate.py +++ b/gr-blocks/python/grc_gnuradio/blks2/error_rate.py diff --git a/grc/grc_gnuradio/blks2/selector.py b/gr-blocks/python/grc_gnuradio/blks2/selector.py index 24e3844658..24e3844658 100644 --- a/grc/grc_gnuradio/blks2/selector.py +++ b/gr-blocks/python/grc_gnuradio/blks2/selector.py diff --git a/grc/grc_gnuradio/blks2/tcp.py b/gr-blocks/python/grc_gnuradio/blks2/tcp.py index aee90fad2c..aee90fad2c 100644 --- a/grc/grc_gnuradio/blks2/tcp.py +++ b/gr-blocks/python/grc_gnuradio/blks2/tcp.py diff --git a/gr-digital/CMakeLists.txt b/gr-digital/CMakeLists.txt index 7a9f8f6c48..c6fa0798d1 100644 --- a/gr-digital/CMakeLists.txt +++ b/gr-digital/CMakeLists.txt @@ -97,6 +97,7 @@ add_subdirectory(doc) if(ENABLE_PYTHON) add_subdirectory(swig) add_subdirectory(python/digital) + add_subdirectory(python/grc_gnuradio) add_subdirectory(grc) add_subdirectory(examples) endif(ENABLE_PYTHON) diff --git a/grc/blocks/blks2_packet_decoder.xml b/gr-digital/grc/blks2_packet_decoder.xml index 07b0d1f2eb..c3672450ea 100644 --- a/grc/blocks/blks2_packet_decoder.xml +++ b/gr-digital/grc/blks2_packet_decoder.xml @@ -7,6 +7,7 @@ <block> <name>Packet Decoder</name> <key>blks2_packet_decoder</key> + <category>Deprecated</category> <import>from grc_gnuradio import blks2 as grc_blks2</import> <make>grc_blks2.packet_demod_$(type.fcn)(grc_blks2.packet_decoder( access_code=$access_code, diff --git a/grc/blocks/blks2_packet_encoder.xml b/gr-digital/grc/blks2_packet_encoder.xml index 88e1ba350c..92de9c9570 100644 --- a/grc/blocks/blks2_packet_encoder.xml +++ b/gr-digital/grc/blks2_packet_encoder.xml @@ -7,6 +7,7 @@ <block> <name>Packet Encoder</name> <key>blks2_packet_encoder</key> + <category>Deprecated</category> <import>from grc_gnuradio import blks2 as grc_blks2</import> <make>grc_blks2.packet_mod_$(type.fcn)(grc_blks2.packet_encoder( samples_per_symbol=$samples_per_symbol, diff --git a/gr-digital/grc/digital_constellation.xml b/gr-digital/grc/digital_constellation.xml index 5254e4d799..ef5364d248 100644 --- a/gr-digital/grc/digital_constellation.xml +++ b/gr-digital/grc/digital_constellation.xml @@ -9,7 +9,13 @@ <key>variable_constellation</key> <category>Modulators</category> <import>from gnuradio import digital</import> - <var_make>self.$(id) = $(id) = digital.constellation_calcdist($const_points, $sym_map, $rot_sym, $dims).base() + <var_make> +#if str($type) == "calcdist" +self.$(id) = $(id) = digital.constellation_calcdist($const_points, $sym_map, $rot_sym, $dims).base() +#else +self.$(id) = $(id) = digital.constellation_$(type)().base() +#end if + #if str($soft_dec_lut).lower() == '"auto"' or str($soft_dec_lut).lower() == "'auto'" self.$(id).gen_soft_dec_lut($precision) #else if str($soft_dec_lut) != 'None' @@ -17,16 +23,53 @@ self.$(id).set_soft_dec_lut($soft_dec_lut, $precision) #end if </var_make> - <var_value>digital.constellation_calcdist($const_points, $sym_map, $rot_sym, $dims)</var_value> +<var_value> +#if str($type) == "calcdist" +digital.constellation_calcdist($const_points, $sym_map, $rot_sym, $dims) +#else +digital.constellation_$(type)() +#end if +</var_value> <make></make> <!--<callback></callback>--> <param> + <name>Constellation Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Variable Constellation</name> + <key>calcdist</key> + </option> + <option> + <name>BPSK</name> + <key>bpsk</key> + </option> + <option> + <name>QPSK</name> + <key>qpsk</key> + </option> + <option> + <name>DQPSK</name> + <key>dqpsk</key> + </option> + <option> + <name>8PSK</name> + <key>8psk</key> + </option> + <option> + <name>16QAM</name> + <key>16qam</key> + </option> + + </param> + <param> <name>Symbol Map</name> <key>sym_map</key> <value>[0, 1, 3, 2]</value> <type>int_vector</type> + <hide> #if str($type) == "calcdist" then 'none' else 'all' #</hide> </param> <param> @@ -34,6 +77,7 @@ self.$(id).set_soft_dec_lut($soft_dec_lut, $precision) <key>const_points</key> <value>[-1-1j, -1+1j, 1+1j, 1-1j]</value> <type>complex_vector</type> + <hide> #if str($type) == "calcdist" then 'none' else 'all' #</hide> </param> <param> @@ -41,6 +85,7 @@ self.$(id).set_soft_dec_lut($soft_dec_lut, $precision) <key>rot_sym</key> <value>4</value> <type>int</type> + <hide> #if str($type) == "calcdist" then 'none' else 'all' #</hide> </param> <param> @@ -48,8 +93,8 @@ self.$(id).set_soft_dec_lut($soft_dec_lut, $precision) <key>dims</key> <value>1</value> <type>int</type> + <hide> #if str($type) == "calcdist" then 'none' else 'all' #</hide> </param> - <param> <name>Soft Decisions Precision</name> <key>precision</key> diff --git a/gr-digital/python/digital/qa_correlate_access_code_XX_ts.py b/gr-digital/python/digital/qa_correlate_access_code_XX_ts.py new file mode 100755 index 0000000000..5429ce1e07 --- /dev/null +++ b/gr-digital/python/digital/qa_correlate_access_code_XX_ts.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python +# +# Copyright 2006,2007,2010,2011,2013,2016 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. +# + +from gnuradio import gr, gr_unittest, digital, blocks +import pmt + +default_access_code = '\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC' + +def string_to_1_0_list(s): + r = [] + for ch in s: + x = ord(ch) + for i in range(8): + t = (x >> i) & 0x1 + r.append(t) + return r + +def to_1_0_string(L): + return ''.join(map(lambda x: chr(x + ord('0')), L)) + +class test_correlate_access_code_XX_ts(gr_unittest.TestCase): + + def setUp(self): + self.tb = gr.top_block() + + def tearDown(self): + self.tb = None + + def test_001(self): + payload = "test packet" # payload length is 11 bytes + header = "\x00\xd0\x00\xd0" # header contains packet length, twice (bit-swapped) + packet = header + payload + pad = (0,) * 64 + src_data = (0, 0, 1, 1, 1, 1, 0, 1, 1) + tuple(string_to_1_0_list(packet)) + pad + expected = tuple(map(long, src_data[9+32:-len(pad)])) + src = blocks.vector_source_b(src_data) + op = digital.correlate_access_code_bb_ts("1011", 0, "sync") + dst = blocks.vector_sink_b() + self.tb.connect(src, op, dst) + self.tb.run() + result_data = dst.data() + result_tags = dst.tags() + self.assertEqual(len(result_data), len(payload)*8) + self.assertEqual(result_tags[0].offset, 0) + self.assertEqual(pmt.to_long(result_tags[0].value), len(payload)*8) + self.assertEqual(result_data, expected) + + def test_002(self): + payload = "test packet" # payload length is 11 bytes + header = "\x00\xd0\x00\xd0" # header contains packet length, twice (bit-swapped) + packet = header + payload + pad = (0,) * 64 + src_data = (0, 0, 1, 1, 1, 1, 0, 1, 1) + tuple(string_to_1_0_list(packet)) + pad + src_floats = tuple(2*b-1 for b in src_data) # convert to binary antipodal symbols (-1,1) + expected = src_floats[9+32:-len(pad)] + src = blocks.vector_source_f(src_floats) + op = digital.correlate_access_code_ff_ts("1011", 0, "sync") + dst = blocks.vector_sink_f() + self.tb.connect(src, op, dst) + self.tb.run() + result_data = dst.data() + result_tags = dst.tags() + self.assertEqual(len(result_data), len(payload)*8) + self.assertEqual(result_tags[0].offset, 0) + self.assertEqual(pmt.to_long(result_tags[0].value), len(payload)*8) + self.assertFloatTuplesAlmostEqual(result_data, expected, 5) + + +if __name__ == '__main__': + gr_unittest.run(test_correlate_access_code_XX_ts, "test_correlate_access_code_XX_ts.xml") + diff --git a/grc/base/CMakeLists.txt b/gr-digital/python/grc_gnuradio/CMakeLists.txt index bdc8a5006f..f021299f1a 100644 --- a/grc/base/CMakeLists.txt +++ b/gr-digital/python/grc_gnuradio/CMakeLists.txt @@ -18,26 +18,13 @@ # Boston, MA 02110-1301, USA. ######################################################################## -GR_PYTHON_INSTALL(FILES - odict.py - ParseXML.py - Block.py - Connection.py - Constants.py - Element.py - FlowGraph.py - Param.py - Platform.py - Port.py - __init__.py - DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/base - COMPONENT "grc" -) -install(FILES - block_tree.dtd - domain.dtd - flow_graph.dtd - DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/base - COMPONENT "grc" +include(GrPython) + +# __init__ files come from gr-blocks + +GR_PYTHON_INSTALL(FILES + blks2/packet.py + DESTINATION ${GR_PYTHON_DIR}/grc_gnuradio/blks2 + COMPONENT "digital_python" ) diff --git a/grc/grc_gnuradio/blks2/packet.py b/gr-digital/python/grc_gnuradio/blks2/packet.py index ef79afde64..ef79afde64 100644 --- a/grc/grc_gnuradio/blks2/packet.py +++ b/gr-digital/python/grc_gnuradio/blks2/packet.py diff --git a/gr-dtv/CMakeLists.txt b/gr-dtv/CMakeLists.txt index fc7ab56bef..5a23482b26 100644 --- a/gr-dtv/CMakeLists.txt +++ b/gr-dtv/CMakeLists.txt @@ -41,6 +41,8 @@ GR_SET_GLOBAL(GR_DTV_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/lib ) +SET(GR_PKG_DTV_EXAMPLES_DIR ${GR_PKG_DATA_DIR}/examples/dtv) + ######################################################################## # Begin conditional configuration ######################################################################## diff --git a/gr-dtv/examples/CMakeLists.txt b/gr-dtv/examples/CMakeLists.txt index 82b663d924..8f209bce4f 100644 --- a/gr-dtv/examples/CMakeLists.txt +++ b/gr-dtv/examples/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2014 Free Software Foundation, Inc. +# Copyright 2014-2015 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -21,6 +21,31 @@ include(GrPython) GR_PYTHON_INSTALL( PROGRAMS + atsc_ctrlport_monitor.py + DESTINATION ${GR_PKG_DTV_EXAMPLES_DIR} + COMPONENT "dtv_python" +) + +install( + FILES + README.dvbs + README.dvbs2 + README.dvbt + README.dvbt2 + README.catv + dvbs2_tx.grc + dvbs_tx.grc + dvbt_rx_8k.grc + dvbt_tx_2k.grc + dvbt_tx_8k.grc + file_atsc_rx.grc + file_atsc_tx.grc + uhd_atsc_capture.grc + uhd_rx_atsc.grc + vv003-cr23.grc + vv009-4kfft.grc + vv018-miso.grc + catv_tx_64qam.grc DESTINATION ${GR_PKG_DTV_EXAMPLES_DIR} COMPONENT "dtv_python" ) diff --git a/gr-dtv/examples/README.catv b/gr-dtv/examples/README.catv new file mode 100644 index 0000000000..84c4cd0b26 --- /dev/null +++ b/gr-dtv/examples/README.catv @@ -0,0 +1,31 @@ +A test Transport Stream (26.970352 Mbps) for the example flow graph +is available here: + +http://www.w6rz.net/advqam64.ts + +It is 357,356,980 bytes. + +The three parameters Control_Word, I_taps and J_increment can be +used to control the interleaver from the following table. + +Control_Word I_taps J_increment Burst protection Latency + 0 128 1 95 us 4 ms + 1 128 1 95 us 4 ms + 2 128 2 190 us 8 ms + 3 64 2 47 us 2 ms + 4 128 3 285 us 12 ms + 5 32 4 24 us 0.98 ms + 6 128 4 379 us 16 ms + 7 16 8 12 us 0.48 ms + 8 128 5 474 us 20 ms + 9 8 16 5.9 us 0.22 ms + 10 128 6 569 us 24 ms + 11 Reserved + 12 128 7 664 us 28 ms + 13 Reserved + 14 128 8 759 us 32 ms + 15 Reserved + +The default is Control_Word = 6, I_taps = 128 and J_increment = 4 +which seems to be the most commonly used on CATV systems. + diff --git a/gr-dtv/examples/README.dvbs b/gr-dtv/examples/README.dvbs new file mode 100644 index 0000000000..d9097c4876 --- /dev/null +++ b/gr-dtv/examples/README.dvbs @@ -0,0 +1,26 @@ +Puncturing values for DVB-S code rates: + +1/2 code rate = Puncture Size = 2, Puncture Pattern = 0b11 +2/3 code rate = Puncture Size = 4, Puncture Pattern = 0b1101 +3/4 code rate = Puncture Size = 6, Puncture Pattern = 0b110110 +5/6 code rate = Puncture Size = 10, Puncture Pattern = 0b1101100110 +7/8 code rate = Puncture Size = 14, Puncture Pattern = 0b11010101100110 + +A test Transport Stream for the example flow graph +(8 Msyms/s and 7/8 code rate) is available here: + +http://www.w6rz.net/advdvbs78.ts + +It is 170,950,844 bytes. + +This stream can also be used at: + +14 Msyms/s 1/2 code rate +10.5 MSyms/s 2/3 code rate +9.333333 MSyms/s 3/4 code rate +8.4 Msyms/s 5/6 code rate + +The equation for calculating the correct Transport Stream bit-rate is: + +TS bit-rate = symbol rate * 2 * code rate * (188 / 204) + diff --git a/gr-dtv/examples/atsc_ctrlport_monitor.py b/gr-dtv/examples/atsc_ctrlport_monitor.py new file mode 100755 index 0000000000..7c43aebb77 --- /dev/null +++ b/gr-dtv/examples/atsc_ctrlport_monitor.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# +# Copyright 2015 Free Software Foundation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import sys +import matplotlib +matplotlib.use("QT4Agg") +import matplotlib.pyplot as plt +import matplotlib.animation as animation +from gnuradio.ctrlport.GNURadioControlPortClient import GNURadioControlPortClient +import scipy +from scipy import fftpack + +""" +If a host is running the ATSC receiver chain with ControlPort +turned on, this script will connect to the host using the hostname and +port pair of the ControlPort instance and display metrics of the +receiver. The ATSC publishes information about the succes of the +Reed-Solomon decoder and Viterbi metrics for use here in displaying +the link quality. This also gets the equalizer taps of the receiver +and displays the frequency response. +""" + +class atsc_ctrlport_monitor: + def __init__(self, host, port): + argv = [None, host, port] + radiosys = GNURadioControlPortClient(argv=argv, rpcmethod='thrift') + self.radio = radiosys.client + print self.radio + + + vt_init_key = 'dtv_atsc_viterbi_decoder0::decoder_metrics' + data = self.radio.getKnobs([vt_init_key])[vt_init_key] + init_metric = scipy.mean(data.value) + self._viterbi_metric = 100*[init_metric,] + + table_col_labels = ('Num Packets', 'Error Rate', 'Packet Error Rate', + 'Viterbi Metric', 'SNR') + + self._fig = plt.figure(1, figsize=(12,12), facecolor='w') + self._sp0 = self._fig.add_subplot(4,1,1) + self._sp1 = self._fig.add_subplot(4,1,2) + self._sp2 = self._fig.add_subplot(4,1,3) + self._plot_taps = self._sp0.plot([], [], 'k', linewidth=2) + self._plot_psd = self._sp1.plot([], [], 'k', linewidth=2) + self._plot_data = self._sp2.plot([], [], 'ok', linewidth=2, markersize=4, alpha=0.05) + + self._ax2 = self._fig.add_subplot(4,1,4) + self._table = self._ax2.table(cellText=[len(table_col_labels)*['0']], + colLabels=table_col_labels, + loc='center') + self._ax2.axis('off') + cells = self._table.properties()['child_artists'] + for c in cells: + c.set_lw(0.1) # set's line width + c.set_ls('solid') + c.set_height(0.2) + + ani = animation.FuncAnimation(self._fig, self.update_data, frames=200, + fargs=(self._plot_taps[0], self._plot_psd[0], + self._plot_data[0], self._table), + init_func=self.init_function, + blit=True) + plt.show() + + def update_data(self, x, taps, psd, syms, table): + try: + eqdata_key = 'dtv_atsc_equalizer0::taps' + symdata_key = 'dtv_atsc_equalizer0::data' + rs_nump_key = 'dtv_atsc_rs_decoder0::num_packets' + rs_numbp_key = 'dtv_atsc_rs_decoder0::num_bad_packets' + rs_numerrs_key = 'dtv_atsc_rs_decoder0::num_errors_corrected' + vt_metrics_key = 'dtv_atsc_viterbi_decoder0::decoder_metrics' + snr_key = 'probe2_f0::SNR' + + data = self.radio.getKnobs([]) + eqdata = data[eqdata_key] + symdata = data[symdata_key] + rs_num_packets = data[rs_nump_key] + rs_num_bad_packets = data[rs_numbp_key] + rs_num_errors_corrected = data[rs_numerrs_key] + vt_decoder_metrics = data[vt_metrics_key] + snr_est = data[snr_key] + + vt_decoder_metrics = scipy.mean(vt_decoder_metrics.value) + self._viterbi_metric.pop() + self._viterbi_metric.insert(0, vt_decoder_metrics) + + except: + sys.stderr.write("Lost connection, exiting") + sys.exit(1) + + ntaps = len(eqdata.value) + taps.set_ydata(eqdata.value) + taps.set_xdata(xrange(ntaps)) + self._sp0.set_xlim(0, ntaps) + self._sp0.set_ylim(min(eqdata.value), max(eqdata.value)) + + fs = 6.25e6 + freq = scipy.linspace(-fs/2, fs/2, 10000) + H = fftpack.fftshift(fftpack.fft(eqdata.value, 10000)) + HdB = 20.0*scipy.log10(abs(H)) + psd.set_ydata(HdB) + psd.set_xdata(freq) + self._sp1.set_xlim(0, fs/2) + self._sp1.set_ylim([min(HdB), max(HdB)]) + self._sp1.set_yticks([min(HdB), max(HdB)]) + self._sp1.set_yticklabels(["min", "max"]) + + nsyms = len(symdata.value) + syms.set_ydata(symdata.value) + syms.set_xdata(nsyms*[0,]) + self._sp2.set_xlim([-1, 1]) + self._sp2.set_ylim([-10, 10]) + + per = float(rs_num_bad_packets.value) / float(rs_num_packets.value) + ber = float(rs_num_errors_corrected.value) / float(187*rs_num_packets.value) + + table._cells[(1,0)]._text.set_text("{0}".format(rs_num_packets.value)) + table._cells[(1,1)]._text.set_text("{0:.2g}".format(ber)) + table._cells[(1,2)]._text.set_text("{0:.2g}".format(per)) + table._cells[(1,3)]._text.set_text("{0:.1f}".format(scipy.mean(self._viterbi_metric))) + table._cells[(1,4)]._text.set_text("{0:.4f}".format(snr_est.value[0])) + + return (taps, psd, syms, table) + + def init_function(self): + return self._plot_taps + self._plot_psd + self._plot_data + +if __name__ == "__main__": + host = sys.argv[1] + port = sys.argv[2] + m = atsc_ctrlport_monitor(host, port) diff --git a/gr-dtv/examples/catv_tx_64qam.grc b/gr-dtv/examples/catv_tx_64qam.grc new file mode 100644 index 0000000000..964ef8470f --- /dev/null +++ b/gr-dtv/examples/catv_tx_64qam.grc @@ -0,0 +1,2079 @@ +<?xml version='1.0' encoding='utf-8'?> +<?grc format='1' created='3.7.10'?> +<flow_graph> + <timestamp>Thu Feb 20 21:02:41 2014</timestamp> + <block> + <key>options</key> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>generate_options</key> + <value>wx_gui</value> + </param> + <param> + <key>hier_block_src_path</key> + <value>.:</value> + </param> + <param> + <key>id</key> + <value>catv_tx_64qam</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>qt_qss_theme</key> + <value></value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>run_command</key> + <value>{python} -u {filename}</value> + </param> + <param> + <key>run_options</key> + <value>prompt</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>thread_safe_setters</key> + <value></value> + </param> + <param> + <key>title</key> + <value></value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 299)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>Control_Word</value> + </param> + <param> + <key>value</key> + <value>6</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 371)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>I_taps</value> + </param> + <param> + <key>value</key> + <value>128</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 443)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>J_increment</value> + </param> + <param> + <key>value</key> + <value>4</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 155)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>center_freq</value> + </param> + <param> + <key>value</key> + <value>429000000</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 227)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>rrc_taps</value> + </param> + <param> + <key>value</key> + <value>100</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 83)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>value</key> + <value>5056941 * 2</value> + </param> + </block> + <block> + <key>variable_slider</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>converver</key> + <value>int_converter</value> + </param> + <param> + <key>value</key> + <value>-8</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(312, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>id</key> + <value>vga1_gain</value> + </param> + <param> + <key>label</key> + <value>VGA1 Gain</value> + </param> + <param> + <key>max</key> + <value>-4</value> + </param> + <param> + <key>min</key> + <value>-35</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>num_steps</key> + <value>31</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + </block> + <block> + <key>variable_slider</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>converver</key> + <value>int_converter</value> + </param> + <param> + <key>value</key> + <value>10</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(448, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>id</key> + <value>vga2_gain</value> + </param> + <param> + <key>label</key> + <value>VGA2 Gain</value> + </param> + <param> + <key>max</key> + <value>25</value> + </param> + <param> + <key>min</key> + <value>0</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>num_steps</key> + <value>25</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + </block> + <block> + <key>blocks_file_source</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>file</key> + <value>/run/shm/advqam64.ts</value> + </param> + <param> + <key>_coordinate</key> + <value>(128, 163)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>blocks_file_source_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>repeat</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + </block> + <block> + <key>blocks_packed_to_unpacked_xx</key> + <param> + <key>bits_per_chunk</key> + <value>7</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>endianness</key> + <value>gr.GR_MSB_FIRST</value> + </param> + <param> + <key>_coordinate</key> + <value>(624, 163)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>blocks_packed_to_unpacked_xx_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>num_ports</key> + <value>1</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + </block> + <block> + <key>blocks_stream_to_vector</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(536, 251)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + <param> + <key>id</key> + <value>blocks_stream_to_vector_0</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>num_items</key> + <value>I_taps</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + </block> + <block> + <key>dtv_catv_frame_sync_enc_bb</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>ctrlword</key> + <value>Control_Word</value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(584, 347)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>dtv_catv_frame_sync_enc_bb_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_catv_randomizer_bb</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(424, 353)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>dtv_catv_randomizer_bb_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_catv_reed_solomon_enc_bb</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(848, 177)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>dtv_catv_reed_solomon_enc_bb_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_catv_transport_framing_enc_bb</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(360, 177)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>dtv_catv_transport_framing_enc_bb_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_catv_trellis_enc_bb</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(800, 353)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>dtv_catv_trellis_enc_bb_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbs2_modulator_bc</key> + <param> + <key>interpolation</key> + <value>INTERPOLATION_ON</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>rate</key> + <value>C_OTHER</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>constellation</key> + <value>MOD_64QAM</value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>framesize</key> + <value>FECFRAME_NORMAL</value> + </param> + <param> + <key>_coordinate</key> + <value>(400, 499)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>dtv_dvbs2_modulator_bc_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_convolutional_interleaver</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>blocks</key> + <value>1</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>M</key> + <value>J_increment</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(168, 339)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>dtv_dvbt_convolutional_interleaver_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>I</key> + <value>I_taps</value> + </param> + </block> + <block> + <key>fft_filter_xxx</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>decim</key> + <value>1</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(712, 507)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>fft_filter_xxx_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>nthreads</key> + <value>1</value> + </param> + <param> + <key>samp_delay</key> + <value>0</value> + </param> + <param> + <key>taps</key> + <value>firdes.root_raised_cosine(0.14, samp_rate, samp_rate/2, 0.18, rrc_taps)</value> + </param> + <param> + <key>type</key> + <value>ccf</value> + </param> + </block> + <block> + <key>osmosdr_sink</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>ant0</key> + <value></value> + </param> + <param> + <key>bb_gain0</key> + <value>vga1_gain</value> + </param> + <param> + <key>bw0</key> + <value>6000000</value> + </param> + <param> + <key>corr0</key> + <value>0</value> + </param> + <param> + <key>freq0</key> + <value>center_freq</value> + </param> + <param> + <key>if_gain0</key> + <value>0</value> + </param> + <param> + <key>gain0</key> + <value>vga2_gain</value> + </param> + <param> + <key>ant10</key> + <value></value> + </param> + <param> + <key>bb_gain10</key> + <value>20</value> + </param> + <param> + <key>bw10</key> + <value>0</value> + </param> + <param> + <key>corr10</key> + <value>0</value> + </param> + <param> + <key>freq10</key> + <value>100e6</value> + </param> + <param> + <key>if_gain10</key> + <value>20</value> + </param> + <param> + <key>gain10</key> + <value>10</value> + </param> + <param> + <key>ant11</key> + <value></value> + </param> + <param> + <key>bb_gain11</key> + <value>20</value> + </param> + <param> + <key>bw11</key> + <value>0</value> + </param> + <param> + <key>corr11</key> + <value>0</value> + </param> + <param> + <key>freq11</key> + <value>100e6</value> + </param> + <param> + <key>if_gain11</key> + <value>20</value> + </param> + <param> + <key>gain11</key> + <value>10</value> + </param> + <param> + <key>ant12</key> + <value></value> + </param> + <param> + <key>bb_gain12</key> + <value>20</value> + </param> + <param> + <key>bw12</key> + <value>0</value> + </param> + <param> + <key>corr12</key> + <value>0</value> + </param> + <param> + <key>freq12</key> + <value>100e6</value> + </param> + <param> + <key>if_gain12</key> + <value>20</value> + </param> + <param> + <key>gain12</key> + <value>10</value> + </param> + <param> + <key>ant13</key> + <value></value> + </param> + <param> + <key>bb_gain13</key> + <value>20</value> + </param> + <param> + <key>bw13</key> + <value>0</value> + </param> + <param> + <key>corr13</key> + <value>0</value> + </param> + <param> + <key>freq13</key> + <value>100e6</value> + </param> + <param> + <key>if_gain13</key> + <value>20</value> + </param> + <param> + <key>gain13</key> + <value>10</value> + </param> + <param> + <key>ant14</key> + <value></value> + </param> + <param> + <key>bb_gain14</key> + <value>20</value> + </param> + <param> + <key>bw14</key> + <value>0</value> + </param> + <param> + <key>corr14</key> + <value>0</value> + </param> + <param> + <key>freq14</key> + <value>100e6</value> + </param> + <param> + <key>if_gain14</key> + <value>20</value> + </param> + <param> + <key>gain14</key> + <value>10</value> + </param> + <param> + <key>ant15</key> + <value></value> + </param> + <param> + <key>bb_gain15</key> + <value>20</value> + </param> + <param> + <key>bw15</key> + <value>0</value> + </param> + <param> + <key>corr15</key> + <value>0</value> + </param> + <param> + <key>freq15</key> + <value>100e6</value> + </param> + <param> + <key>if_gain15</key> + <value>20</value> + </param> + <param> + <key>gain15</key> + <value>10</value> + </param> + <param> + <key>ant16</key> + <value></value> + </param> + <param> + <key>bb_gain16</key> + <value>20</value> + </param> + <param> + <key>bw16</key> + <value>0</value> + </param> + <param> + <key>corr16</key> + <value>0</value> + </param> + <param> + <key>freq16</key> + <value>100e6</value> + </param> + <param> + <key>if_gain16</key> + <value>20</value> + </param> + <param> + <key>gain16</key> + <value>10</value> + </param> + <param> + <key>ant17</key> + <value></value> + </param> + <param> + <key>bb_gain17</key> + <value>20</value> + </param> + <param> + <key>bw17</key> + <value>0</value> + </param> + <param> + <key>corr17</key> + <value>0</value> + </param> + <param> + <key>freq17</key> + <value>100e6</value> + </param> + <param> + <key>if_gain17</key> + <value>20</value> + </param> + <param> + <key>gain17</key> + <value>10</value> + </param> + <param> + <key>ant18</key> + <value></value> + </param> + <param> + <key>bb_gain18</key> + <value>20</value> + </param> + <param> + <key>bw18</key> + <value>0</value> + </param> + <param> + <key>corr18</key> + <value>0</value> + </param> + <param> + <key>freq18</key> + <value>100e6</value> + </param> + <param> + <key>if_gain18</key> + <value>20</value> + </param> + <param> + <key>gain18</key> + <value>10</value> + </param> + <param> + <key>ant19</key> + <value></value> + </param> + <param> + <key>bb_gain19</key> + <value>20</value> + </param> + <param> + <key>bw19</key> + <value>0</value> + </param> + <param> + <key>corr19</key> + <value>0</value> + </param> + <param> + <key>freq19</key> + <value>100e6</value> + </param> + <param> + <key>if_gain19</key> + <value>20</value> + </param> + <param> + <key>gain19</key> + <value>10</value> + </param> + <param> + <key>ant1</key> + <value></value> + </param> + <param> + <key>bb_gain1</key> + <value>20</value> + </param> + <param> + <key>bw1</key> + <value>0</value> + </param> + <param> + <key>corr1</key> + <value>0</value> + </param> + <param> + <key>freq1</key> + <value>100e6</value> + </param> + <param> + <key>if_gain1</key> + <value>20</value> + </param> + <param> + <key>gain1</key> + <value>10</value> + </param> + <param> + <key>ant20</key> + <value></value> + </param> + <param> + <key>bb_gain20</key> + <value>20</value> + </param> + <param> + <key>bw20</key> + <value>0</value> + </param> + <param> + <key>corr20</key> + <value>0</value> + </param> + <param> + <key>freq20</key> + <value>100e6</value> + </param> + <param> + <key>if_gain20</key> + <value>20</value> + </param> + <param> + <key>gain20</key> + <value>10</value> + </param> + <param> + <key>ant21</key> + <value></value> + </param> + <param> + <key>bb_gain21</key> + <value>20</value> + </param> + <param> + <key>bw21</key> + <value>0</value> + </param> + <param> + <key>corr21</key> + <value>0</value> + </param> + <param> + <key>freq21</key> + <value>100e6</value> + </param> + <param> + <key>if_gain21</key> + <value>20</value> + </param> + <param> + <key>gain21</key> + <value>10</value> + </param> + <param> + <key>ant22</key> + <value></value> + </param> + <param> + <key>bb_gain22</key> + <value>20</value> + </param> + <param> + <key>bw22</key> + <value>0</value> + </param> + <param> + <key>corr22</key> + <value>0</value> + </param> + <param> + <key>freq22</key> + <value>100e6</value> + </param> + <param> + <key>if_gain22</key> + <value>20</value> + </param> + <param> + <key>gain22</key> + <value>10</value> + </param> + <param> + <key>ant23</key> + <value></value> + </param> + <param> + <key>bb_gain23</key> + <value>20</value> + </param> + <param> + <key>bw23</key> + <value>0</value> + </param> + <param> + <key>corr23</key> + <value>0</value> + </param> + <param> + <key>freq23</key> + <value>100e6</value> + </param> + <param> + <key>if_gain23</key> + <value>20</value> + </param> + <param> + <key>gain23</key> + <value>10</value> + </param> + <param> + <key>ant24</key> + <value></value> + </param> + <param> + <key>bb_gain24</key> + <value>20</value> + </param> + <param> + <key>bw24</key> + <value>0</value> + </param> + <param> + <key>corr24</key> + <value>0</value> + </param> + <param> + <key>freq24</key> + <value>100e6</value> + </param> + <param> + <key>if_gain24</key> + <value>20</value> + </param> + <param> + <key>gain24</key> + <value>10</value> + </param> + <param> + <key>ant25</key> + <value></value> + </param> + <param> + <key>bb_gain25</key> + <value>20</value> + </param> + <param> + <key>bw25</key> + <value>0</value> + </param> + <param> + <key>corr25</key> + <value>0</value> + </param> + <param> + <key>freq25</key> + <value>100e6</value> + </param> + <param> + <key>if_gain25</key> + <value>20</value> + </param> + <param> + <key>gain25</key> + <value>10</value> + </param> + <param> + <key>ant26</key> + <value></value> + </param> + <param> + <key>bb_gain26</key> + <value>20</value> + </param> + <param> + <key>bw26</key> + <value>0</value> + </param> + <param> + <key>corr26</key> + <value>0</value> + </param> + <param> + <key>freq26</key> + <value>100e6</value> + </param> + <param> + <key>if_gain26</key> + <value>20</value> + </param> + <param> + <key>gain26</key> + <value>10</value> + </param> + <param> + <key>ant27</key> + <value></value> + </param> + <param> + <key>bb_gain27</key> + <value>20</value> + </param> + <param> + <key>bw27</key> + <value>0</value> + </param> + <param> + <key>corr27</key> + <value>0</value> + </param> + <param> + <key>freq27</key> + <value>100e6</value> + </param> + <param> + <key>if_gain27</key> + <value>20</value> + </param> + <param> + <key>gain27</key> + <value>10</value> + </param> + <param> + <key>ant28</key> + <value></value> + </param> + <param> + <key>bb_gain28</key> + <value>20</value> + </param> + <param> + <key>bw28</key> + <value>0</value> + </param> + <param> + <key>corr28</key> + <value>0</value> + </param> + <param> + <key>freq28</key> + <value>100e6</value> + </param> + <param> + <key>if_gain28</key> + <value>20</value> + </param> + <param> + <key>gain28</key> + <value>10</value> + </param> + <param> + <key>ant29</key> + <value></value> + </param> + <param> + <key>bb_gain29</key> + <value>20</value> + </param> + <param> + <key>bw29</key> + <value>0</value> + </param> + <param> + <key>corr29</key> + <value>0</value> + </param> + <param> + <key>freq29</key> + <value>100e6</value> + </param> + <param> + <key>if_gain29</key> + <value>20</value> + </param> + <param> + <key>gain29</key> + <value>10</value> + </param> + <param> + <key>ant2</key> + <value></value> + </param> + <param> + <key>bb_gain2</key> + <value>20</value> + </param> + <param> + <key>bw2</key> + <value>0</value> + </param> + <param> + <key>corr2</key> + <value>0</value> + </param> + <param> + <key>freq2</key> + <value>100e6</value> + </param> + <param> + <key>if_gain2</key> + <value>20</value> + </param> + <param> + <key>gain2</key> + <value>10</value> + </param> + <param> + <key>ant30</key> + <value></value> + </param> + <param> + <key>bb_gain30</key> + <value>20</value> + </param> + <param> + <key>bw30</key> + <value>0</value> + </param> + <param> + <key>corr30</key> + <value>0</value> + </param> + <param> + <key>freq30</key> + <value>100e6</value> + </param> + <param> + <key>if_gain30</key> + <value>20</value> + </param> + <param> + <key>gain30</key> + <value>10</value> + </param> + <param> + <key>ant31</key> + <value></value> + </param> + <param> + <key>bb_gain31</key> + <value>20</value> + </param> + <param> + <key>bw31</key> + <value>0</value> + </param> + <param> + <key>corr31</key> + <value>0</value> + </param> + <param> + <key>freq31</key> + <value>100e6</value> + </param> + <param> + <key>if_gain31</key> + <value>20</value> + </param> + <param> + <key>gain31</key> + <value>10</value> + </param> + <param> + <key>ant3</key> + <value></value> + </param> + <param> + <key>bb_gain3</key> + <value>20</value> + </param> + <param> + <key>bw3</key> + <value>0</value> + </param> + <param> + <key>corr3</key> + <value>0</value> + </param> + <param> + <key>freq3</key> + <value>100e6</value> + </param> + <param> + <key>if_gain3</key> + <value>20</value> + </param> + <param> + <key>gain3</key> + <value>10</value> + </param> + <param> + <key>ant4</key> + <value></value> + </param> + <param> + <key>bb_gain4</key> + <value>20</value> + </param> + <param> + <key>bw4</key> + <value>0</value> + </param> + <param> + <key>corr4</key> + <value>0</value> + </param> + <param> + <key>freq4</key> + <value>100e6</value> + </param> + <param> + <key>if_gain4</key> + <value>20</value> + </param> + <param> + <key>gain4</key> + <value>10</value> + </param> + <param> + <key>ant5</key> + <value></value> + </param> + <param> + <key>bb_gain5</key> + <value>20</value> + </param> + <param> + <key>bw5</key> + <value>0</value> + </param> + <param> + <key>corr5</key> + <value>0</value> + </param> + <param> + <key>freq5</key> + <value>100e6</value> + </param> + <param> + <key>if_gain5</key> + <value>20</value> + </param> + <param> + <key>gain5</key> + <value>10</value> + </param> + <param> + <key>ant6</key> + <value></value> + </param> + <param> + <key>bb_gain6</key> + <value>20</value> + </param> + <param> + <key>bw6</key> + <value>0</value> + </param> + <param> + <key>corr6</key> + <value>0</value> + </param> + <param> + <key>freq6</key> + <value>100e6</value> + </param> + <param> + <key>if_gain6</key> + <value>20</value> + </param> + <param> + <key>gain6</key> + <value>10</value> + </param> + <param> + <key>ant7</key> + <value></value> + </param> + <param> + <key>bb_gain7</key> + <value>20</value> + </param> + <param> + <key>bw7</key> + <value>0</value> + </param> + <param> + <key>corr7</key> + <value>0</value> + </param> + <param> + <key>freq7</key> + <value>100e6</value> + </param> + <param> + <key>if_gain7</key> + <value>20</value> + </param> + <param> + <key>gain7</key> + <value>10</value> + </param> + <param> + <key>ant8</key> + <value></value> + </param> + <param> + <key>bb_gain8</key> + <value>20</value> + </param> + <param> + <key>bw8</key> + <value>0</value> + </param> + <param> + <key>corr8</key> + <value>0</value> + </param> + <param> + <key>freq8</key> + <value>100e6</value> + </param> + <param> + <key>if_gain8</key> + <value>20</value> + </param> + <param> + <key>gain8</key> + <value>10</value> + </param> + <param> + <key>ant9</key> + <value></value> + </param> + <param> + <key>bb_gain9</key> + <value>20</value> + </param> + <param> + <key>bw9</key> + <value>0</value> + </param> + <param> + <key>corr9</key> + <value>0</value> + </param> + <param> + <key>freq9</key> + <value>100e6</value> + </param> + <param> + <key>if_gain9</key> + <value>20</value> + </param> + <param> + <key>gain9</key> + <value>10</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>args</key> + <value>bladerf=0,buffers=128,buflen=32768</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(1056, 467)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>osmosdr_sink_0</value> + </param> + <param> + <key>type</key> + <value>fc32</value> + </param> + <param> + <key>clock_source0</key> + <value></value> + </param> + <param> + <key>time_source0</key> + <value></value> + </param> + <param> + <key>clock_source1</key> + <value></value> + </param> + <param> + <key>time_source1</key> + <value></value> + </param> + <param> + <key>clock_source2</key> + <value></value> + </param> + <param> + <key>time_source2</key> + <value></value> + </param> + <param> + <key>clock_source3</key> + <value></value> + </param> + <param> + <key>time_source3</key> + <value></value> + </param> + <param> + <key>clock_source4</key> + <value></value> + </param> + <param> + <key>time_source4</key> + <value></value> + </param> + <param> + <key>clock_source5</key> + <value></value> + </param> + <param> + <key>time_source5</key> + <value></value> + </param> + <param> + <key>clock_source6</key> + <value></value> + </param> + <param> + <key>time_source6</key> + <value></value> + </param> + <param> + <key>clock_source7</key> + <value></value> + </param> + <param> + <key>time_source7</key> + <value></value> + </param> + <param> + <key>nchan</key> + <value>1</value> + </param> + <param> + <key>num_mboards</key> + <value>1</value> + </param> + <param> + <key>sample_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>sync</key> + <value></value> + </param> + </block> + <block> + <key>wxgui_fftsink2</key> + <param> + <key>avg_alpha</key> + <value>0.1333</value> + </param> + <param> + <key>average</key> + <value>True</value> + </param> + <param> + <key>baseband_freq</key> + <value>center_freq</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>fft_size</key> + <value>1024</value> + </param> + <param> + <key>freqvar</key> + <value>None</value> + </param> + <param> + <key>_coordinate</key> + <value>(1056, 203)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>id</key> + <value>wxgui_fftsink2_0_0</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>peak_hold</key> + <value>False</value> + </param> + <param> + <key>ref_level</key> + <value>-10</value> + </param> + <param> + <key>ref_scale</key> + <value>2.0</value> + </param> + <param> + <key>fft_rate</key> + <value>15</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>title</key> + <value>FFT Plot</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>win_size</key> + <value>640,480</value> + </param> + <param> + <key>win</key> + <value>None</value> + </param> + <param> + <key>y_divs</key> + <value>10</value> + </param> + <param> + <key>y_per_div</key> + <value>10</value> + </param> + </block> + <connection> + <source_block_id>blocks_file_source_0</source_block_id> + <sink_block_id>dtv_catv_transport_framing_enc_bb_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_packed_to_unpacked_xx_0</source_block_id> + <sink_block_id>dtv_catv_reed_solomon_enc_bb_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_stream_to_vector_0</source_block_id> + <sink_block_id>dtv_dvbt_convolutional_interleaver_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_catv_frame_sync_enc_bb_0</source_block_id> + <sink_block_id>dtv_catv_trellis_enc_bb_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_catv_randomizer_bb_0</source_block_id> + <sink_block_id>dtv_catv_frame_sync_enc_bb_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_catv_reed_solomon_enc_bb_0</source_block_id> + <sink_block_id>blocks_stream_to_vector_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_catv_transport_framing_enc_bb_0</source_block_id> + <sink_block_id>blocks_packed_to_unpacked_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_catv_trellis_enc_bb_0</source_block_id> + <sink_block_id>dtv_dvbs2_modulator_bc_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbs2_modulator_bc_0</source_block_id> + <sink_block_id>fft_filter_xxx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_convolutional_interleaver_0</source_block_id> + <sink_block_id>dtv_catv_randomizer_bb_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>fft_filter_xxx_0</source_block_id> + <sink_block_id>osmosdr_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>fft_filter_xxx_0</source_block_id> + <sink_block_id>wxgui_fftsink2_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/gr-dtv/examples/dvbs2_tx.grc b/gr-dtv/examples/dvbs2_tx.grc index 47daa4cb9d..c6de308ae3 100644 --- a/gr-dtv/examples/dvbs2_tx.grc +++ b/gr-dtv/examples/dvbs2_tx.grc @@ -1,23 +1,23 @@ -<?xml version='1.0' encoding='ASCII'?> -<?grc format='1' created='3.7.7'?> +<?xml version='1.0' encoding='utf-8'?> +<?grc format='1' created='3.7.10'?> <flow_graph> <timestamp>Wed Sep 3 03:03:39 2014</timestamp> <block> <key>options</key> <param> - <key>id</key> - <value>dvbs2_tx</value> + <key>author</key> + <value></value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>window_size</key> + <value>1280, 1024</value> </param> <param> - <key>title</key> - <value></value> + <key>category</key> + <value>Custom</value> </param> <param> - <key>author</key> + <key>comment</key> <value></value> </param> <param> @@ -25,16 +25,44 @@ <value></value> </param> <param> - <key>window_size</key> - <value>1280, 1024</value> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> </param> <param> <key>generate_options</key> <value>wx_gui</value> </param> <param> - <key>category</key> - <value>Custom</value> + <key>hier_block_src_path</key> + <value>.:</value> + </param> + <param> + <key>id</key> + <value>dvbs2_tx</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>qt_qss_theme</key> + <value></value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>run_command</key> + <value>{python} -u {filename}</value> </param> <param> <key>run_options</key> @@ -45,45 +73,79 @@ <value>True</value> </param> <param> - <key>max_nouts</key> - <value>0</value> + <key>thread_safe_setters</key> + <value></value> </param> <param> - <key>realtime_scheduling</key> + <key>title</key> <value></value> </param> + </block> + <block> + <key>variable</key> <param> - <key>alias</key> + <key>comment</key> <value></value> </param> <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> <key>_coordinate</key> - <value>(8, 11)</value> + <value>(8, 203)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> + <param> + <key>id</key> + <value>frequency</value> + </param> + <param> + <key>value</key> + <value>1280e6</value> + </param> </block> <block> <key>variable</key> <param> - <key>id</key> - <value>samp_rate</value> + <key>comment</key> + <value></value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> + <key>_coordinate</key> + <value>(8, 267)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>rolloff</value> + </param> + <param> <key>value</key> - <value>symbol_rate * 2</value> + <value>0.2</value> </param> + </block> + <block> + <key>variable</key> <param> - <key>alias</key> + <key>comment</key> <value></value> </param> <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> <key>_coordinate</key> <value>(8, 75)</value> </param> @@ -91,107 +153,186 @@ <key>_rotation</key> <value>0</value> </param> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>value</key> + <value>symbol_rate * 2</value> + </param> </block> <block> <key>variable</key> <param> - <key>id</key> - <value>symbol_rate</value> + <key>comment</key> + <value></value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> + <key>_coordinate</key> + <value>(8, 139)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>symbol_rate</value> + </param> + <param> <key>value</key> <value>5000000</value> </param> + </block> + <block> + <key>variable</key> <param> - <key>alias</key> + <key>comment</key> <value></value> </param> <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> <key>_coordinate</key> - <value>(8, 139)</value> + <value>(8, 331)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> - </block> - <block> - <key>variable</key> <param> <key>id</key> - <value>rolloff</value> + <value>taps</value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>value</key> + <value>100</value> </param> + </block> + <block> + <key>blocks_file_sink</key> <param> - <key>value</key> - <value>0.2</value> + <key>append</key> + <value>False</value> </param> <param> <key>alias</key> <value></value> </param> <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>file</key> + <value>adv.cfile</value> + </param> + <param> <key>_coordinate</key> - <value>(8, 203)</value> + <value>(784, 547)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> - </block> - <block> - <key>variable</key> <param> <key>id</key> - <value>taps</value> + <value>blocks_file_sink_0</value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>type</key> + <value>complex</value> </param> <param> - <key>value</key> - <value>50</value> + <key>unbuffered</key> + <value>False</value> </param> <param> + <key>vlen</key> + <value>1</value> + </param> + </block> + <block> + <key>blocks_file_source</key> + <param> <key>alias</key> <value></value> </param> <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>file</key> + <value>/run/shm/adv16apsk910.ts</value> + </param> + <param> <key>_coordinate</key> - <value>(8, 267)</value> + <value>(176, 43)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> - </block> - <block> - <key>dtv_dvb_bch_bb</key> <param> <key>id</key> - <value>dtv_dvb_bch_bb_0</value> + <value>blocks_file_source_0</value> </param> <param> - <key>_enabled</key> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>repeat</key> <value>True</value> </param> <param> - <key>standard</key> - <value>STANDARD_DVBS2</value> + <key>vlen</key> + <value>1</value> </param> + </block> + <block> + <key>dtv_dvb_bbheader_bb</key> <param> - <key>framesize</key> + <key>mode</key> <value>FECFRAME_NORMAL</value> </param> <param> + <key>alias</key> + <value></value> + </param> + <param> <key>rate1</key> <value>C1_2</value> </param> @@ -208,7 +349,7 @@ <value>C1_4</value> </param> <param> - <key>alias</key> + <key>comment</key> <value></value> </param> <param> @@ -216,39 +357,59 @@ <value></value> </param> <param> - <key>minoutbuf</key> - <value>0</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>maxoutbuf</key> - <value>0</value> + <key>fecblocks</key> + <value>168</value> + </param> + <param> + <key>framesize</key> + <value>FECFRAME_NORMAL</value> </param> <param> <key>_coordinate</key> - <value>(824, 35)</value> + <value>(400, 27)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> - </block> - <block> - <key>dtv_dvb_bbscrambler_bb</key> <param> <key>id</key> - <value>dtv_dvb_bbscrambler_bb_0</value> + <value>dtv_dvb_bbheader_bb_0</value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>inband</key> + <value>INBAND_OFF</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>rolloff</key> + <value>RO_0_20</value> </param> <param> <key>standard</key> <value>STANDARD_DVBS2</value> </param> <param> - <key>framesize</key> - <value>FECFRAME_NORMAL</value> + <key>tsrate</key> + <value>4000000</value> + </param> + </block> + <block> + <key>dtv_dvb_bbscrambler_bb</key> + <param> + <key>alias</key> + <value></value> </param> <param> <key>rate1</key> @@ -267,7 +428,7 @@ <value>C1_4</value> </param> <param> - <key>alias</key> + <key>comment</key> <value></value> </param> <param> @@ -275,12 +436,12 @@ <value></value> </param> <param> - <key>minoutbuf</key> - <value>0</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>maxoutbuf</key> - <value>0</value> + <key>framesize</key> + <value>FECFRAME_NORMAL</value> </param> <param> <key>_coordinate</key> @@ -290,24 +451,28 @@ <key>_rotation</key> <value>0</value> </param> - </block> - <block> - <key>dtv_dvb_ldpc_bb</key> <param> <key>id</key> - <value>dtv_dvb_ldpc_bb_0</value> + <value>dtv_dvb_bbscrambler_bb_0</value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> </param> <param> <key>standard</key> <value>STANDARD_DVBS2</value> </param> + </block> + <block> + <key>dtv_dvb_bch_bb</key> <param> - <key>framesize</key> - <value>FECFRAME_NORMAL</value> + <key>alias</key> + <value></value> </param> <param> <key>rate1</key> @@ -326,11 +491,7 @@ <value>C1_4</value> </param> <param> - <key>constellation</key> - <value>MOD_OTHER</value> - </param> - <param> - <key>alias</key> + <key>comment</key> <value></value> </param> <param> @@ -338,239 +499,310 @@ <value></value> </param> <param> - <key>minoutbuf</key> - <value>0</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>maxoutbuf</key> - <value>0</value> + <key>framesize</key> + <value>FECFRAME_NORMAL</value> </param> <param> <key>_coordinate</key> - <value>(1048, 27)</value> + <value>(824, 35)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> + <param> + <key>id</key> + <value>dtv_dvb_bch_bb_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>standard</key> + <value>STANDARD_DVBS2</value> + </param> </block> <block> - <key>dtv_dvbs2_interleaver_bb</key> + <key>dtv_dvb_ldpc_bb</key> <param> - <key>id</key> - <value>dtv_dvbs2_interleaver_bb_0</value> + <key>alias</key> + <value></value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>rate1</key> + <value>C1_2</value> </param> <param> - <key>framesize</key> - <value>FECFRAME_NORMAL</value> + <key>rate2</key> + <value>C1_3</value> </param> <param> - <key>constellation</key> - <value>MOD_16APSK</value> + <key>rate3</key> + <value>C9_10</value> </param> <param> - <key>rate</key> - <value>C_OTHER</value> + <key>rate4</key> + <value>C1_4</value> </param> <param> - <key>alias</key> + <key>comment</key> <value></value> </param> <param> + <key>constellation</key> + <value>MOD_OTHER</value> + </param> + <param> <key>affinity</key> <value></value> </param> <param> - <key>minoutbuf</key> - <value>0</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>maxoutbuf</key> - <value>0</value> + <key>framesize</key> + <value>FECFRAME_NORMAL</value> </param> <param> <key>_coordinate</key> - <value>(192, 235)</value> + <value>(1048, 27)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> - </block> - <block> - <key>wxgui_fftsink2</key> <param> <key>id</key> - <value>wxgui_fftsink2_0</value> + <value>dtv_dvb_ldpc_bb_0</value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>maxoutbuf</key> + <value>0</value> </param> <param> - <key>type</key> - <value>complex</value> + <key>minoutbuf</key> + <value>0</value> </param> <param> - <key>title</key> - <value>FFT Plot</value> + <key>standard</key> + <value>STANDARD_DVBS2</value> </param> + </block> + <block> + <key>dtv_dvbs2_interleaver_bb</key> <param> - <key>samp_rate</key> - <value>samp_rate</value> + <key>alias</key> + <value></value> </param> <param> - <key>baseband_freq</key> - <value>1280000000</value> + <key>rate</key> + <value>C_OTHER</value> </param> <param> - <key>y_per_div</key> - <value>10</value> + <key>comment</key> + <value></value> </param> <param> - <key>y_divs</key> - <value>10</value> + <key>constellation</key> + <value>MOD_16APSK</value> </param> <param> - <key>ref_level</key> - <value>0</value> + <key>affinity</key> + <value></value> </param> <param> - <key>ref_scale</key> - <value>2.0</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>fft_size</key> - <value>1024</value> + <key>framesize</key> + <value>FECFRAME_NORMAL</value> </param> <param> - <key>fft_rate</key> - <value>15</value> + <key>_coordinate</key> + <value>(192, 235)</value> </param> <param> - <key>peak_hold</key> - <value>False</value> + <key>_rotation</key> + <value>0</value> </param> <param> - <key>average</key> - <value>True</value> + <key>id</key> + <value>dtv_dvbs2_interleaver_bb_0</value> </param> <param> - <key>avg_alpha</key> - <value>0.13333</value> + <key>maxoutbuf</key> + <value>0</value> </param> <param> - <key>win</key> - <value>None</value> + <key>minoutbuf</key> + <value>0</value> </param> + </block> + <block> + <key>dtv_dvbs2_modulator_bc</key> <param> - <key>win_size</key> - <value></value> + <key>interpolation</key> + <value>INTERPOLATION_OFF</value> </param> <param> - <key>grid_pos</key> + <key>alias</key> <value></value> </param> <param> - <key>notebook</key> - <value></value> + <key>rate</key> + <value>C9_10</value> </param> <param> - <key>freqvar</key> - <value>None</value> + <key>comment</key> + <value></value> </param> <param> - <key>alias</key> - <value></value> + <key>constellation</key> + <value>MOD_16APSK</value> </param> <param> <key>affinity</key> <value></value> </param> <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>framesize</key> + <value>FECFRAME_NORMAL</value> + </param> + <param> <key>_coordinate</key> - <value>(1000, 395)</value> + <value>(472, 227)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> - </block> - <block> - <key>dtv_dvbs2_modulator_bc</key> <param> <key>id</key> <value>dtv_dvbs2_modulator_bc_0</value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>maxoutbuf</key> + <value>0</value> </param> <param> - <key>framesize</key> - <value>FECFRAME_NORMAL</value> + <key>minoutbuf</key> + <value>0</value> </param> + </block> + <block> + <key>dtv_dvbs2_physical_cc</key> <param> - <key>constellation</key> - <value>MOD_16APSK</value> + <key>alias</key> + <value></value> </param> <param> <key>rate</key> <value>C9_10</value> </param> <param> - <key>alias</key> + <key>comment</key> <value></value> </param> <param> + <key>constellation</key> + <value>MOD_16APSK</value> + </param> + <param> <key>affinity</key> <value></value> </param> <param> - <key>minoutbuf</key> - <value>0</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>maxoutbuf</key> - <value>0</value> + <key>framesize</key> + <value>FECFRAME_NORMAL</value> </param> <param> <key>_coordinate</key> - <value>(472, 235)</value> + <value>(192, 443)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> + <param> + <key>goldcode</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>dtv_dvbs2_physical_cc_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>pilots</key> + <value>PILOTS_ON</value> + </param> </block> <block> <key>fft_filter_xxx</key> <param> - <key>id</key> - <value>fft_filter_xxx_0</value> + <key>alias</key> + <value></value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>comment</key> + <value></value> </param> <param> - <key>type</key> - <value>ccc</value> + <key>affinity</key> + <value></value> </param> <param> <key>decim</key> <value>1</value> </param> <param> - <key>taps</key> - <value>firdes.root_raised_cosine(1, samp_rate, samp_rate/2, rolloff, taps)</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>samp_delay</key> + <key>_coordinate</key> + <value>(472, 459)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>fft_filter_xxx_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> <value>0</value> </param> <param> @@ -578,1014 +810,1458 @@ <value>1</value> </param> <param> + <key>samp_delay</key> + <value>0</value> + </param> + <param> + <key>taps</key> + <value>firdes.root_raised_cosine(1.0, samp_rate, samp_rate/2, rolloff, taps)</value> + </param> + <param> + <key>type</key> + <value>ccc</value> + </param> + </block> + <block> + <key>osmosdr_sink</key> + <param> <key>alias</key> <value></value> </param> <param> - <key>affinity</key> + <key>ant0</key> <value></value> </param> <param> - <key>minoutbuf</key> + <key>bb_gain0</key> + <value>-10</value> + </param> + <param> + <key>bw0</key> + <value>6000000</value> + </param> + <param> + <key>corr0</key> <value>0</value> </param> <param> - <key>maxoutbuf</key> + <key>freq0</key> + <value>frequency</value> + </param> + <param> + <key>if_gain0</key> <value>0</value> </param> <param> - <key>_coordinate</key> - <value>(472, 459)</value> + <key>gain0</key> + <value>15</value> </param> <param> - <key>_rotation</key> + <key>ant10</key> + <value></value> + </param> + <param> + <key>bb_gain10</key> + <value>20</value> + </param> + <param> + <key>bw10</key> <value>0</value> </param> - </block> - <block> - <key>dtv_dvbs2_physical_cc</key> <param> - <key>id</key> - <value>dtv_dvbs2_physical_cc_0</value> + <key>corr10</key> + <value>0</value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>freq10</key> + <value>100e6</value> </param> <param> - <key>framesize</key> - <value>FECFRAME_NORMAL</value> + <key>if_gain10</key> + <value>20</value> </param> <param> - <key>constellation</key> - <value>MOD_16APSK</value> + <key>gain10</key> + <value>10</value> </param> <param> - <key>rate</key> - <value>C9_10</value> + <key>ant11</key> + <value></value> </param> <param> - <key>pilots</key> - <value>PILOTS_ON</value> + <key>bb_gain11</key> + <value>20</value> </param> <param> - <key>goldcode</key> + <key>bw11</key> <value>0</value> </param> <param> - <key>alias</key> - <value></value> + <key>corr11</key> + <value>0</value> </param> <param> - <key>affinity</key> + <key>freq11</key> + <value>100e6</value> + </param> + <param> + <key>if_gain11</key> + <value>20</value> + </param> + <param> + <key>gain11</key> + <value>10</value> + </param> + <param> + <key>ant12</key> <value></value> </param> <param> - <key>minoutbuf</key> + <key>bb_gain12</key> + <value>20</value> + </param> + <param> + <key>bw12</key> <value>0</value> </param> <param> - <key>maxoutbuf</key> + <key>corr12</key> <value>0</value> </param> <param> - <key>_coordinate</key> - <value>(192, 443)</value> + <key>freq12</key> + <value>100e6</value> </param> <param> - <key>_rotation</key> + <key>if_gain12</key> + <value>20</value> + </param> + <param> + <key>gain12</key> + <value>10</value> + </param> + <param> + <key>ant13</key> + <value></value> + </param> + <param> + <key>bb_gain13</key> + <value>20</value> + </param> + <param> + <key>bw13</key> <value>0</value> </param> - </block> - <block> - <key>osmosdr_sink</key> <param> - <key>id</key> - <value>osmosdr_sink_0</value> + <key>corr13</key> + <value>0</value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>freq13</key> + <value>100e6</value> </param> <param> - <key>type</key> - <value>fc32</value> + <key>if_gain13</key> + <value>20</value> </param> <param> - <key>args</key> - <value>bladerf=0,buffers=128,buflen=32768</value> + <key>gain13</key> + <value>10</value> </param> <param> - <key>sync</key> + <key>ant14</key> <value></value> </param> <param> - <key>num_mboards</key> - <value>1</value> + <key>bb_gain14</key> + <value>20</value> </param> <param> - <key>clock_source0</key> - <value></value> + <key>bw14</key> + <value>0</value> </param> <param> - <key>time_source0</key> - <value></value> + <key>corr14</key> + <value>0</value> </param> <param> - <key>clock_source1</key> - <value></value> + <key>freq14</key> + <value>100e6</value> </param> <param> - <key>time_source1</key> - <value></value> + <key>if_gain14</key> + <value>20</value> </param> <param> - <key>clock_source2</key> - <value></value> + <key>gain14</key> + <value>10</value> </param> <param> - <key>time_source2</key> + <key>ant15</key> <value></value> </param> <param> - <key>clock_source3</key> - <value></value> + <key>bb_gain15</key> + <value>20</value> </param> <param> - <key>time_source3</key> - <value></value> + <key>bw15</key> + <value>0</value> </param> <param> - <key>clock_source4</key> - <value></value> + <key>corr15</key> + <value>0</value> </param> <param> - <key>time_source4</key> - <value></value> + <key>freq15</key> + <value>100e6</value> </param> <param> - <key>clock_source5</key> - <value></value> + <key>if_gain15</key> + <value>20</value> </param> <param> - <key>time_source5</key> - <value></value> + <key>gain15</key> + <value>10</value> </param> <param> - <key>clock_source6</key> + <key>ant16</key> <value></value> </param> <param> - <key>time_source6</key> - <value></value> + <key>bb_gain16</key> + <value>20</value> </param> <param> - <key>clock_source7</key> - <value></value> + <key>bw16</key> + <value>0</value> </param> <param> - <key>time_source7</key> - <value></value> + <key>corr16</key> + <value>0</value> </param> <param> - <key>nchan</key> - <value>1</value> + <key>freq16</key> + <value>100e6</value> </param> <param> - <key>sample_rate</key> - <value>samp_rate</value> + <key>if_gain16</key> + <value>20</value> </param> <param> - <key>freq0</key> - <value>1280e6</value> + <key>gain16</key> + <value>10</value> </param> <param> - <key>corr0</key> - <value>0</value> + <key>ant17</key> + <value></value> </param> <param> - <key>gain0</key> - <value>15</value> + <key>bb_gain17</key> + <value>20</value> </param> <param> - <key>if_gain0</key> + <key>bw17</key> <value>0</value> </param> <param> - <key>bb_gain0</key> - <value>-10</value> + <key>corr17</key> + <value>0</value> </param> <param> - <key>ant0</key> + <key>freq17</key> + <value>100e6</value> + </param> + <param> + <key>if_gain17</key> + <value>20</value> + </param> + <param> + <key>gain17</key> + <value>10</value> + </param> + <param> + <key>ant18</key> <value></value> </param> <param> - <key>bw0</key> - <value>6000000</value> + <key>bb_gain18</key> + <value>20</value> </param> <param> - <key>freq1</key> - <value>100e6</value> + <key>bw18</key> + <value>0</value> </param> <param> - <key>corr1</key> + <key>corr18</key> <value>0</value> </param> <param> - <key>gain1</key> + <key>freq18</key> + <value>100e6</value> + </param> + <param> + <key>if_gain18</key> + <value>20</value> + </param> + <param> + <key>gain18</key> <value>10</value> </param> <param> - <key>if_gain1</key> + <key>ant19</key> + <value></value> + </param> + <param> + <key>bb_gain19</key> <value>20</value> </param> <param> - <key>bb_gain1</key> + <key>bw19</key> + <value>0</value> + </param> + <param> + <key>corr19</key> + <value>0</value> + </param> + <param> + <key>freq19</key> + <value>100e6</value> + </param> + <param> + <key>if_gain19</key> <value>20</value> </param> <param> + <key>gain19</key> + <value>10</value> + </param> + <param> <key>ant1</key> <value></value> </param> <param> + <key>bb_gain1</key> + <value>20</value> + </param> + <param> <key>bw1</key> <value>0</value> </param> <param> - <key>freq2</key> + <key>corr1</key> + <value>0</value> + </param> + <param> + <key>freq1</key> <value>100e6</value> </param> <param> - <key>corr2</key> - <value>0</value> + <key>if_gain1</key> + <value>20</value> </param> <param> - <key>gain2</key> + <key>gain1</key> <value>10</value> </param> <param> - <key>if_gain2</key> - <value>20</value> + <key>ant20</key> + <value></value> </param> <param> - <key>bb_gain2</key> + <key>bb_gain20</key> <value>20</value> </param> <param> - <key>ant2</key> - <value></value> + <key>bw20</key> + <value>0</value> </param> <param> - <key>bw2</key> + <key>corr20</key> <value>0</value> </param> <param> - <key>freq3</key> + <key>freq20</key> <value>100e6</value> </param> <param> - <key>corr3</key> - <value>0</value> + <key>if_gain20</key> + <value>20</value> </param> <param> - <key>gain3</key> + <key>gain20</key> <value>10</value> </param> <param> - <key>if_gain3</key> - <value>20</value> + <key>ant21</key> + <value></value> </param> <param> - <key>bb_gain3</key> + <key>bb_gain21</key> <value>20</value> </param> <param> - <key>ant3</key> - <value></value> + <key>bw21</key> + <value>0</value> </param> <param> - <key>bw3</key> + <key>corr21</key> <value>0</value> </param> <param> - <key>freq4</key> + <key>freq21</key> <value>100e6</value> </param> <param> - <key>corr4</key> - <value>0</value> + <key>if_gain21</key> + <value>20</value> </param> <param> - <key>gain4</key> + <key>gain21</key> <value>10</value> </param> <param> - <key>if_gain4</key> - <value>20</value> + <key>ant22</key> + <value></value> </param> <param> - <key>bb_gain4</key> + <key>bb_gain22</key> <value>20</value> </param> <param> - <key>ant4</key> - <value></value> + <key>bw22</key> + <value>0</value> </param> <param> - <key>bw4</key> + <key>corr22</key> <value>0</value> </param> <param> - <key>freq5</key> + <key>freq22</key> <value>100e6</value> </param> <param> - <key>corr5</key> - <value>0</value> + <key>if_gain22</key> + <value>20</value> </param> <param> - <key>gain5</key> + <key>gain22</key> <value>10</value> </param> <param> - <key>if_gain5</key> - <value>20</value> + <key>ant23</key> + <value></value> </param> <param> - <key>bb_gain5</key> + <key>bb_gain23</key> <value>20</value> </param> <param> - <key>ant5</key> - <value></value> + <key>bw23</key> + <value>0</value> </param> <param> - <key>bw5</key> + <key>corr23</key> <value>0</value> </param> <param> - <key>freq6</key> + <key>freq23</key> <value>100e6</value> </param> <param> - <key>corr6</key> - <value>0</value> + <key>if_gain23</key> + <value>20</value> </param> <param> - <key>gain6</key> + <key>gain23</key> <value>10</value> </param> <param> - <key>if_gain6</key> - <value>20</value> + <key>ant24</key> + <value></value> </param> <param> - <key>bb_gain6</key> + <key>bb_gain24</key> <value>20</value> </param> <param> - <key>ant6</key> - <value></value> + <key>bw24</key> + <value>0</value> </param> <param> - <key>bw6</key> + <key>corr24</key> <value>0</value> </param> <param> - <key>freq7</key> + <key>freq24</key> <value>100e6</value> </param> <param> - <key>corr7</key> - <value>0</value> + <key>if_gain24</key> + <value>20</value> </param> <param> - <key>gain7</key> + <key>gain24</key> <value>10</value> </param> <param> - <key>if_gain7</key> - <value>20</value> + <key>ant25</key> + <value></value> </param> <param> - <key>bb_gain7</key> + <key>bb_gain25</key> <value>20</value> </param> <param> - <key>ant7</key> - <value></value> + <key>bw25</key> + <value>0</value> </param> <param> - <key>bw7</key> + <key>corr25</key> <value>0</value> </param> <param> - <key>freq8</key> + <key>freq25</key> <value>100e6</value> </param> <param> - <key>corr8</key> - <value>0</value> + <key>if_gain25</key> + <value>20</value> </param> <param> - <key>gain8</key> + <key>gain25</key> <value>10</value> </param> <param> - <key>if_gain8</key> - <value>20</value> + <key>ant26</key> + <value></value> </param> <param> - <key>bb_gain8</key> + <key>bb_gain26</key> <value>20</value> </param> <param> - <key>ant8</key> - <value></value> + <key>bw26</key> + <value>0</value> </param> <param> - <key>bw8</key> + <key>corr26</key> <value>0</value> </param> <param> - <key>freq9</key> + <key>freq26</key> <value>100e6</value> </param> <param> - <key>corr9</key> - <value>0</value> + <key>if_gain26</key> + <value>20</value> </param> <param> - <key>gain9</key> + <key>gain26</key> <value>10</value> </param> <param> - <key>if_gain9</key> - <value>20</value> + <key>ant27</key> + <value></value> </param> <param> - <key>bb_gain9</key> + <key>bb_gain27</key> <value>20</value> </param> <param> - <key>ant9</key> - <value></value> + <key>bw27</key> + <value>0</value> </param> <param> - <key>bw9</key> + <key>corr27</key> <value>0</value> </param> <param> - <key>freq10</key> + <key>freq27</key> <value>100e6</value> </param> <param> - <key>corr10</key> - <value>0</value> + <key>if_gain27</key> + <value>20</value> </param> <param> - <key>gain10</key> + <key>gain27</key> <value>10</value> </param> <param> - <key>if_gain10</key> - <value>20</value> + <key>ant28</key> + <value></value> </param> <param> - <key>bb_gain10</key> + <key>bb_gain28</key> <value>20</value> </param> <param> - <key>ant10</key> - <value></value> + <key>bw28</key> + <value>0</value> </param> <param> - <key>bw10</key> + <key>corr28</key> <value>0</value> </param> <param> - <key>freq11</key> + <key>freq28</key> <value>100e6</value> </param> <param> - <key>corr11</key> - <value>0</value> + <key>if_gain28</key> + <value>20</value> </param> <param> - <key>gain11</key> + <key>gain28</key> <value>10</value> </param> <param> - <key>if_gain11</key> - <value>20</value> + <key>ant29</key> + <value></value> </param> <param> - <key>bb_gain11</key> + <key>bb_gain29</key> <value>20</value> </param> <param> - <key>ant11</key> - <value></value> + <key>bw29</key> + <value>0</value> </param> <param> - <key>bw11</key> + <key>corr29</key> <value>0</value> </param> <param> - <key>freq12</key> + <key>freq29</key> <value>100e6</value> </param> <param> - <key>corr12</key> - <value>0</value> + <key>if_gain29</key> + <value>20</value> </param> <param> - <key>gain12</key> + <key>gain29</key> <value>10</value> </param> <param> - <key>if_gain12</key> - <value>20</value> + <key>ant2</key> + <value></value> </param> <param> - <key>bb_gain12</key> + <key>bb_gain2</key> <value>20</value> </param> <param> - <key>ant12</key> - <value></value> + <key>bw2</key> + <value>0</value> </param> <param> - <key>bw12</key> + <key>corr2</key> <value>0</value> </param> <param> - <key>freq13</key> + <key>freq2</key> <value>100e6</value> </param> <param> - <key>corr13</key> - <value>0</value> + <key>if_gain2</key> + <value>20</value> </param> <param> - <key>gain13</key> + <key>gain2</key> <value>10</value> </param> <param> - <key>if_gain13</key> - <value>20</value> + <key>ant30</key> + <value></value> </param> <param> - <key>bb_gain13</key> + <key>bb_gain30</key> <value>20</value> </param> <param> - <key>ant13</key> - <value></value> + <key>bw30</key> + <value>0</value> </param> <param> - <key>bw13</key> + <key>corr30</key> <value>0</value> </param> <param> - <key>freq14</key> + <key>freq30</key> <value>100e6</value> </param> <param> - <key>corr14</key> - <value>0</value> + <key>if_gain30</key> + <value>20</value> </param> <param> - <key>gain14</key> + <key>gain30</key> <value>10</value> </param> <param> - <key>if_gain14</key> - <value>20</value> + <key>ant31</key> + <value></value> </param> <param> - <key>bb_gain14</key> + <key>bb_gain31</key> <value>20</value> </param> <param> - <key>ant14</key> - <value></value> + <key>bw31</key> + <value>0</value> </param> <param> - <key>bw14</key> + <key>corr31</key> <value>0</value> </param> <param> - <key>freq15</key> + <key>freq31</key> <value>100e6</value> </param> <param> - <key>corr15</key> - <value>0</value> + <key>if_gain31</key> + <value>20</value> </param> <param> - <key>gain15</key> + <key>gain31</key> <value>10</value> </param> <param> - <key>if_gain15</key> + <key>ant3</key> + <value></value> + </param> + <param> + <key>bb_gain3</key> <value>20</value> </param> <param> - <key>bb_gain15</key> + <key>bw3</key> + <value>0</value> + </param> + <param> + <key>corr3</key> + <value>0</value> + </param> + <param> + <key>freq3</key> + <value>100e6</value> + </param> + <param> + <key>if_gain3</key> <value>20</value> </param> <param> - <key>ant15</key> + <key>gain3</key> + <value>10</value> + </param> + <param> + <key>ant4</key> <value></value> </param> <param> - <key>bw15</key> + <key>bb_gain4</key> + <value>20</value> + </param> + <param> + <key>bw4</key> <value>0</value> </param> <param> - <key>freq16</key> + <key>corr4</key> + <value>0</value> + </param> + <param> + <key>freq4</key> <value>100e6</value> </param> <param> - <key>corr16</key> - <value>0</value> + <key>if_gain4</key> + <value>20</value> </param> <param> - <key>gain16</key> + <key>gain4</key> <value>10</value> </param> <param> - <key>if_gain16</key> + <key>ant5</key> + <value></value> + </param> + <param> + <key>bb_gain5</key> <value>20</value> </param> <param> - <key>bb_gain16</key> + <key>bw5</key> + <value>0</value> + </param> + <param> + <key>corr5</key> + <value>0</value> + </param> + <param> + <key>freq5</key> + <value>100e6</value> + </param> + <param> + <key>if_gain5</key> <value>20</value> </param> <param> - <key>ant16</key> + <key>gain5</key> + <value>10</value> + </param> + <param> + <key>ant6</key> <value></value> </param> <param> - <key>bw16</key> + <key>bb_gain6</key> + <value>20</value> + </param> + <param> + <key>bw6</key> <value>0</value> </param> <param> - <key>freq17</key> + <key>corr6</key> + <value>0</value> + </param> + <param> + <key>freq6</key> <value>100e6</value> </param> <param> - <key>corr17</key> - <value>0</value> + <key>if_gain6</key> + <value>20</value> </param> <param> - <key>gain17</key> + <key>gain6</key> <value>10</value> </param> <param> - <key>if_gain17</key> + <key>ant7</key> + <value></value> + </param> + <param> + <key>bb_gain7</key> <value>20</value> </param> <param> - <key>bb_gain17</key> + <key>bw7</key> + <value>0</value> + </param> + <param> + <key>corr7</key> + <value>0</value> + </param> + <param> + <key>freq7</key> + <value>100e6</value> + </param> + <param> + <key>if_gain7</key> <value>20</value> </param> <param> - <key>ant17</key> + <key>gain7</key> + <value>10</value> + </param> + <param> + <key>ant8</key> <value></value> </param> <param> - <key>bw17</key> + <key>bb_gain8</key> + <value>20</value> + </param> + <param> + <key>bw8</key> <value>0</value> </param> <param> - <key>freq18</key> + <key>corr8</key> + <value>0</value> + </param> + <param> + <key>freq8</key> <value>100e6</value> </param> <param> - <key>corr18</key> - <value>0</value> + <key>if_gain8</key> + <value>20</value> </param> <param> - <key>gain18</key> + <key>gain8</key> <value>10</value> </param> <param> - <key>if_gain18</key> + <key>ant9</key> + <value></value> + </param> + <param> + <key>bb_gain9</key> <value>20</value> </param> <param> - <key>bb_gain18</key> + <key>bw9</key> + <value>0</value> + </param> + <param> + <key>corr9</key> + <value>0</value> + </param> + <param> + <key>freq9</key> + <value>100e6</value> + </param> + <param> + <key>if_gain9</key> <value>20</value> </param> <param> - <key>ant18</key> + <key>gain9</key> + <value>10</value> + </param> + <param> + <key>comment</key> <value></value> </param> <param> - <key>bw18</key> + <key>affinity</key> + <value></value> + </param> + <param> + <key>args</key> + <value>bladerf=0,buffers=128,buflen=32768</value> + </param> + <param> + <key>_enabled</key> <value>0</value> </param> <param> - <key>freq19</key> - <value>100e6</value> + <key>_coordinate</key> + <value>(1040, 243)</value> </param> <param> - <key>corr19</key> + <key>_rotation</key> <value>0</value> </param> <param> - <key>gain19</key> - <value>10</value> + <key>id</key> + <value>osmosdr_sink_0</value> </param> <param> - <key>if_gain19</key> - <value>20</value> + <key>type</key> + <value>fc32</value> </param> <param> - <key>bb_gain19</key> - <value>20</value> + <key>clock_source0</key> + <value></value> </param> <param> - <key>ant19</key> + <key>time_source0</key> <value></value> </param> <param> - <key>bw19</key> + <key>clock_source1</key> + <value></value> + </param> + <param> + <key>time_source1</key> + <value></value> + </param> + <param> + <key>clock_source2</key> + <value></value> + </param> + <param> + <key>time_source2</key> + <value></value> + </param> + <param> + <key>clock_source3</key> + <value></value> + </param> + <param> + <key>time_source3</key> + <value></value> + </param> + <param> + <key>clock_source4</key> + <value></value> + </param> + <param> + <key>time_source4</key> + <value></value> + </param> + <param> + <key>clock_source5</key> + <value></value> + </param> + <param> + <key>time_source5</key> + <value></value> + </param> + <param> + <key>clock_source6</key> + <value></value> + </param> + <param> + <key>time_source6</key> + <value></value> + </param> + <param> + <key>clock_source7</key> + <value></value> + </param> + <param> + <key>time_source7</key> + <value></value> + </param> + <param> + <key>nchan</key> + <value>1</value> + </param> + <param> + <key>num_mboards</key> + <value>1</value> + </param> + <param> + <key>sample_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>sync</key> + <value></value> + </param> + </block> + <block> + <key>uhd_usrp_sink</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>ant0</key> + <value></value> + </param> + <param> + <key>bw0</key> <value>0</value> </param> <param> - <key>freq20</key> - <value>100e6</value> + <key>center_freq0</key> + <value>uhd.tune_request(frequency, ((symbol_rate * (1 + rolloff)) / 2 ) + 1e5)</value> </param> <param> - <key>corr20</key> + <key>norm_gain0</key> + <value>False</value> + </param> + <param> + <key>gain0</key> + <value>60</value> + </param> + <param> + <key>ant10</key> + <value></value> + </param> + <param> + <key>bw10</key> <value>0</value> </param> <param> - <key>gain20</key> - <value>10</value> + <key>center_freq10</key> + <value>0</value> </param> <param> - <key>if_gain20</key> - <value>20</value> + <key>norm_gain10</key> + <value>False</value> </param> <param> - <key>bb_gain20</key> - <value>20</value> + <key>gain10</key> + <value>0</value> </param> <param> - <key>ant20</key> + <key>ant11</key> <value></value> </param> <param> - <key>bw20</key> + <key>bw11</key> <value>0</value> </param> <param> - <key>freq21</key> - <value>100e6</value> + <key>center_freq11</key> + <value>0</value> </param> <param> - <key>corr21</key> + <key>norm_gain11</key> + <value>False</value> + </param> + <param> + <key>gain11</key> <value>0</value> </param> <param> - <key>gain21</key> - <value>10</value> + <key>ant12</key> + <value></value> </param> <param> - <key>if_gain21</key> - <value>20</value> + <key>bw12</key> + <value>0</value> </param> <param> - <key>bb_gain21</key> - <value>20</value> + <key>center_freq12</key> + <value>0</value> </param> <param> - <key>ant21</key> + <key>norm_gain12</key> + <value>False</value> + </param> + <param> + <key>gain12</key> + <value>0</value> + </param> + <param> + <key>ant13</key> <value></value> </param> <param> - <key>bw21</key> + <key>bw13</key> <value>0</value> </param> <param> - <key>freq22</key> - <value>100e6</value> + <key>center_freq13</key> + <value>0</value> </param> <param> - <key>corr22</key> + <key>norm_gain13</key> + <value>False</value> + </param> + <param> + <key>gain13</key> <value>0</value> </param> <param> - <key>gain22</key> - <value>10</value> + <key>ant14</key> + <value></value> </param> <param> - <key>if_gain22</key> - <value>20</value> + <key>bw14</key> + <value>0</value> </param> <param> - <key>bb_gain22</key> - <value>20</value> + <key>center_freq14</key> + <value>0</value> </param> <param> - <key>ant22</key> + <key>norm_gain14</key> + <value>False</value> + </param> + <param> + <key>gain14</key> + <value>0</value> + </param> + <param> + <key>ant15</key> <value></value> </param> <param> - <key>bw22</key> + <key>bw15</key> <value>0</value> </param> <param> - <key>freq23</key> - <value>100e6</value> + <key>center_freq15</key> + <value>0</value> </param> <param> - <key>corr23</key> + <key>norm_gain15</key> + <value>False</value> + </param> + <param> + <key>gain15</key> <value>0</value> </param> <param> - <key>gain23</key> - <value>10</value> + <key>ant16</key> + <value></value> </param> <param> - <key>if_gain23</key> - <value>20</value> + <key>bw16</key> + <value>0</value> </param> <param> - <key>bb_gain23</key> - <value>20</value> + <key>center_freq16</key> + <value>0</value> </param> <param> - <key>ant23</key> + <key>norm_gain16</key> + <value>False</value> + </param> + <param> + <key>gain16</key> + <value>0</value> + </param> + <param> + <key>ant17</key> <value></value> </param> <param> - <key>bw23</key> + <key>bw17</key> <value>0</value> </param> <param> - <key>freq24</key> - <value>100e6</value> + <key>center_freq17</key> + <value>0</value> </param> <param> - <key>corr24</key> + <key>norm_gain17</key> + <value>False</value> + </param> + <param> + <key>gain17</key> <value>0</value> </param> <param> - <key>gain24</key> - <value>10</value> + <key>ant18</key> + <value></value> </param> <param> - <key>if_gain24</key> - <value>20</value> + <key>bw18</key> + <value>0</value> </param> <param> - <key>bb_gain24</key> - <value>20</value> + <key>center_freq18</key> + <value>0</value> </param> <param> - <key>ant24</key> + <key>norm_gain18</key> + <value>False</value> + </param> + <param> + <key>gain18</key> + <value>0</value> + </param> + <param> + <key>ant19</key> <value></value> </param> <param> - <key>bw24</key> + <key>bw19</key> <value>0</value> </param> <param> - <key>freq25</key> - <value>100e6</value> + <key>center_freq19</key> + <value>0</value> </param> <param> - <key>corr25</key> + <key>norm_gain19</key> + <value>False</value> + </param> + <param> + <key>gain19</key> <value>0</value> </param> <param> - <key>gain25</key> - <value>10</value> + <key>ant1</key> + <value></value> </param> <param> - <key>if_gain25</key> - <value>20</value> + <key>bw1</key> + <value>0</value> </param> <param> - <key>bb_gain25</key> - <value>20</value> + <key>center_freq1</key> + <value>0</value> </param> <param> - <key>ant25</key> + <key>norm_gain1</key> + <value>False</value> + </param> + <param> + <key>gain1</key> + <value>0</value> + </param> + <param> + <key>ant20</key> <value></value> </param> <param> - <key>bw25</key> + <key>bw20</key> <value>0</value> </param> <param> - <key>freq26</key> - <value>100e6</value> + <key>center_freq20</key> + <value>0</value> </param> <param> - <key>corr26</key> + <key>norm_gain20</key> + <value>False</value> + </param> + <param> + <key>gain20</key> <value>0</value> </param> <param> - <key>gain26</key> - <value>10</value> + <key>ant21</key> + <value></value> </param> <param> - <key>if_gain26</key> - <value>20</value> + <key>bw21</key> + <value>0</value> </param> <param> - <key>bb_gain26</key> - <value>20</value> + <key>center_freq21</key> + <value>0</value> </param> <param> - <key>ant26</key> + <key>norm_gain21</key> + <value>False</value> + </param> + <param> + <key>gain21</key> + <value>0</value> + </param> + <param> + <key>ant22</key> <value></value> </param> <param> - <key>bw26</key> + <key>bw22</key> <value>0</value> </param> <param> - <key>freq27</key> - <value>100e6</value> + <key>center_freq22</key> + <value>0</value> </param> <param> - <key>corr27</key> + <key>norm_gain22</key> + <value>False</value> + </param> + <param> + <key>gain22</key> <value>0</value> </param> <param> - <key>gain27</key> - <value>10</value> + <key>ant23</key> + <value></value> </param> <param> - <key>if_gain27</key> - <value>20</value> + <key>bw23</key> + <value>0</value> </param> <param> - <key>bb_gain27</key> - <value>20</value> + <key>center_freq23</key> + <value>0</value> </param> <param> - <key>ant27</key> + <key>norm_gain23</key> + <value>False</value> + </param> + <param> + <key>gain23</key> + <value>0</value> + </param> + <param> + <key>ant24</key> <value></value> </param> <param> - <key>bw27</key> + <key>bw24</key> <value>0</value> </param> <param> - <key>freq28</key> - <value>100e6</value> + <key>center_freq24</key> + <value>0</value> </param> <param> - <key>corr28</key> + <key>norm_gain24</key> + <value>False</value> + </param> + <param> + <key>gain24</key> <value>0</value> </param> <param> - <key>gain28</key> - <value>10</value> + <key>ant25</key> + <value></value> </param> <param> - <key>if_gain28</key> - <value>20</value> + <key>bw25</key> + <value>0</value> </param> <param> - <key>bb_gain28</key> - <value>20</value> + <key>center_freq25</key> + <value>0</value> </param> <param> - <key>ant28</key> + <key>norm_gain25</key> + <value>False</value> + </param> + <param> + <key>gain25</key> + <value>0</value> + </param> + <param> + <key>ant26</key> <value></value> </param> <param> - <key>bw28</key> + <key>bw26</key> <value>0</value> </param> <param> - <key>freq29</key> - <value>100e6</value> + <key>center_freq26</key> + <value>0</value> </param> <param> - <key>corr29</key> + <key>norm_gain26</key> + <value>False</value> + </param> + <param> + <key>gain26</key> <value>0</value> </param> <param> - <key>gain29</key> - <value>10</value> + <key>ant27</key> + <value></value> </param> <param> - <key>if_gain29</key> - <value>20</value> + <key>bw27</key> + <value>0</value> </param> <param> - <key>bb_gain29</key> - <value>20</value> + <key>center_freq27</key> + <value>0</value> + </param> + <param> + <key>norm_gain27</key> + <value>False</value> + </param> + <param> + <key>gain27</key> + <value>0</value> + </param> + <param> + <key>ant28</key> + <value></value> + </param> + <param> + <key>bw28</key> + <value>0</value> + </param> + <param> + <key>center_freq28</key> + <value>0</value> + </param> + <param> + <key>norm_gain28</key> + <value>False</value> + </param> + <param> + <key>gain28</key> + <value>0</value> </param> <param> <key>ant29</key> @@ -1596,24 +2272,36 @@ <value>0</value> </param> <param> - <key>freq30</key> - <value>100e6</value> + <key>center_freq29</key> + <value>0</value> </param> <param> - <key>corr30</key> + <key>norm_gain29</key> + <value>False</value> + </param> + <param> + <key>gain29</key> <value>0</value> </param> <param> - <key>gain30</key> - <value>10</value> + <key>ant2</key> + <value></value> </param> <param> - <key>if_gain30</key> - <value>20</value> + <key>bw2</key> + <value>0</value> </param> <param> - <key>bb_gain30</key> - <value>20</value> + <key>center_freq2</key> + <value>0</value> + </param> + <param> + <key>norm_gain2</key> + <value>False</value> + </param> + <param> + <key>gain2</key> + <value>0</value> </param> <param> <key>ant30</key> @@ -1624,82 +2312,183 @@ <value>0</value> </param> <param> - <key>freq31</key> - <value>100e6</value> + <key>center_freq30</key> + <value>0</value> </param> <param> - <key>corr31</key> + <key>norm_gain30</key> + <value>False</value> + </param> + <param> + <key>gain30</key> <value>0</value> </param> <param> + <key>ant31</key> + <value></value> + </param> + <param> + <key>bw31</key> + <value>0</value> + </param> + <param> + <key>center_freq31</key> + <value>0</value> + </param> + <param> + <key>norm_gain31</key> + <value>False</value> + </param> + <param> <key>gain31</key> - <value>10</value> + <value>0</value> </param> <param> - <key>if_gain31</key> - <value>20</value> + <key>ant3</key> + <value></value> </param> <param> - <key>bb_gain31</key> - <value>20</value> + <key>bw3</key> + <value>0</value> </param> <param> - <key>ant31</key> + <key>center_freq3</key> + <value>0</value> + </param> + <param> + <key>norm_gain3</key> + <value>False</value> + </param> + <param> + <key>gain3</key> + <value>0</value> + </param> + <param> + <key>ant4</key> <value></value> </param> <param> - <key>bw31</key> + <key>bw4</key> <value>0</value> </param> <param> - <key>alias</key> + <key>center_freq4</key> + <value>0</value> + </param> + <param> + <key>norm_gain4</key> + <value>False</value> + </param> + <param> + <key>gain4</key> + <value>0</value> + </param> + <param> + <key>ant5</key> <value></value> </param> <param> - <key>affinity</key> + <key>bw5</key> + <value>0</value> + </param> + <param> + <key>center_freq5</key> + <value>0</value> + </param> + <param> + <key>norm_gain5</key> + <value>False</value> + </param> + <param> + <key>gain5</key> + <value>0</value> + </param> + <param> + <key>ant6</key> <value></value> </param> <param> - <key>_coordinate</key> - <value>(1000, 203)</value> + <key>bw6</key> + <value>0</value> </param> <param> - <key>_rotation</key> + <key>center_freq6</key> <value>0</value> </param> - </block> - <block> - <key>blocks_file_sink</key> <param> - <key>id</key> - <value>blocks_file_sink_0</value> + <key>norm_gain6</key> + <value>False</value> </param> <param> - <key>_enabled</key> + <key>gain6</key> + <value>0</value> + </param> + <param> + <key>ant7</key> + <value></value> + </param> + <param> + <key>bw7</key> + <value>0</value> + </param> + <param> + <key>center_freq7</key> + <value>0</value> + </param> + <param> + <key>norm_gain7</key> <value>False</value> </param> <param> - <key>file</key> - <value>adv.cfile</value> + <key>gain7</key> + <value>0</value> </param> <param> - <key>type</key> - <value>complex</value> + <key>ant8</key> + <value></value> </param> <param> - <key>vlen</key> - <value>1</value> + <key>bw8</key> + <value>0</value> </param> <param> - <key>unbuffered</key> + <key>center_freq8</key> + <value>0</value> + </param> + <param> + <key>norm_gain8</key> <value>False</value> </param> <param> - <key>append</key> + <key>gain8</key> + <value>0</value> + </param> + <param> + <key>ant9</key> + <value></value> + </param> + <param> + <key>bw9</key> + <value>0</value> + </param> + <param> + <key>center_freq9</key> + <value>0</value> + </param> + <param> + <key>norm_gain9</key> <value>False</value> </param> <param> - <key>alias</key> + <key>gain9</key> + <value>0</value> + </param> + <param> + <key>clock_rate</key> + <value>0.0</value> + </param> + <param> + <key>comment</key> <value></value> </param> <param> @@ -1707,163 +2496,270 @@ <value></value> </param> <param> + <key>dev_addr</key> + <value>"send_frame_size=65536,num_send_frames=256,master_clock_rate=" + str(samp_rate*2)</value> + </param> + <param> + <key>dev_args</key> + <value>""</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> <key>_coordinate</key> - <value>(792, 547)</value> + <value>(1040, 427)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> - </block> - <block> - <key>dtv_dvb_bbheader_bb</key> <param> <key>id</key> - <value>dtv_dvb_bbheader_bb_0</value> + <value>uhd_usrp_sink_0_0</value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>type</key> + <value>fc32</value> </param> <param> - <key>standard</key> - <value>STANDARD_DVBS2</value> + <key>clock_source0</key> + <value></value> </param> <param> - <key>framesize</key> - <value>FECFRAME_NORMAL</value> + <key>sd_spec0</key> + <value></value> </param> <param> - <key>rate1</key> - <value>C1_2</value> + <key>time_source0</key> + <value></value> </param> <param> - <key>rate2</key> - <value>C1_3</value> + <key>clock_source1</key> + <value></value> </param> <param> - <key>rate3</key> - <value>C9_10</value> + <key>sd_spec1</key> + <value></value> </param> <param> - <key>rate4</key> - <value>C1_4</value> + <key>time_source1</key> + <value></value> </param> <param> - <key>rolloff</key> - <value>RO_0_20</value> + <key>clock_source2</key> + <value></value> </param> <param> - <key>mode</key> - <value>FECFRAME_NORMAL</value> + <key>sd_spec2</key> + <value></value> </param> <param> - <key>inband</key> - <value>INBAND_OFF</value> + <key>time_source2</key> + <value></value> </param> <param> - <key>fecblocks</key> - <value>168</value> + <key>clock_source3</key> + <value></value> </param> <param> - <key>tsrate</key> - <value>4000000</value> + <key>sd_spec3</key> + <value></value> </param> <param> - <key>alias</key> + <key>time_source3</key> <value></value> </param> <param> - <key>affinity</key> + <key>clock_source4</key> <value></value> </param> <param> - <key>minoutbuf</key> - <value>0</value> + <key>sd_spec4</key> + <value></value> </param> <param> - <key>maxoutbuf</key> - <value>0</value> + <key>time_source4</key> + <value></value> </param> <param> - <key>_coordinate</key> - <value>(400, 27)</value> + <key>clock_source5</key> + <value></value> </param> <param> - <key>_rotation</key> - <value>0</value> + <key>sd_spec5</key> + <value></value> </param> - </block> - <block> - <key>blocks_file_source</key> <param> - <key>id</key> - <value>blocks_file_source_0</value> + <key>time_source5</key> + <value></value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>clock_source6</key> + <value></value> </param> <param> - <key>file</key> - <value>/run/shm/adv16apsk910.ts</value> + <key>sd_spec6</key> + <value></value> </param> <param> - <key>type</key> - <value>byte</value> + <key>time_source6</key> + <value></value> </param> <param> - <key>repeat</key> - <value>True</value> + <key>clock_source7</key> + <value></value> </param> <param> - <key>vlen</key> + <key>sd_spec7</key> + <value></value> + </param> + <param> + <key>time_source7</key> + <value></value> + </param> + <param> + <key>nchan</key> <value>1</value> </param> <param> + <key>num_mboards</key> + <value>1</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>hide_cmd_port</key> + <value>False</value> + </param> + <param> + <key>stream_args</key> + <value></value> + </param> + <param> + <key>stream_chans</key> + <value>[]</value> + </param> + <param> + <key>sync</key> + <value></value> + </param> + <param> + <key>len_tag_name</key> + <value></value> + </param> + <param> + <key>otw</key> + <value></value> + </param> + </block> + <block> + <key>wxgui_fftsink2</key> + <param> + <key>avg_alpha</key> + <value>0.13333</value> + </param> + <param> + <key>average</key> + <value>True</value> + </param> + <param> + <key>baseband_freq</key> + <value>frequency</value> + </param> + <param> <key>alias</key> <value></value> </param> <param> + <key>comment</key> + <value></value> + </param> + <param> <key>affinity</key> <value></value> </param> <param> - <key>minoutbuf</key> - <value>0</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>maxoutbuf</key> - <value>0</value> + <key>fft_size</key> + <value>1024</value> + </param> + <param> + <key>freqvar</key> + <value>None</value> </param> <param> <key>_coordinate</key> - <value>(176, 43)</value> + <value>(784, 203)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>id</key> + <value>wxgui_fftsink2_0</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>peak_hold</key> + <value>False</value> + </param> + <param> + <key>ref_level</key> + <value>0</value> + </param> + <param> + <key>ref_scale</key> + <value>2.0</value> + </param> + <param> + <key>fft_rate</key> + <value>15</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>title</key> + <value>FFT Plot</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>win_size</key> + <value></value> + </param> + <param> + <key>win</key> + <value>None</value> + </param> + <param> + <key>y_divs</key> + <value>10</value> + </param> + <param> + <key>y_per_div</key> + <value>10</value> + </param> </block> <connection> - <source_block_id>fft_filter_xxx_0</source_block_id> - <sink_block_id>osmosdr_sink_0</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> - </connection> - <connection> - <source_block_id>fft_filter_xxx_0</source_block_id> - <sink_block_id>wxgui_fftsink2_0</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> - </connection> - <connection> - <source_block_id>fft_filter_xxx_0</source_block_id> - <sink_block_id>blocks_file_sink_0</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> - </connection> - <connection> <source_block_id>blocks_file_source_0</source_block_id> <sink_block_id>dtv_dvb_bbheader_bb_0</sink_block_id> <source_key>0</source_key> @@ -1900,14 +2796,38 @@ <sink_key>0</sink_key> </connection> <connection> + <source_block_id>dtv_dvbs2_modulator_bc_0</source_block_id> + <sink_block_id>dtv_dvbs2_physical_cc_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> <source_block_id>dtv_dvbs2_physical_cc_0</source_block_id> <sink_block_id>fft_filter_xxx_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> <connection> - <source_block_id>dtv_dvbs2_modulator_bc_0</source_block_id> - <sink_block_id>dtv_dvbs2_physical_cc_0</sink_block_id> + <source_block_id>fft_filter_xxx_0</source_block_id> + <sink_block_id>blocks_file_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>fft_filter_xxx_0</source_block_id> + <sink_block_id>osmosdr_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>fft_filter_xxx_0</source_block_id> + <sink_block_id>uhd_usrp_sink_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>fft_filter_xxx_0</source_block_id> + <sink_block_id>wxgui_fftsink2_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> diff --git a/gr-dtv/examples/dvbs_tx.grc b/gr-dtv/examples/dvbs_tx.grc new file mode 100644 index 0000000000..c9dd98a0b9 --- /dev/null +++ b/gr-dtv/examples/dvbs_tx.grc @@ -0,0 +1,2853 @@ +<?xml version='1.0' encoding='utf-8'?> +<?grc format='1' created='3.7.10'?> +<flow_graph> + <timestamp>Wed Jun 18 01:23:58 2014</timestamp> + <block> + <key>options</key> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>generate_options</key> + <value>wx_gui</value> + </param> + <param> + <key>hier_block_src_path</key> + <value>.:</value> + </param> + <param> + <key>id</key> + <value>dvbs_tx</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>qt_qss_theme</key> + <value></value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>run_command</key> + <value>{python} -u {filename}</value> + </param> + <param> + <key>run_options</key> + <value>prompt</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>thread_safe_setters</key> + <value></value> + </param> + <param> + <key>title</key> + <value></value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 203)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>frequency</value> + </param> + <param> + <key>value</key> + <value>1280e6</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 267)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>rrc_taps</value> + </param> + <param> + <key>value</key> + <value>100</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 75)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>value</key> + <value>symbol_rate * 2</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 139)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>symbol_rate</value> + </param> + <param> + <key>value</key> + <value>8000000</value> + </param> + </block> + <block> + <key>blocks_file_sink</key> + <param> + <key>append</key> + <value>False</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>0</value> + </param> + <param> + <key>file</key> + <value>adv.bin</value> + </param> + <param> + <key>_coordinate</key> + <value>(848, 507)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>blocks_file_sink_0</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>unbuffered</key> + <value>False</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + </block> + <block> + <key>blocks_file_source</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>file</key> + <value>/run/shm/advdvbs78.ts</value> + </param> + <param> + <key>_coordinate</key> + <value>(184, 59)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>blocks_file_source_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>repeat</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + </block> + <block> + <key>blocks_pack_k_bits_bb</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(176, 451)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>blocks_pack_k_bits_bb_0</value> + </param> + <param> + <key>k</key> + <value>2</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_packed_to_unpacked_xx</key> + <param> + <key>bits_per_chunk</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>endianness</key> + <value>gr.GR_MSB_FIRST</value> + </param> + <param> + <key>_coordinate</key> + <value>(1080, 59)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>blocks_packed_to_unpacked_xx_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>num_ports</key> + <value>1</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + </block> + <block> + <key>blocks_unpack_k_bits_bb</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(408, 235)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>blocks_unpack_k_bits_bb_0</value> + </param> + <param> + <key>k</key> + <value>2</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbs2_modulator_bc</key> + <param> + <key>interpolation</key> + <value>INTERPOLATION_ON</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>rate</key> + <value>C_OTHER</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>constellation</key> + <value>MOD_QPSK</value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>framesize</key> + <value>FECFRAME_NORMAL</value> + </param> + <param> + <key>_coordinate</key> + <value>(352, 427)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>dtv_dvbs2_modulator_bc_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_convolutional_interleaver</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>blocks</key> + <value>136</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>M</key> + <value>17</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(832, 51)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>dtv_dvbt_convolutional_interleaver_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>I</key> + <value>12</value> + </param> + </block> + <block> + <key>dtv_dvbt_energy_dispersal</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>nsize</key> + <value>1</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(408, 73)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>dtv_dvbt_energy_dispersal_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_reed_solomon_enc</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>blocks</key> + <value>8</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>gfpoly</key> + <value>0x11d</value> + </param> + <param> + <key>_coordinate</key> + <value>(600, 19)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>dtv_dvbt_reed_solomon_enc_0</value> + </param> + <param> + <key>k</key> + <value>239</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>n</key> + <value>255</value> + </param> + <param> + <key>s</key> + <value>51</value> + </param> + <param> + <key>m</key> + <value>8</value> + </param> + <param> + <key>p</key> + <value>2</value> + </param> + <param> + <key>t</key> + <value>8</value> + </param> + </block> + <block> + <key>fec_puncture_xx</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>delay</key> + <value>0</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(600, 219)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>fec_puncture_xx_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>puncpat</key> + <value>0b11010101100110</value> + </param> + <param> + <key>puncsize</key> + <value>14</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + </block> + <block> + <key>fft_filter_xxx</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>decim</key> + <value>1</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(584, 435)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>fft_filter_xxx_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>nthreads</key> + <value>1</value> + </param> + <param> + <key>samp_delay</key> + <value>0</value> + </param> + <param> + <key>taps</key> + <value>firdes.root_raised_cosine(1.0, samp_rate, samp_rate/2, 0.35, rrc_taps)</value> + </param> + <param> + <key>type</key> + <value>ccc</value> + </param> + </block> + <block> + <key>osmosdr_sink</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>ant0</key> + <value></value> + </param> + <param> + <key>bb_gain0</key> + <value>-10</value> + </param> + <param> + <key>bw0</key> + <value>10000000</value> + </param> + <param> + <key>corr0</key> + <value>0</value> + </param> + <param> + <key>freq0</key> + <value>frequency</value> + </param> + <param> + <key>if_gain0</key> + <value>0</value> + </param> + <param> + <key>gain0</key> + <value>15</value> + </param> + <param> + <key>ant10</key> + <value></value> + </param> + <param> + <key>bb_gain10</key> + <value>20</value> + </param> + <param> + <key>bw10</key> + <value>0</value> + </param> + <param> + <key>corr10</key> + <value>0</value> + </param> + <param> + <key>freq10</key> + <value>100e6</value> + </param> + <param> + <key>if_gain10</key> + <value>20</value> + </param> + <param> + <key>gain10</key> + <value>10</value> + </param> + <param> + <key>ant11</key> + <value></value> + </param> + <param> + <key>bb_gain11</key> + <value>20</value> + </param> + <param> + <key>bw11</key> + <value>0</value> + </param> + <param> + <key>corr11</key> + <value>0</value> + </param> + <param> + <key>freq11</key> + <value>100e6</value> + </param> + <param> + <key>if_gain11</key> + <value>20</value> + </param> + <param> + <key>gain11</key> + <value>10</value> + </param> + <param> + <key>ant12</key> + <value></value> + </param> + <param> + <key>bb_gain12</key> + <value>20</value> + </param> + <param> + <key>bw12</key> + <value>0</value> + </param> + <param> + <key>corr12</key> + <value>0</value> + </param> + <param> + <key>freq12</key> + <value>100e6</value> + </param> + <param> + <key>if_gain12</key> + <value>20</value> + </param> + <param> + <key>gain12</key> + <value>10</value> + </param> + <param> + <key>ant13</key> + <value></value> + </param> + <param> + <key>bb_gain13</key> + <value>20</value> + </param> + <param> + <key>bw13</key> + <value>0</value> + </param> + <param> + <key>corr13</key> + <value>0</value> + </param> + <param> + <key>freq13</key> + <value>100e6</value> + </param> + <param> + <key>if_gain13</key> + <value>20</value> + </param> + <param> + <key>gain13</key> + <value>10</value> + </param> + <param> + <key>ant14</key> + <value></value> + </param> + <param> + <key>bb_gain14</key> + <value>20</value> + </param> + <param> + <key>bw14</key> + <value>0</value> + </param> + <param> + <key>corr14</key> + <value>0</value> + </param> + <param> + <key>freq14</key> + <value>100e6</value> + </param> + <param> + <key>if_gain14</key> + <value>20</value> + </param> + <param> + <key>gain14</key> + <value>10</value> + </param> + <param> + <key>ant15</key> + <value></value> + </param> + <param> + <key>bb_gain15</key> + <value>20</value> + </param> + <param> + <key>bw15</key> + <value>0</value> + </param> + <param> + <key>corr15</key> + <value>0</value> + </param> + <param> + <key>freq15</key> + <value>100e6</value> + </param> + <param> + <key>if_gain15</key> + <value>20</value> + </param> + <param> + <key>gain15</key> + <value>10</value> + </param> + <param> + <key>ant16</key> + <value></value> + </param> + <param> + <key>bb_gain16</key> + <value>20</value> + </param> + <param> + <key>bw16</key> + <value>0</value> + </param> + <param> + <key>corr16</key> + <value>0</value> + </param> + <param> + <key>freq16</key> + <value>100e6</value> + </param> + <param> + <key>if_gain16</key> + <value>20</value> + </param> + <param> + <key>gain16</key> + <value>10</value> + </param> + <param> + <key>ant17</key> + <value></value> + </param> + <param> + <key>bb_gain17</key> + <value>20</value> + </param> + <param> + <key>bw17</key> + <value>0</value> + </param> + <param> + <key>corr17</key> + <value>0</value> + </param> + <param> + <key>freq17</key> + <value>100e6</value> + </param> + <param> + <key>if_gain17</key> + <value>20</value> + </param> + <param> + <key>gain17</key> + <value>10</value> + </param> + <param> + <key>ant18</key> + <value></value> + </param> + <param> + <key>bb_gain18</key> + <value>20</value> + </param> + <param> + <key>bw18</key> + <value>0</value> + </param> + <param> + <key>corr18</key> + <value>0</value> + </param> + <param> + <key>freq18</key> + <value>100e6</value> + </param> + <param> + <key>if_gain18</key> + <value>20</value> + </param> + <param> + <key>gain18</key> + <value>10</value> + </param> + <param> + <key>ant19</key> + <value></value> + </param> + <param> + <key>bb_gain19</key> + <value>20</value> + </param> + <param> + <key>bw19</key> + <value>0</value> + </param> + <param> + <key>corr19</key> + <value>0</value> + </param> + <param> + <key>freq19</key> + <value>100e6</value> + </param> + <param> + <key>if_gain19</key> + <value>20</value> + </param> + <param> + <key>gain19</key> + <value>10</value> + </param> + <param> + <key>ant1</key> + <value></value> + </param> + <param> + <key>bb_gain1</key> + <value>20</value> + </param> + <param> + <key>bw1</key> + <value>0</value> + </param> + <param> + <key>corr1</key> + <value>0</value> + </param> + <param> + <key>freq1</key> + <value>100e6</value> + </param> + <param> + <key>if_gain1</key> + <value>20</value> + </param> + <param> + <key>gain1</key> + <value>10</value> + </param> + <param> + <key>ant20</key> + <value></value> + </param> + <param> + <key>bb_gain20</key> + <value>20</value> + </param> + <param> + <key>bw20</key> + <value>0</value> + </param> + <param> + <key>corr20</key> + <value>0</value> + </param> + <param> + <key>freq20</key> + <value>100e6</value> + </param> + <param> + <key>if_gain20</key> + <value>20</value> + </param> + <param> + <key>gain20</key> + <value>10</value> + </param> + <param> + <key>ant21</key> + <value></value> + </param> + <param> + <key>bb_gain21</key> + <value>20</value> + </param> + <param> + <key>bw21</key> + <value>0</value> + </param> + <param> + <key>corr21</key> + <value>0</value> + </param> + <param> + <key>freq21</key> + <value>100e6</value> + </param> + <param> + <key>if_gain21</key> + <value>20</value> + </param> + <param> + <key>gain21</key> + <value>10</value> + </param> + <param> + <key>ant22</key> + <value></value> + </param> + <param> + <key>bb_gain22</key> + <value>20</value> + </param> + <param> + <key>bw22</key> + <value>0</value> + </param> + <param> + <key>corr22</key> + <value>0</value> + </param> + <param> + <key>freq22</key> + <value>100e6</value> + </param> + <param> + <key>if_gain22</key> + <value>20</value> + </param> + <param> + <key>gain22</key> + <value>10</value> + </param> + <param> + <key>ant23</key> + <value></value> + </param> + <param> + <key>bb_gain23</key> + <value>20</value> + </param> + <param> + <key>bw23</key> + <value>0</value> + </param> + <param> + <key>corr23</key> + <value>0</value> + </param> + <param> + <key>freq23</key> + <value>100e6</value> + </param> + <param> + <key>if_gain23</key> + <value>20</value> + </param> + <param> + <key>gain23</key> + <value>10</value> + </param> + <param> + <key>ant24</key> + <value></value> + </param> + <param> + <key>bb_gain24</key> + <value>20</value> + </param> + <param> + <key>bw24</key> + <value>0</value> + </param> + <param> + <key>corr24</key> + <value>0</value> + </param> + <param> + <key>freq24</key> + <value>100e6</value> + </param> + <param> + <key>if_gain24</key> + <value>20</value> + </param> + <param> + <key>gain24</key> + <value>10</value> + </param> + <param> + <key>ant25</key> + <value></value> + </param> + <param> + <key>bb_gain25</key> + <value>20</value> + </param> + <param> + <key>bw25</key> + <value>0</value> + </param> + <param> + <key>corr25</key> + <value>0</value> + </param> + <param> + <key>freq25</key> + <value>100e6</value> + </param> + <param> + <key>if_gain25</key> + <value>20</value> + </param> + <param> + <key>gain25</key> + <value>10</value> + </param> + <param> + <key>ant26</key> + <value></value> + </param> + <param> + <key>bb_gain26</key> + <value>20</value> + </param> + <param> + <key>bw26</key> + <value>0</value> + </param> + <param> + <key>corr26</key> + <value>0</value> + </param> + <param> + <key>freq26</key> + <value>100e6</value> + </param> + <param> + <key>if_gain26</key> + <value>20</value> + </param> + <param> + <key>gain26</key> + <value>10</value> + </param> + <param> + <key>ant27</key> + <value></value> + </param> + <param> + <key>bb_gain27</key> + <value>20</value> + </param> + <param> + <key>bw27</key> + <value>0</value> + </param> + <param> + <key>corr27</key> + <value>0</value> + </param> + <param> + <key>freq27</key> + <value>100e6</value> + </param> + <param> + <key>if_gain27</key> + <value>20</value> + </param> + <param> + <key>gain27</key> + <value>10</value> + </param> + <param> + <key>ant28</key> + <value></value> + </param> + <param> + <key>bb_gain28</key> + <value>20</value> + </param> + <param> + <key>bw28</key> + <value>0</value> + </param> + <param> + <key>corr28</key> + <value>0</value> + </param> + <param> + <key>freq28</key> + <value>100e6</value> + </param> + <param> + <key>if_gain28</key> + <value>20</value> + </param> + <param> + <key>gain28</key> + <value>10</value> + </param> + <param> + <key>ant29</key> + <value></value> + </param> + <param> + <key>bb_gain29</key> + <value>20</value> + </param> + <param> + <key>bw29</key> + <value>0</value> + </param> + <param> + <key>corr29</key> + <value>0</value> + </param> + <param> + <key>freq29</key> + <value>100e6</value> + </param> + <param> + <key>if_gain29</key> + <value>20</value> + </param> + <param> + <key>gain29</key> + <value>10</value> + </param> + <param> + <key>ant2</key> + <value></value> + </param> + <param> + <key>bb_gain2</key> + <value>20</value> + </param> + <param> + <key>bw2</key> + <value>0</value> + </param> + <param> + <key>corr2</key> + <value>0</value> + </param> + <param> + <key>freq2</key> + <value>100e6</value> + </param> + <param> + <key>if_gain2</key> + <value>20</value> + </param> + <param> + <key>gain2</key> + <value>10</value> + </param> + <param> + <key>ant30</key> + <value></value> + </param> + <param> + <key>bb_gain30</key> + <value>20</value> + </param> + <param> + <key>bw30</key> + <value>0</value> + </param> + <param> + <key>corr30</key> + <value>0</value> + </param> + <param> + <key>freq30</key> + <value>100e6</value> + </param> + <param> + <key>if_gain30</key> + <value>20</value> + </param> + <param> + <key>gain30</key> + <value>10</value> + </param> + <param> + <key>ant31</key> + <value></value> + </param> + <param> + <key>bb_gain31</key> + <value>20</value> + </param> + <param> + <key>bw31</key> + <value>0</value> + </param> + <param> + <key>corr31</key> + <value>0</value> + </param> + <param> + <key>freq31</key> + <value>100e6</value> + </param> + <param> + <key>if_gain31</key> + <value>20</value> + </param> + <param> + <key>gain31</key> + <value>10</value> + </param> + <param> + <key>ant3</key> + <value></value> + </param> + <param> + <key>bb_gain3</key> + <value>20</value> + </param> + <param> + <key>bw3</key> + <value>0</value> + </param> + <param> + <key>corr3</key> + <value>0</value> + </param> + <param> + <key>freq3</key> + <value>100e6</value> + </param> + <param> + <key>if_gain3</key> + <value>20</value> + </param> + <param> + <key>gain3</key> + <value>10</value> + </param> + <param> + <key>ant4</key> + <value></value> + </param> + <param> + <key>bb_gain4</key> + <value>20</value> + </param> + <param> + <key>bw4</key> + <value>0</value> + </param> + <param> + <key>corr4</key> + <value>0</value> + </param> + <param> + <key>freq4</key> + <value>100e6</value> + </param> + <param> + <key>if_gain4</key> + <value>20</value> + </param> + <param> + <key>gain4</key> + <value>10</value> + </param> + <param> + <key>ant5</key> + <value></value> + </param> + <param> + <key>bb_gain5</key> + <value>20</value> + </param> + <param> + <key>bw5</key> + <value>0</value> + </param> + <param> + <key>corr5</key> + <value>0</value> + </param> + <param> + <key>freq5</key> + <value>100e6</value> + </param> + <param> + <key>if_gain5</key> + <value>20</value> + </param> + <param> + <key>gain5</key> + <value>10</value> + </param> + <param> + <key>ant6</key> + <value></value> + </param> + <param> + <key>bb_gain6</key> + <value>20</value> + </param> + <param> + <key>bw6</key> + <value>0</value> + </param> + <param> + <key>corr6</key> + <value>0</value> + </param> + <param> + <key>freq6</key> + <value>100e6</value> + </param> + <param> + <key>if_gain6</key> + <value>20</value> + </param> + <param> + <key>gain6</key> + <value>10</value> + </param> + <param> + <key>ant7</key> + <value></value> + </param> + <param> + <key>bb_gain7</key> + <value>20</value> + </param> + <param> + <key>bw7</key> + <value>0</value> + </param> + <param> + <key>corr7</key> + <value>0</value> + </param> + <param> + <key>freq7</key> + <value>100e6</value> + </param> + <param> + <key>if_gain7</key> + <value>20</value> + </param> + <param> + <key>gain7</key> + <value>10</value> + </param> + <param> + <key>ant8</key> + <value></value> + </param> + <param> + <key>bb_gain8</key> + <value>20</value> + </param> + <param> + <key>bw8</key> + <value>0</value> + </param> + <param> + <key>corr8</key> + <value>0</value> + </param> + <param> + <key>freq8</key> + <value>100e6</value> + </param> + <param> + <key>if_gain8</key> + <value>20</value> + </param> + <param> + <key>gain8</key> + <value>10</value> + </param> + <param> + <key>ant9</key> + <value></value> + </param> + <param> + <key>bb_gain9</key> + <value>20</value> + </param> + <param> + <key>bw9</key> + <value>0</value> + </param> + <param> + <key>corr9</key> + <value>0</value> + </param> + <param> + <key>freq9</key> + <value>100e6</value> + </param> + <param> + <key>if_gain9</key> + <value>20</value> + </param> + <param> + <key>gain9</key> + <value>10</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>args</key> + <value>bladerf=0,buffers=128,buflen=32768</value> + </param> + <param> + <key>_enabled</key> + <value>0</value> + </param> + <param> + <key>_coordinate</key> + <value>(1064, 211)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>osmosdr_sink_0</value> + </param> + <param> + <key>type</key> + <value>fc32</value> + </param> + <param> + <key>clock_source0</key> + <value></value> + </param> + <param> + <key>time_source0</key> + <value></value> + </param> + <param> + <key>clock_source1</key> + <value></value> + </param> + <param> + <key>time_source1</key> + <value></value> + </param> + <param> + <key>clock_source2</key> + <value></value> + </param> + <param> + <key>time_source2</key> + <value></value> + </param> + <param> + <key>clock_source3</key> + <value></value> + </param> + <param> + <key>time_source3</key> + <value></value> + </param> + <param> + <key>clock_source4</key> + <value></value> + </param> + <param> + <key>time_source4</key> + <value></value> + </param> + <param> + <key>clock_source5</key> + <value></value> + </param> + <param> + <key>time_source5</key> + <value></value> + </param> + <param> + <key>clock_source6</key> + <value></value> + </param> + <param> + <key>time_source6</key> + <value></value> + </param> + <param> + <key>clock_source7</key> + <value></value> + </param> + <param> + <key>time_source7</key> + <value></value> + </param> + <param> + <key>nchan</key> + <value>1</value> + </param> + <param> + <key>num_mboards</key> + <value>1</value> + </param> + <param> + <key>sample_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>sync</key> + <value></value> + </param> + </block> + <block> + <key>trellis_encoder_xx</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>blocklength</key> + <value>0</value> + </param> + <param> + <key>blockwise</key> + <value>False</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>fsm_args</key> + <value>1, 2, (0171, 0133)</value> + </param> + <param> + <key>_coordinate</key> + <value>(176, 227)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>trellis_encoder_xx_0</value> + </param> + <param> + <key>init_state</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>type</key> + <value>bb</value> + </param> + </block> + <block> + <key>uhd_usrp_sink</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>ant0</key> + <value></value> + </param> + <param> + <key>bw0</key> + <value>0</value> + </param> + <param> + <key>center_freq0</key> + <value>uhd.tune_request(frequency, ((symbol_rate * 1.35) / 2 ) + 1e5)</value> + </param> + <param> + <key>norm_gain0</key> + <value>False</value> + </param> + <param> + <key>gain0</key> + <value>60</value> + </param> + <param> + <key>ant10</key> + <value></value> + </param> + <param> + <key>bw10</key> + <value>0</value> + </param> + <param> + <key>center_freq10</key> + <value>0</value> + </param> + <param> + <key>norm_gain10</key> + <value>False</value> + </param> + <param> + <key>gain10</key> + <value>0</value> + </param> + <param> + <key>ant11</key> + <value></value> + </param> + <param> + <key>bw11</key> + <value>0</value> + </param> + <param> + <key>center_freq11</key> + <value>0</value> + </param> + <param> + <key>norm_gain11</key> + <value>False</value> + </param> + <param> + <key>gain11</key> + <value>0</value> + </param> + <param> + <key>ant12</key> + <value></value> + </param> + <param> + <key>bw12</key> + <value>0</value> + </param> + <param> + <key>center_freq12</key> + <value>0</value> + </param> + <param> + <key>norm_gain12</key> + <value>False</value> + </param> + <param> + <key>gain12</key> + <value>0</value> + </param> + <param> + <key>ant13</key> + <value></value> + </param> + <param> + <key>bw13</key> + <value>0</value> + </param> + <param> + <key>center_freq13</key> + <value>0</value> + </param> + <param> + <key>norm_gain13</key> + <value>False</value> + </param> + <param> + <key>gain13</key> + <value>0</value> + </param> + <param> + <key>ant14</key> + <value></value> + </param> + <param> + <key>bw14</key> + <value>0</value> + </param> + <param> + <key>center_freq14</key> + <value>0</value> + </param> + <param> + <key>norm_gain14</key> + <value>False</value> + </param> + <param> + <key>gain14</key> + <value>0</value> + </param> + <param> + <key>ant15</key> + <value></value> + </param> + <param> + <key>bw15</key> + <value>0</value> + </param> + <param> + <key>center_freq15</key> + <value>0</value> + </param> + <param> + <key>norm_gain15</key> + <value>False</value> + </param> + <param> + <key>gain15</key> + <value>0</value> + </param> + <param> + <key>ant16</key> + <value></value> + </param> + <param> + <key>bw16</key> + <value>0</value> + </param> + <param> + <key>center_freq16</key> + <value>0</value> + </param> + <param> + <key>norm_gain16</key> + <value>False</value> + </param> + <param> + <key>gain16</key> + <value>0</value> + </param> + <param> + <key>ant17</key> + <value></value> + </param> + <param> + <key>bw17</key> + <value>0</value> + </param> + <param> + <key>center_freq17</key> + <value>0</value> + </param> + <param> + <key>norm_gain17</key> + <value>False</value> + </param> + <param> + <key>gain17</key> + <value>0</value> + </param> + <param> + <key>ant18</key> + <value></value> + </param> + <param> + <key>bw18</key> + <value>0</value> + </param> + <param> + <key>center_freq18</key> + <value>0</value> + </param> + <param> + <key>norm_gain18</key> + <value>False</value> + </param> + <param> + <key>gain18</key> + <value>0</value> + </param> + <param> + <key>ant19</key> + <value></value> + </param> + <param> + <key>bw19</key> + <value>0</value> + </param> + <param> + <key>center_freq19</key> + <value>0</value> + </param> + <param> + <key>norm_gain19</key> + <value>False</value> + </param> + <param> + <key>gain19</key> + <value>0</value> + </param> + <param> + <key>ant1</key> + <value></value> + </param> + <param> + <key>bw1</key> + <value>0</value> + </param> + <param> + <key>center_freq1</key> + <value>0</value> + </param> + <param> + <key>norm_gain1</key> + <value>False</value> + </param> + <param> + <key>gain1</key> + <value>0</value> + </param> + <param> + <key>ant20</key> + <value></value> + </param> + <param> + <key>bw20</key> + <value>0</value> + </param> + <param> + <key>center_freq20</key> + <value>0</value> + </param> + <param> + <key>norm_gain20</key> + <value>False</value> + </param> + <param> + <key>gain20</key> + <value>0</value> + </param> + <param> + <key>ant21</key> + <value></value> + </param> + <param> + <key>bw21</key> + <value>0</value> + </param> + <param> + <key>center_freq21</key> + <value>0</value> + </param> + <param> + <key>norm_gain21</key> + <value>False</value> + </param> + <param> + <key>gain21</key> + <value>0</value> + </param> + <param> + <key>ant22</key> + <value></value> + </param> + <param> + <key>bw22</key> + <value>0</value> + </param> + <param> + <key>center_freq22</key> + <value>0</value> + </param> + <param> + <key>norm_gain22</key> + <value>False</value> + </param> + <param> + <key>gain22</key> + <value>0</value> + </param> + <param> + <key>ant23</key> + <value></value> + </param> + <param> + <key>bw23</key> + <value>0</value> + </param> + <param> + <key>center_freq23</key> + <value>0</value> + </param> + <param> + <key>norm_gain23</key> + <value>False</value> + </param> + <param> + <key>gain23</key> + <value>0</value> + </param> + <param> + <key>ant24</key> + <value></value> + </param> + <param> + <key>bw24</key> + <value>0</value> + </param> + <param> + <key>center_freq24</key> + <value>0</value> + </param> + <param> + <key>norm_gain24</key> + <value>False</value> + </param> + <param> + <key>gain24</key> + <value>0</value> + </param> + <param> + <key>ant25</key> + <value></value> + </param> + <param> + <key>bw25</key> + <value>0</value> + </param> + <param> + <key>center_freq25</key> + <value>0</value> + </param> + <param> + <key>norm_gain25</key> + <value>False</value> + </param> + <param> + <key>gain25</key> + <value>0</value> + </param> + <param> + <key>ant26</key> + <value></value> + </param> + <param> + <key>bw26</key> + <value>0</value> + </param> + <param> + <key>center_freq26</key> + <value>0</value> + </param> + <param> + <key>norm_gain26</key> + <value>False</value> + </param> + <param> + <key>gain26</key> + <value>0</value> + </param> + <param> + <key>ant27</key> + <value></value> + </param> + <param> + <key>bw27</key> + <value>0</value> + </param> + <param> + <key>center_freq27</key> + <value>0</value> + </param> + <param> + <key>norm_gain27</key> + <value>False</value> + </param> + <param> + <key>gain27</key> + <value>0</value> + </param> + <param> + <key>ant28</key> + <value></value> + </param> + <param> + <key>bw28</key> + <value>0</value> + </param> + <param> + <key>center_freq28</key> + <value>0</value> + </param> + <param> + <key>norm_gain28</key> + <value>False</value> + </param> + <param> + <key>gain28</key> + <value>0</value> + </param> + <param> + <key>ant29</key> + <value></value> + </param> + <param> + <key>bw29</key> + <value>0</value> + </param> + <param> + <key>center_freq29</key> + <value>0</value> + </param> + <param> + <key>norm_gain29</key> + <value>False</value> + </param> + <param> + <key>gain29</key> + <value>0</value> + </param> + <param> + <key>ant2</key> + <value></value> + </param> + <param> + <key>bw2</key> + <value>0</value> + </param> + <param> + <key>center_freq2</key> + <value>0</value> + </param> + <param> + <key>norm_gain2</key> + <value>False</value> + </param> + <param> + <key>gain2</key> + <value>0</value> + </param> + <param> + <key>ant30</key> + <value></value> + </param> + <param> + <key>bw30</key> + <value>0</value> + </param> + <param> + <key>center_freq30</key> + <value>0</value> + </param> + <param> + <key>norm_gain30</key> + <value>False</value> + </param> + <param> + <key>gain30</key> + <value>0</value> + </param> + <param> + <key>ant31</key> + <value></value> + </param> + <param> + <key>bw31</key> + <value>0</value> + </param> + <param> + <key>center_freq31</key> + <value>0</value> + </param> + <param> + <key>norm_gain31</key> + <value>False</value> + </param> + <param> + <key>gain31</key> + <value>0</value> + </param> + <param> + <key>ant3</key> + <value></value> + </param> + <param> + <key>bw3</key> + <value>0</value> + </param> + <param> + <key>center_freq3</key> + <value>0</value> + </param> + <param> + <key>norm_gain3</key> + <value>False</value> + </param> + <param> + <key>gain3</key> + <value>0</value> + </param> + <param> + <key>ant4</key> + <value></value> + </param> + <param> + <key>bw4</key> + <value>0</value> + </param> + <param> + <key>center_freq4</key> + <value>0</value> + </param> + <param> + <key>norm_gain4</key> + <value>False</value> + </param> + <param> + <key>gain4</key> + <value>0</value> + </param> + <param> + <key>ant5</key> + <value></value> + </param> + <param> + <key>bw5</key> + <value>0</value> + </param> + <param> + <key>center_freq5</key> + <value>0</value> + </param> + <param> + <key>norm_gain5</key> + <value>False</value> + </param> + <param> + <key>gain5</key> + <value>0</value> + </param> + <param> + <key>ant6</key> + <value></value> + </param> + <param> + <key>bw6</key> + <value>0</value> + </param> + <param> + <key>center_freq6</key> + <value>0</value> + </param> + <param> + <key>norm_gain6</key> + <value>False</value> + </param> + <param> + <key>gain6</key> + <value>0</value> + </param> + <param> + <key>ant7</key> + <value></value> + </param> + <param> + <key>bw7</key> + <value>0</value> + </param> + <param> + <key>center_freq7</key> + <value>0</value> + </param> + <param> + <key>norm_gain7</key> + <value>False</value> + </param> + <param> + <key>gain7</key> + <value>0</value> + </param> + <param> + <key>ant8</key> + <value></value> + </param> + <param> + <key>bw8</key> + <value>0</value> + </param> + <param> + <key>center_freq8</key> + <value>0</value> + </param> + <param> + <key>norm_gain8</key> + <value>False</value> + </param> + <param> + <key>gain8</key> + <value>0</value> + </param> + <param> + <key>ant9</key> + <value></value> + </param> + <param> + <key>bw9</key> + <value>0</value> + </param> + <param> + <key>center_freq9</key> + <value>0</value> + </param> + <param> + <key>norm_gain9</key> + <value>False</value> + </param> + <param> + <key>gain9</key> + <value>0</value> + </param> + <param> + <key>clock_rate</key> + <value>0.0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>dev_addr</key> + <value>"send_frame_size=65536,num_send_frames=256,master_clock_rate=" + str(samp_rate*2)</value> + </param> + <param> + <key>dev_args</key> + <value>""</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(1064, 403)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>uhd_usrp_sink_0_0</value> + </param> + <param> + <key>type</key> + <value>fc32</value> + </param> + <param> + <key>clock_source0</key> + <value></value> + </param> + <param> + <key>sd_spec0</key> + <value></value> + </param> + <param> + <key>time_source0</key> + <value></value> + </param> + <param> + <key>clock_source1</key> + <value></value> + </param> + <param> + <key>sd_spec1</key> + <value></value> + </param> + <param> + <key>time_source1</key> + <value></value> + </param> + <param> + <key>clock_source2</key> + <value></value> + </param> + <param> + <key>sd_spec2</key> + <value></value> + </param> + <param> + <key>time_source2</key> + <value></value> + </param> + <param> + <key>clock_source3</key> + <value></value> + </param> + <param> + <key>sd_spec3</key> + <value></value> + </param> + <param> + <key>time_source3</key> + <value></value> + </param> + <param> + <key>clock_source4</key> + <value></value> + </param> + <param> + <key>sd_spec4</key> + <value></value> + </param> + <param> + <key>time_source4</key> + <value></value> + </param> + <param> + <key>clock_source5</key> + <value></value> + </param> + <param> + <key>sd_spec5</key> + <value></value> + </param> + <param> + <key>time_source5</key> + <value></value> + </param> + <param> + <key>clock_source6</key> + <value></value> + </param> + <param> + <key>sd_spec6</key> + <value></value> + </param> + <param> + <key>time_source6</key> + <value></value> + </param> + <param> + <key>clock_source7</key> + <value></value> + </param> + <param> + <key>sd_spec7</key> + <value></value> + </param> + <param> + <key>time_source7</key> + <value></value> + </param> + <param> + <key>nchan</key> + <value>1</value> + </param> + <param> + <key>num_mboards</key> + <value>1</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>hide_cmd_port</key> + <value>False</value> + </param> + <param> + <key>stream_args</key> + <value></value> + </param> + <param> + <key>stream_chans</key> + <value>[]</value> + </param> + <param> + <key>sync</key> + <value></value> + </param> + <param> + <key>len_tag_name</key> + <value></value> + </param> + <param> + <key>otw</key> + <value></value> + </param> + </block> + <block> + <key>wxgui_fftsink2</key> + <param> + <key>avg_alpha</key> + <value>0.13333</value> + </param> + <param> + <key>average</key> + <value>True</value> + </param> + <param> + <key>baseband_freq</key> + <value>frequency</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>fft_size</key> + <value>1024</value> + </param> + <param> + <key>freqvar</key> + <value>None</value> + </param> + <param> + <key>_coordinate</key> + <value>(848, 195)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>id</key> + <value>wxgui_fftsink2_0</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>peak_hold</key> + <value>False</value> + </param> + <param> + <key>ref_level</key> + <value>0</value> + </param> + <param> + <key>ref_scale</key> + <value>2.0</value> + </param> + <param> + <key>fft_rate</key> + <value>15</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>title</key> + <value>FFT Plot</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>win_size</key> + <value></value> + </param> + <param> + <key>win</key> + <value>None</value> + </param> + <param> + <key>y_divs</key> + <value>10</value> + </param> + <param> + <key>y_per_div</key> + <value>10</value> + </param> + </block> + <connection> + <source_block_id>blocks_file_source_0</source_block_id> + <sink_block_id>dtv_dvbt_energy_dispersal_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_pack_k_bits_bb_0</source_block_id> + <sink_block_id>dtv_dvbs2_modulator_bc_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_packed_to_unpacked_xx_0</source_block_id> + <sink_block_id>trellis_encoder_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_unpack_k_bits_bb_0</source_block_id> + <sink_block_id>fec_puncture_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbs2_modulator_bc_0</source_block_id> + <sink_block_id>fft_filter_xxx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_convolutional_interleaver_0</source_block_id> + <sink_block_id>blocks_packed_to_unpacked_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_energy_dispersal_0</source_block_id> + <sink_block_id>dtv_dvbt_reed_solomon_enc_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_reed_solomon_enc_0</source_block_id> + <sink_block_id>dtv_dvbt_convolutional_interleaver_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>fec_puncture_xx_0</source_block_id> + <sink_block_id>blocks_pack_k_bits_bb_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>fft_filter_xxx_0</source_block_id> + <sink_block_id>blocks_file_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>fft_filter_xxx_0</source_block_id> + <sink_block_id>osmosdr_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>fft_filter_xxx_0</source_block_id> + <sink_block_id>uhd_usrp_sink_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>fft_filter_xxx_0</source_block_id> + <sink_block_id>wxgui_fftsink2_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>trellis_encoder_xx_0</source_block_id> + <sink_block_id>blocks_unpack_k_bits_bb_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/gr-dtv/grc/CMakeLists.txt b/gr-dtv/grc/CMakeLists.txt index 2fed81ab12..a1386c5adf 100644 --- a/gr-dtv/grc/CMakeLists.txt +++ b/gr-dtv/grc/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2014,2015 Free Software Foundation, Inc. +# Copyright 2014,2015,2016 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -68,6 +68,11 @@ install(FILES dtv_dvbt_convolutional_deinterleaver.xml dtv_dvbt_reed_solomon_dec.xml dtv_dvbt_energy_descramble.xml + dtv_catv_transport_framing_enc_bb.xml + dtv_catv_reed_solomon_enc_bb.xml + dtv_catv_randomizer_bb.xml + dtv_catv_frame_sync_enc_bb.xml + dtv_catv_trellis_enc_bb.xml DESTINATION ${GRC_BLOCKS_DIR} COMPONENT "dtv_python" ) diff --git a/gr-dtv/grc/dtv_block_tree.xml b/gr-dtv/grc/dtv_block_tree.xml index 32c8974531..fba33852c0 100644 --- a/gr-dtv/grc/dtv_block_tree.xml +++ b/gr-dtv/grc/dtv_block_tree.xml @@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright 2014,2015 Free Software Foundation, Inc. + Copyright 2014,2015,2016 Free Software Foundation, Inc. This file is part of GNU Radio @@ -94,5 +94,13 @@ <block>dtv_dvbt_reed_solomon_dec</block> <block>dtv_dvbt_energy_descramble</block> </cat> + <cat> + <name>ITU-T J.83B</name> + <block>dtv_catv_transport_framing_enc_bb</block> + <block>dtv_catv_reed_solomon_enc_bb</block> + <block>dtv_catv_randomizer_bb</block> + <block>dtv_catv_frame_sync_enc_bb</block> + <block>dtv_catv_trellis_enc_bb</block> + </cat> </cat> </cat> diff --git a/gr-dtv/grc/dtv_catv_frame_sync_enc_bb.xml b/gr-dtv/grc/dtv_catv_frame_sync_enc_bb.xml new file mode 100644 index 0000000000..e7c1392960 --- /dev/null +++ b/gr-dtv/grc/dtv_catv_frame_sync_enc_bb.xml @@ -0,0 +1,26 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Frame Sync Encoder +################################################### + --> +<block> + <name>Frame Sync Encoder</name> + <key>dtv_catv_frame_sync_enc_bb</key> + <import>from gnuradio import dtv</import> + <make>dtv.catv_frame_sync_enc_bb($ctrlword)</make> + <param> + <name>Control Word</name> + <key>ctrlword</key> + <value>6</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/gr-dtv/grc/dtv_catv_randomizer_bb.xml b/gr-dtv/grc/dtv_catv_randomizer_bb.xml new file mode 100644 index 0000000000..ca4787d786 --- /dev/null +++ b/gr-dtv/grc/dtv_catv_randomizer_bb.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Randomizer +################################################### + --> +<block> + <name>Randomizer</name> + <key>dtv_catv_randomizer_bb</key> + <import>from gnuradio import dtv</import> + <make>dtv.catv_randomizer_bb()</make> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/gr-dtv/grc/dtv_catv_reed_solomon_enc_bb.xml b/gr-dtv/grc/dtv_catv_reed_solomon_enc_bb.xml new file mode 100644 index 0000000000..a5dfdc2a5a --- /dev/null +++ b/gr-dtv/grc/dtv_catv_reed_solomon_enc_bb.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Reed Solomon Encoder +################################################### + --> +<block> + <name>Reed-Solomon Encoder</name> + <key>dtv_catv_reed_solomon_enc_bb</key> + <import>from gnuradio import dtv</import> + <make>dtv.catv_reed_solomon_enc_bb()</make> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/gr-dtv/grc/dtv_catv_transport_framing_enc_bb.xml b/gr-dtv/grc/dtv_catv_transport_framing_enc_bb.xml new file mode 100644 index 0000000000..d0b6bf382b --- /dev/null +++ b/gr-dtv/grc/dtv_catv_transport_framing_enc_bb.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Transport Framing Encoder +################################################### + --> +<block> + <name>Transport Framing Encoder</name> + <key>dtv_catv_transport_framing_enc_bb</key> + <import>from gnuradio import dtv</import> + <make>dtv.catv_transport_framing_enc_bb()</make> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/gr-dtv/grc/dtv_catv_trellis_enc_bb.xml b/gr-dtv/grc/dtv_catv_trellis_enc_bb.xml new file mode 100644 index 0000000000..a96d60c895 --- /dev/null +++ b/gr-dtv/grc/dtv_catv_trellis_enc_bb.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Trellis Encoder +################################################### + --> +<block> + <name>Trellis Encoder</name> + <key>dtv_catv_trellis_enc_bb</key> + <import>from gnuradio import dtv</import> + <make>dtv.catv_trellis_enc_bb()</make> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/gr-dtv/grc/dtv_dvbs2_modulator_bc.xml b/gr-dtv/grc/dtv_dvbs2_modulator_bc.xml index 1f7fef09a3..8de645d585 100644 --- a/gr-dtv/grc/dtv_dvbs2_modulator_bc.xml +++ b/gr-dtv/grc/dtv_dvbs2_modulator_bc.xml @@ -8,7 +8,7 @@ <name>DVB-S2X Modulator</name> <key>dtv_dvbs2_modulator_bc</key> <import>from gnuradio import dtv</import> - <make>dtv.dvbs2_modulator_bc($framesize.val, $rate.val, $constellation.val)</make> + <make>dtv.dvbs2_modulator_bc($framesize.val, $rate.val, $constellation.val, $interpolation.val)</make> <param> <name>FECFRAME size</name> <key>framesize</key> @@ -253,6 +253,26 @@ <key>MOD_256APSK</key> <opt>val:dtv.MOD_256APSK</opt> </option> + <option> + <name>64QAM</name> + <key>MOD_64QAM</key> + <opt>val:dtv.MOD_64QAM</opt> + </option> + </param> + <param> + <name>2X Interpolation</name> + <key>interpolation</key> + <type>enum</type> + <option> + <name>Off</name> + <key>INTERPOLATION_OFF</key> + <opt>val:dtv.INTERPOLATION_OFF</opt> + </option> + <option> + <name>On</name> + <key>INTERPOLATION_ON</key> + <opt>val:dtv.INTERPOLATION_ON</opt> + </option> </param> <sink> <name>in</name> diff --git a/gr-dtv/include/gnuradio/dtv/CMakeLists.txt b/gr-dtv/include/gnuradio/dtv/CMakeLists.txt index 4232ff7065..620dd55879 100644 --- a/gr-dtv/include/gnuradio/dtv/CMakeLists.txt +++ b/gr-dtv/include/gnuradio/dtv/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2014,2015 Free Software Foundation, Inc. +# Copyright 2014,2015,2016 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -74,6 +74,11 @@ install(FILES dvbt_convolutional_deinterleaver.h dvbt_reed_solomon_dec.h dvbt_energy_descramble.h + catv_transport_framing_enc_bb.h + catv_reed_solomon_enc_bb.h + catv_randomizer_bb.h + catv_frame_sync_enc_bb.h + catv_trellis_enc_bb.h DESTINATION ${GR_INCLUDE_DIR}/gnuradio/dtv COMPONENT "dtv_devel" diff --git a/gr-dtv/include/gnuradio/dtv/atsc_equalizer.h b/gr-dtv/include/gnuradio/dtv/atsc_equalizer.h index 3fe101ac25..17f2e8f768 100644 --- a/gr-dtv/include/gnuradio/dtv/atsc_equalizer.h +++ b/gr-dtv/include/gnuradio/dtv/atsc_equalizer.h @@ -45,6 +45,9 @@ namespace gr { * \brief Make a new instance of gr::dtv::atsc_equalizer. */ static sptr make(); + + virtual std::vector<float> taps() const = 0; + virtual std::vector<float> data() const = 0; }; } /* namespace dtv */ diff --git a/gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h b/gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h index 92eb263e5d..c2b7d0defa 100644 --- a/gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h +++ b/gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h @@ -42,6 +42,21 @@ namespace gr { typedef boost::shared_ptr<atsc_rs_decoder> sptr; /*! + * Returns the number of errors corrected by the decoder. + */ + virtual int num_errors_corrected() const = 0; + + /*! + * Returns the number of bad packets rejected by the decoder. + */ + virtual int num_bad_packets() const = 0; + + /*! + * Returns the total number of packets seen by the decoder. + */ + virtual int num_packets() const = 0; + + /*! * \brief Make a new instance of gr::dtv::atsc_rs_decoder. */ static sptr make(); diff --git a/gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h b/gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h index a4c18c39da..8efece4c43 100644 --- a/gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h +++ b/gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h @@ -45,6 +45,12 @@ namespace gr { * \brief Make a new instance of gr::dtv::atsc_viterbi_decoder. */ static sptr make(); + + /*! + * For each decoder, returns the current best state of the + * decoding metrics. + */ + virtual std::vector<float> decoder_metrics() const = 0; }; } /* namespace dtv */ diff --git a/gr-dtv/include/gnuradio/dtv/catv_frame_sync_enc_bb.h b/gr-dtv/include/gnuradio/dtv/catv_frame_sync_enc_bb.h new file mode 100644 index 0000000000..799a2d3c55 --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/catv_frame_sync_enc_bb.h @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DTV_CATV_FRAME_SYNC_ENC_BB_H +#define INCLUDED_DTV_CATV_FRAME_SYNC_ENC_BB_H + +#include <gnuradio/dtv/api.h> +#include <gnuradio/block.h> + +namespace gr { + namespace dtv { + + /*! + * \brief Frame Sync Encoder. Adds a 42-bit frame sync pattern with control word. + * \ingroup dtv + * + * Input: Scrambled FEC Frame packets of 60 * 128 7-bit symbols.\n + * Output: Scrambled FEC Frame packets of 60 * 128 7-bit symbols with 42-bit FSYNC word. + */ + class DTV_API catv_frame_sync_enc_bb : virtual public gr::block + { + public: + typedef boost::shared_ptr<catv_frame_sync_enc_bb> sptr; + + /*! + * \brief Create an ITU-T J.83B Frame Sync Encoder. + * + * \param ctrlword convolutional interleaver control word. + */ + static sptr make(int ctrlword); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_CATV_FRAME_SYNC_ENC_BB_H */ + diff --git a/gr-dtv/include/gnuradio/dtv/catv_randomizer_bb.h b/gr-dtv/include/gnuradio/dtv/catv_randomizer_bb.h new file mode 100644 index 0000000000..83230b8167 --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/catv_randomizer_bb.h @@ -0,0 +1,53 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DTV_CATV_RANDOMIZER_BB_H +#define INCLUDED_DTV_CATV_RANDOMIZER_BB_H + +#include <gnuradio/dtv/api.h> +#include <gnuradio/sync_block.h> + +namespace gr { + namespace dtv { + + /*! + * \brief Randomizer, x^3 + x + alpha^3, 7-bit symbols. + * \ingroup dtv + * + * Input: Interleaved MPEG-2 + RS parity bitstream packets of 128 7-bit symbols.\n + * Output: Scrambled FEC Frame packets of 60 * 128 7-bit symbols. + */ + class DTV_API catv_randomizer_bb : virtual public gr::sync_block + { + public: + typedef boost::shared_ptr<catv_randomizer_bb> sptr; + + /*! + * \brief Create an ITU-T J.83B randomizer. + * + */ + static sptr make(); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_CATV_RANDOMIZER_BB_H */ + diff --git a/gr-dtv/include/gnuradio/dtv/catv_reed_solomon_enc_bb.h b/gr-dtv/include/gnuradio/dtv/catv_reed_solomon_enc_bb.h new file mode 100644 index 0000000000..b661f0da7f --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/catv_reed_solomon_enc_bb.h @@ -0,0 +1,53 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DTV_CATV_REED_SOLOMON_ENC_BB_H +#define INCLUDED_DTV_CATV_REED_SOLOMON_ENC_BB_H + +#include <gnuradio/dtv/api.h> +#include <gnuradio/block.h> + +namespace gr { + namespace dtv { + + /*! + * \brief Reed Solomon Encoder, t=3, (128,122), 7-bit symbols. + * \ingroup dtv + * + * Input: MPEG-2 bitstream packets of 122 7-bit symbols.\n + * Output: MPEG-2 + RS parity bitstream packets of 128 7-bit symbols. + */ + class DTV_API catv_reed_solomon_enc_bb : virtual public gr::block + { + public: + typedef boost::shared_ptr<catv_reed_solomon_enc_bb> sptr; + + /*! + * \brief Create an ITU-T J.83B Reed Solomon encoder. + * + */ + static sptr make(); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_CATV_REED_SOLOMON_ENC_BB_H */ + diff --git a/gr-dtv/include/gnuradio/dtv/catv_transport_framing_enc_bb.h b/gr-dtv/include/gnuradio/dtv/catv_transport_framing_enc_bb.h new file mode 100644 index 0000000000..7df100d990 --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/catv_transport_framing_enc_bb.h @@ -0,0 +1,53 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DTV_CATV_TRANSPORT_FRAMING_ENC_BB_H +#define INCLUDED_DTV_CATV_TRANSPORT_FRAMING_ENC_BB_H + +#include <gnuradio/dtv/api.h> +#include <gnuradio/sync_block.h> + +namespace gr { + namespace dtv { + + /*! + * \brief Transport Framing Encoder. Adds a parity checksum to MPEG-2 packets. + * \ingroup dtv + * + * Input: MPEG-2 Transport Stream.\n + * Output: MPEG-2 Transport Stream with parity checksum byte. + */ + class DTV_API catv_transport_framing_enc_bb : virtual public gr::sync_block + { + public: + typedef boost::shared_ptr<catv_transport_framing_enc_bb> sptr; + + /*! + * \brief Create an ITU-T J.83B Transport Framing Encoder. + * + */ + static sptr make(); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_CATV_TRANSPORT_FRAMING_ENC_BB_H */ + diff --git a/gr-dtv/include/gnuradio/dtv/catv_trellis_enc_bb.h b/gr-dtv/include/gnuradio/dtv/catv_trellis_enc_bb.h new file mode 100644 index 0000000000..aa6cec1703 --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/catv_trellis_enc_bb.h @@ -0,0 +1,53 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DTV_CATV_TRELLIS_ENC_BB_H +#define INCLUDED_DTV_CATV_TRELLIS_ENC_BB_H + +#include <gnuradio/dtv/api.h> +#include <gnuradio/block.h> + +namespace gr { + namespace dtv { + + /*! + * \brief Trellis Encoder. 14/15 code rate. + * \ingroup dtv + * + * Input: Scrambled FEC Frame packets of 60 * 128 7-bit symbols with 42-bit FSYNC word.\n + * Output: Four 7-bit symbols (28 bits) Trellis encoded to 30 bits (14/15 code rate). + */ + class DTV_API catv_trellis_enc_bb : virtual public gr::block + { + public: + typedef boost::shared_ptr<catv_trellis_enc_bb> sptr; + + /*! + * \brief Create an ITU-T J.83B Trellis Encoder. + * + */ + static sptr make(); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_CATV_TRELLIS_ENC_BB_H */ + diff --git a/gr-dtv/include/gnuradio/dtv/dvbs2_config.h b/gr-dtv/include/gnuradio/dtv/dvbs2_config.h index 919c7de155..079857a8cf 100644 --- a/gr-dtv/include/gnuradio/dtv/dvbs2_config.h +++ b/gr-dtv/include/gnuradio/dtv/dvbs2_config.h @@ -38,11 +38,17 @@ namespace gr { PILOTS_ON, }; + enum dvbs2_interpolation_t { + INTERPOLATION_OFF = 0, + INTERPOLATION_ON, + }; + } // namespace dtv } // namespace gr typedef gr::dtv::dvbs2_rolloff_factor_t dvbs2_rolloff_factor_t; typedef gr::dtv::dvbs2_pilots_t dvbs2_pilots_t; +typedef gr::dtv::dvbs2_interpolation_t dvbs2_interpolation_t; #endif /* INCLUDED_DTV_DVBS2_CONFIG_H */ diff --git a/gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h b/gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h index 68e5403e05..a1f2c9e6fe 100644 --- a/gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h +++ b/gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2015 Free Software Foundation, Inc. + * Copyright 2015,2016 Free Software Foundation, Inc. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ #include <gnuradio/dtv/api.h> #include <gnuradio/dtv/dvb_config.h> +#include <gnuradio/dtv/dvbs2_config.h> #include <gnuradio/block.h> namespace gr { @@ -46,8 +47,9 @@ namespace gr { * \param framesize FEC frame size (normal or short). * \param rate FEC code rate. * \param constellation DVB-S2 constellation. + * \param interpolation 2X zero stuffing interpolation (on/off). */ - static sptr make(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation); + static sptr make(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbs2_interpolation_t interpolation); }; } // namespace dtv diff --git a/gr-dtv/lib/CMakeLists.txt b/gr-dtv/lib/CMakeLists.txt index 868205c241..6ae308395d 100644 --- a/gr-dtv/lib/CMakeLists.txt +++ b/gr-dtv/lib/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2014,2015 Free Software Foundation, Inc. +# Copyright 2014,2015,2016 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -112,6 +112,11 @@ list(APPEND dtv_sources dvbt/dvbt_convolutional_deinterleaver_impl.cc dvbt/dvbt_reed_solomon_dec_impl.cc dvbt/dvbt_energy_descramble_impl.cc + catv/catv_transport_framing_enc_bb_impl.cc + catv/catv_reed_solomon_enc_bb_impl.cc + catv/catv_randomizer_bb_impl.cc + catv/catv_frame_sync_enc_bb_impl.cc + catv/catv_trellis_enc_bb_impl.cc ) if(ENABLE_GR_CTRLPORT) diff --git a/gr-dtv/lib/atsc/atsc_equalizer_impl.cc b/gr-dtv/lib/atsc/atsc_equalizer_impl.cc index c804be6dc7..de01cea6f2 100644 --- a/gr-dtv/lib/atsc/atsc_equalizer_impl.cc +++ b/gr-dtv/lib/atsc/atsc_equalizer_impl.cc @@ -28,6 +28,7 @@ #include "atsc_types.h" #include "atsc_pnXXX_impl.h" #include <gnuradio/io_signature.h> +#include <volk/volk.h> namespace gr { namespace dtv { @@ -76,23 +77,42 @@ namespace gr { init_field_sync_common(training_sequence1, 0); init_field_sync_common(training_sequence2, 1); - for (int i = 0; i < NTAPS; i++) - d_taps[i] = 0.0; + d_taps.resize(NTAPS, 0.0f); d_buff_not_filled = true; + + const int alignment_multiple = + volk_get_alignment() / sizeof(float); + set_alignment(std::max(1, alignment_multiple)); } atsc_equalizer_impl::~atsc_equalizer_impl() { } + std::vector<float> + atsc_equalizer_impl::taps() const + { + return d_taps; + } + + std::vector<float> + atsc_equalizer_impl::data() const + { + std::vector<float> ret(&data_mem2[0], &data_mem2[ATSC_DATA_SEGMENT_LENGTH-1]); + return ret; + } + void - atsc_equalizer_impl::filterN(const float *input_samples, float *output_samples, int nsamples) + atsc_equalizer_impl::filterN(const float *input_samples, + float *output_samples, + int nsamples) { for (int j = 0; j < nsamples; j++) { output_samples[j] = 0; - for(int i = 0; i < NTAPS; i++) - output_samples[j] += d_taps[i] * input_samples[j + i]; + volk_32f_x2_dot_prod_32f(&output_samples[j], + &input_samples[j], + &d_taps[0], NTAPS); } } @@ -107,14 +127,16 @@ namespace gr { for(int j = 0; j < nsamples; j++) { output_samples[j] = 0; - for( int i = 0; i < NTAPS; i++ ) - output_samples[j] += d_taps[i] * input_samples[j + i]; + volk_32f_x2_dot_prod_32f(&output_samples[j], + &input_samples[j], + &d_taps[0], NTAPS); - double e = output_samples[j] - training_pattern[j]; + float e = output_samples[j] - training_pattern[j]; // update taps... - for( int i = 0; i < NTAPS; i++ ) - d_taps[i] -= BETA * e * (double)(input_samples[j + i]); + float tmp_taps[NTAPS]; + volk_32f_s32f_multiply_32f(tmp_taps, &input_samples[j], BETA*e, NTAPS); + volk_32f_x2_subtract_32f(&d_taps[0], &d_taps[0], tmp_taps, NTAPS); } } @@ -131,8 +153,8 @@ namespace gr { int i = 0; if(d_buff_not_filled) { - for(int j = 0; j < ATSC_DATA_SEGMENT_LENGTH; j++) - data_mem[NPRETAPS + j] = in[i].data[j]; + memcpy(&data_mem[NPRETAPS], in[i].data, + ATSC_DATA_SEGMENT_LENGTH*sizeof(float)); d_flags = in[i].pli._flags; d_segno = in[i].pli._segno; d_buff_not_filled = false; @@ -141,8 +163,8 @@ namespace gr { for (; i < noutput_items; i++) { - for(int j = 0; j < NTAPS - NPRETAPS; j++) - data_mem[ATSC_DATA_SEGMENT_LENGTH + NPRETAPS + j] = in[i].data[j]; + memcpy(&data_mem[ATSC_DATA_SEGMENT_LENGTH + NPRETAPS], in[i].data, + (NTAPS - NPRETAPS)*sizeof(float)); if(d_segno == -1) { if(d_flags & 0x0010) { @@ -157,19 +179,18 @@ namespace gr { else { filterN(data_mem, data_mem2, ATSC_DATA_SEGMENT_LENGTH); - for(int j = 0; j < ATSC_DATA_SEGMENT_LENGTH; j++) - out[output_produced].data[j] = data_mem2[j]; + memcpy(out[output_produced].data, data_mem2, + ATSC_DATA_SEGMENT_LENGTH*sizeof(float)); out[output_produced].pli._flags = d_flags; out[output_produced].pli._segno = d_segno; output_produced++; } - for( int j = 0; j < NPRETAPS; j++ ) - data_mem[j] = data_mem[ATSC_DATA_SEGMENT_LENGTH + j]; - - for(int j = 0; j < ATSC_DATA_SEGMENT_LENGTH; j++) - data_mem[NPRETAPS + j] = in[i].data[j]; + memcpy(data_mem, &data_mem[ATSC_DATA_SEGMENT_LENGTH], + NPRETAPS*sizeof(float)); + memcpy(&data_mem[NPRETAPS], in[i].data, + ATSC_DATA_SEGMENT_LENGTH*sizeof(float)); d_flags = in[i].pli._flags; d_segno = in[i].pli._segno; @@ -179,5 +200,31 @@ namespace gr { return output_produced; } + void + atsc_equalizer_impl::setup_rpc() + { +#ifdef GR_CTRLPORT + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<atsc_equalizer, std::vector<float> >( + alias(), "taps", + &atsc_equalizer::taps, + pmt::make_f32vector(1,-10), + pmt::make_f32vector(1,10), + pmt::make_f32vector(1,0), + "", "Equalizer Taps", RPC_PRIVLVL_MIN, + DISPTIME))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<atsc_equalizer, std::vector<float> >( + alias(), "data", + &atsc_equalizer::data, + pmt::make_f32vector(1,-10), + pmt::make_f32vector(1,10), + pmt::make_f32vector(1,0), + "", "Post-equalizer Data", RPC_PRIVLVL_MIN, + DISPTIME))); +#endif /* GR_CTRLPORT */ + } + } /* namespace dtv */ } /* namespace gr */ diff --git a/gr-dtv/lib/atsc/atsc_equalizer_impl.h b/gr-dtv/lib/atsc/atsc_equalizer_impl.h index 6ff89ca646..75862f6408 100644 --- a/gr-dtv/lib/atsc/atsc_equalizer_impl.h +++ b/gr-dtv/lib/atsc/atsc_equalizer_impl.h @@ -46,7 +46,7 @@ namespace gr { void adaptN(const float *input_samples, const float *training_pattern, float *output_samples, int nsamples); - float d_taps[NTAPS]; + std::vector<float> d_taps; float data_mem[ATSC_DATA_SEGMENT_LENGTH + NTAPS]; // Buffer for previous data packet float data_mem2[ATSC_DATA_SEGMENT_LENGTH]; @@ -59,6 +59,11 @@ namespace gr { atsc_equalizer_impl(); ~atsc_equalizer_impl(); + void setup_rpc(); + + std::vector<float> taps() const; + std::vector<float> data() const; + virtual int general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, diff --git a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc index 7a950e716e..b8ee91a52d 100644 --- a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc +++ b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc @@ -56,9 +56,9 @@ namespace gr { { d_rs = init_rs_char(rs_init_symsize, rs_init_gfpoly, rs_init_fcr, rs_init_prim, rs_init_nroots); assert (d_rs != 0); - nerrors_corrrected_count = 0; - bad_packet_count = 0; - total_packets = 0; + d_nerrors_corrrected_count = 0; + d_bad_packet_count = 0; + d_total_packets = 0; } int atsc_rs_decoder_impl::decode (atsc_mpeg_packet_no_sync &out, const atsc_mpeg_packet_rs_encoded &in) @@ -89,6 +89,24 @@ namespace gr { } int + atsc_rs_decoder_impl::num_errors_corrected() const + { + return d_nerrors_corrrected_count; + } + + int + atsc_rs_decoder_impl::num_bad_packets() const + { + return d_bad_packet_count; + } + + int + atsc_rs_decoder_impl::num_packets() const + { + return d_total_packets; + } + + int atsc_rs_decoder_impl::work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) @@ -102,24 +120,20 @@ namespace gr { int nerrors_corrrected = decode(out[i], in[i]); out[i].pli.set_transport_error(nerrors_corrrected == -1); - if (nerrors_corrrected == -1) - bad_packet_count++; - else - nerrors_corrrected_count += nerrors_corrrected; + if (nerrors_corrrected == -1) { + d_bad_packet_count++; + d_nerrors_corrrected_count += 10; // lower bound estimate; most this RS can fix + } + else { + d_nerrors_corrrected_count += nerrors_corrrected; + } - total_packets++; + d_total_packets++; #if 0 - if (total_packets > 1000) { - // FIXME: convert to logger - std::cout << "Error rate: " - << (float)nerrors_corrrected_count/total_packets - << "\tPacket error rate: " - << (float)bad_packet_count/total_packets - << std::endl; - - nerrors_corrrected_count = 0; - bad_packet_count = 0; - total_packets = 0; + if (d_total_packets > 1000) { + GR_LOG_INFO(d_logger, boost::format("Error rate: %1%\tPacket error rate: %2%") \ + % ((float)d_nerrors_corrrected_count/(ATSC_MPEG_DATA_LENGTH*d_total_packets)) + % ((float)d_bad_packet_count/d_total_packets)); } #endif } @@ -127,5 +141,42 @@ namespace gr { return noutput_items; } + + void + atsc_rs_decoder_impl::setup_rpc() + { +#ifdef GR_CTRLPORT + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<atsc_rs_decoder, int >( + alias(), "num_errors_corrected", + &atsc_rs_decoder::num_errors_corrected, + pmt::from_long(0), + pmt::from_long(10000000), + pmt::from_long(0), + "", "Number of errors corrected", RPC_PRIVLVL_MIN, + DISPTIME))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<atsc_rs_decoder, int >( + alias(), "num_bad_packets", + &atsc_rs_decoder::num_bad_packets, + pmt::from_long(0), + pmt::from_long(10000000), + pmt::from_long(0), + "", "Number of bad packets", RPC_PRIVLVL_MIN, + DISPTIME))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<atsc_rs_decoder, int >( + alias(), "num_packets", + &atsc_rs_decoder::num_packets, + pmt::from_long(0), + pmt::from_long(10000000), + pmt::from_long(0), + "", "Number of packets", RPC_PRIVLVL_MIN, + DISPTIME))); +#endif /* GR_CTRLPORT */ + } + } /* namespace dtv */ } /* namespace gr */ diff --git a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h index 57460128dc..adbc4879a9 100644 --- a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h +++ b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h @@ -36,15 +36,22 @@ namespace gr { class atsc_rs_decoder_impl : public atsc_rs_decoder { private: - int nerrors_corrrected_count; - int bad_packet_count; - int total_packets; + int d_nerrors_corrrected_count; + int d_bad_packet_count; + int d_total_packets; + int d_total_bits; void *d_rs; public: atsc_rs_decoder_impl(); ~atsc_rs_decoder_impl(); + void setup_rpc(); + + int num_errors_corrected() const; + int num_bad_packets() const; + int num_packets() const; + /*! * Decode RS encoded packet. * \returns a count of corrected symbols, or -1 if the block was uncorrectible. diff --git a/gr-dtv/lib/atsc/atsc_single_viterbi.cc b/gr-dtv/lib/atsc/atsc_single_viterbi.cc index 385940e453..011cc0fe96 100644 --- a/gr-dtv/lib/atsc/atsc_single_viterbi.cc +++ b/gr-dtv/lib/atsc/atsc_single_viterbi.cc @@ -28,7 +28,7 @@ namespace gr { /* was_sent is a table of what symbol we get given what bit pair was sent and what state we where in [state][pair] */ - const int atsc_single_viterbi::was_sent[4][4] = { + const int atsc_single_viterbi::d_was_sent[4][4] = { {0,2,4,6}, {0,2,4,6}, {1,3,5,7}, @@ -37,7 +37,7 @@ namespace gr { /* transition_table is a table of what state we were in given current state and bit pair sent [state][pair] */ - const int atsc_single_viterbi::transition_table[4][4] = { + const int atsc_single_viterbi::d_transition_table[4][4] = { {0,2,0,2}, {2,0,2,0}, {1,3,1,3}, @@ -49,11 +49,12 @@ namespace gr { { for (unsigned int i = 0; i<2; i++) for (unsigned int j = 0; j<4; j++) { - path_metrics[i][j] = 0; - traceback[i][j] = 0; + d_path_metrics[i][j] = 0; + d_traceback[i][j] = 0; } - post_coder_state = 0; - phase = 0; + d_post_coder_state = 0; + d_phase = 0; + d_best_state_metric = 100000; } atsc_single_viterbi::atsc_single_viterbi() @@ -61,17 +62,24 @@ namespace gr { reset(); } + float + atsc_single_viterbi::best_state_metric() const + { + return d_best_state_metric; + } + char atsc_single_viterbi::decode(float input) { unsigned int best_state = 0; - float best_state_metric = 100000; + //float best_state_metric = 100000; + d_best_state_metric = 100000; /* Precompute distances from input to each possible symbol */ - float distances[8] = { (float)fabs( input + 7 ), (float)fabs( input + 5 ), - (float)fabs( input + 3 ), (float)fabs( input + 1 ), - (float)fabs( input - 1 ), (float)fabs( input - 3 ), - (float)fabs( input - 5 ), (float)fabs( input - 7 ) }; + float distances[8] = { fabsf( input + 7 ), fabsf( input + 5 ), + fabsf( input + 3 ), fabsf( input + 1 ), + fabsf( input - 1 ), fabsf( input - 3 ), + fabsf( input - 5 ), fabsf( input - 7 ) }; /* We start by iterating over all possible states */ for (unsigned int state = 0; state < 4; state++) { @@ -79,15 +87,20 @@ namespace gr { states to the state we are testing, we only need to look at the 4 paths that can be taken given the 2-bit input */ int min_metric_symb = 0; - float min_metric = distances[was_sent[state][0]] + path_metrics[phase][transition_table[state][0]]; + float min_metric = distances[d_was_sent[state][0]] + + d_path_metrics[d_phase][d_transition_table[state][0]]; + for (unsigned int symbol_sent = 1; symbol_sent < 4; symbol_sent++) - if( (distances[was_sent[state][symbol_sent]] + path_metrics[phase][transition_table[state][symbol_sent]]) < min_metric) { - min_metric = distances[was_sent[state][symbol_sent]] + path_metrics[phase][transition_table[state][symbol_sent]]; + if( (distances[d_was_sent[state][symbol_sent]] + + d_path_metrics[d_phase][d_transition_table[state][symbol_sent]]) < min_metric) { + min_metric = distances[d_was_sent[state][symbol_sent]] + + d_path_metrics[d_phase][d_transition_table[state][symbol_sent]]; min_metric_symb = symbol_sent; } - path_metrics[phase^1][state] = min_metric; - traceback[phase^1][state] = (((unsigned long long)min_metric_symb) << 62) | (traceback[phase][transition_table[state][min_metric_symb]] >> 2); + d_path_metrics[d_phase^1][state] = min_metric; + d_traceback[d_phase^1][state] = (((unsigned long long)min_metric_symb) << 62) | + (d_traceback[d_phase][d_transition_table[state][min_metric_symb]] >> 2); /* If this is the most probable state so far remember it, this only needs to be checked when we are about to output a path @@ -98,26 +111,24 @@ namespace gr { head state path will tend towards the optimal path with a probability approaching 1 in just 8 or so transitions */ - if(min_metric <= best_state_metric) { - best_state_metric = min_metric; + if(min_metric <= d_best_state_metric) { + d_best_state_metric = min_metric; best_state = state; } } - if(best_state_metric > 10000) { + if(d_best_state_metric > 10000) { for(unsigned int state = 0; state < 4; state++) - path_metrics[phase^1][state] -= best_state_metric; + d_path_metrics[d_phase^1][state] -= d_best_state_metric; } - phase ^= 1; + d_phase ^= 1; - int y2 = (0x2 & traceback[phase][best_state]) >> 1; - int x2 = y2 ^ post_coder_state; - post_coder_state = y2; + int y2 = (0x2 & d_traceback[d_phase][best_state]) >> 1; + int x2 = y2 ^ d_post_coder_state; + d_post_coder_state = y2; - return ( x2 << 1 ) | (0x1 & traceback[phase][best_state]); + return ( x2 << 1 ) | (0x1 & d_traceback[d_phase][best_state]); } } /* namespace dtv */ } /* namespace gr */ - - diff --git a/gr-dtv/lib/atsc/atsc_single_viterbi.h b/gr-dtv/lib/atsc/atsc_single_viterbi.h index 3c756c7690..9522e2eb1b 100644 --- a/gr-dtv/lib/atsc/atsc_single_viterbi.h +++ b/gr-dtv/lib/atsc/atsc_single_viterbi.h @@ -44,14 +44,17 @@ namespace gr { //! internal delay of decoder static int delay () { return TB_LEN - 1; } - protected: - static const int transition_table[4][4]; - static const int was_sent[4][4]; + float best_state_metric() const; - float path_metrics [2][4]; - unsigned long long traceback [2][4]; - unsigned char phase; - int post_coder_state; + protected: + static const int d_transition_table[4][4]; + static const int d_was_sent[4][4]; + + float d_path_metrics [2][4]; + unsigned long long d_traceback [2][4]; + unsigned char d_phase; + int d_post_coder_state; + float d_best_state_metric; }; } /* namespace dtv */ diff --git a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc index 430eb55a17..2284372dfb 100644 --- a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc +++ b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc @@ -77,6 +77,15 @@ namespace gr { fifo[i]->reset(); } + std::vector<float> + atsc_viterbi_decoder_impl::decoder_metrics() const + { + std::vector<float> metrics(NCODERS); + for (int i = 0; i < NCODERS; i++) + metrics[i] = viterbi[i].best_state_metric(); + return metrics; + } + int atsc_viterbi_decoder_impl::work(int noutput_items, gr_vector_const_void_star &input_items, @@ -135,5 +144,21 @@ namespace gr { return noutput_items; } + void + atsc_viterbi_decoder_impl::setup_rpc() + { +#ifdef GR_CTRLPORT + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<atsc_viterbi_decoder, std::vector<float> >( + alias(), "decoder_metrics", + &atsc_viterbi_decoder::decoder_metrics, + pmt::make_f32vector(1,0), + pmt::make_f32vector(1,100000), + pmt::make_f32vector(1,0), + "", "Viterbi decoder metrics", RPC_PRIVLVL_MIN, + DISPTIME))); +#endif /* GR_CTRLPORT */ + } + } /* namespace dtv */ } /* namespace gr */ diff --git a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h index b4fbbd1033..ef4faab313 100644 --- a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h +++ b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h @@ -63,8 +63,12 @@ namespace gr { atsc_viterbi_decoder_impl(); ~atsc_viterbi_decoder_impl(); + void setup_rpc(); + void reset(); + std::vector<float> decoder_metrics() const; + virtual int work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); diff --git a/gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.cc b/gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.cc new file mode 100644 index 0000000000..87c706b445 --- /dev/null +++ b/gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.cc @@ -0,0 +1,96 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/io_signature.h> +#include "catv_frame_sync_enc_bb_impl.h" + +namespace gr { + namespace dtv { + + catv_frame_sync_enc_bb::sptr + catv_frame_sync_enc_bb::make(int ctrlword) + { + return gnuradio::get_initial_sptr + (new catv_frame_sync_enc_bb_impl(ctrlword)); + } + + /* + * The private constructor + */ + catv_frame_sync_enc_bb_impl::catv_frame_sync_enc_bb_impl(int ctrlword) + : gr::block("catv_frame_sync_enc_bb", + gr::io_signature::make(1, 1, sizeof(unsigned char)), + gr::io_signature::make(1, 1, sizeof(unsigned char))) + { + set_output_multiple(60 * 128 + 6); + control_word = ctrlword; + } + + /* + * Our virtual destructor. + */ + catv_frame_sync_enc_bb_impl::~catv_frame_sync_enc_bb_impl() + { + } + + void + catv_frame_sync_enc_bb_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + ninput_items_required[0] = noutput_items / (60 * 128 + 6) * (60 * 128); + } + + int + catv_frame_sync_enc_bb_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + unsigned char *out = (unsigned char *) output_items[0]; + + int i = 0, j = 0; + while (i < noutput_items) { + memcpy(out + i, in + j, 60 * 128); + i += 60 * 128; + j += 60 * 128; + + out[i++] = 0x75; + out[i++] = 0x2C; + out[i++] = 0x0D; + out[i++] = 0x6C; + out[i++] = control_word << 3; + out[i++] = 0x00; + } + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (j); + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.h b/gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.h new file mode 100644 index 0000000000..fb924f7a14 --- /dev/null +++ b/gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.h @@ -0,0 +1,50 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DTV_CATV_FRAME_SYNC_ENC_BB_IMPL_H +#define INCLUDED_DTV_CATV_FRAME_SYNC_ENC_BB_IMPL_H + +#include <gnuradio/dtv/catv_frame_sync_enc_bb.h> + +namespace gr { + namespace dtv { + + class catv_frame_sync_enc_bb_impl : public catv_frame_sync_enc_bb + { + private: + int control_word; + + public: + catv_frame_sync_enc_bb_impl(int ctrlword); + ~catv_frame_sync_enc_bb_impl(); + + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_CATV_FRAME_SYNC_ENC_BB_IMPL_H */ + diff --git a/gr-dtv/lib/catv/catv_randomizer_bb_impl.cc b/gr-dtv/lib/catv/catv_randomizer_bb_impl.cc new file mode 100644 index 0000000000..698288dcd3 --- /dev/null +++ b/gr-dtv/lib/catv/catv_randomizer_bb_impl.cc @@ -0,0 +1,104 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/io_signature.h> +#include "catv_randomizer_bb_impl.h" + +namespace gr { + namespace dtv { + + catv_randomizer_bb::sptr + catv_randomizer_bb::make() + { + return gnuradio::get_initial_sptr + (new catv_randomizer_bb_impl()); + } + + /* + * The private constructor + */ + catv_randomizer_bb_impl::catv_randomizer_bb_impl() + : gr::sync_block("catv_randomizer_bb", + gr::io_signature::make(1, 1, sizeof(unsigned char)), + gr::io_signature::make(1, 1, sizeof(unsigned char))) + { + init_rand(); + + offset = 0; + max_offset = 60 * 128; + } + + /* + * Our virtual destructor. + */ + catv_randomizer_bb_impl::~catv_randomizer_bb_impl() + { + } + + void + catv_randomizer_bb_impl::init_rand() + { + unsigned char c2 = 0x7F, c1 = 0x7F, c0 = 0x7F; + unsigned char c2_new, c1_new, c0_new; + int n, i; + + for (n = 0; n < 60 * 128; n++) { + rseq[n] = c2; + c2_new = c1; + c1_new = c0 ^ c2; + c0_new = c2; + for (i = 0; i < 3; i++) { + c0_new <<= 1; + if (c0_new & 0x80) { + c0_new = (c0_new & 0x7F) ^ 0x09; + } + } + c2 = c2_new; + c1 = c1_new; + c0 = c0_new; + } + } + + int + catv_randomizer_bb_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + unsigned char *out = (unsigned char *) output_items[0]; + + for (int i = 0; i < noutput_items; i++) { + out[i] = in[i] ^ rseq[offset++]; + if (offset == max_offset) { + offset = 0; + } + } + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/catv/catv_randomizer_bb_impl.h b/gr-dtv/lib/catv/catv_randomizer_bb_impl.h new file mode 100644 index 0000000000..e4e40f8f6e --- /dev/null +++ b/gr-dtv/lib/catv/catv_randomizer_bb_impl.h @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DTV_CATV_RANDOMIZER_BB_IMPL_H +#define INCLUDED_DTV_CATV_RANDOMIZER_BB_IMPL_H + +#include <gnuradio/dtv/catv_randomizer_bb.h> + +namespace gr { + namespace dtv { + + class catv_randomizer_bb_impl : public catv_randomizer_bb + { + private: + unsigned char rseq[60 * 128]; + int offset, max_offset; + void init_rand(); + + public: + catv_randomizer_bb_impl(); + ~catv_randomizer_bb_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_CATV_RANDOMIZER_BB_IMPL_H */ + diff --git a/gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.cc b/gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.cc new file mode 100644 index 0000000000..06a1f12c3e --- /dev/null +++ b/gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.cc @@ -0,0 +1,153 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/io_signature.h> +#include "catv_reed_solomon_enc_bb_impl.h" + +namespace gr { + namespace dtv { + + catv_reed_solomon_enc_bb::sptr + catv_reed_solomon_enc_bb::make() + { + return gnuradio::get_initial_sptr + (new catv_reed_solomon_enc_bb_impl()); + } + + /* + * The private constructor + */ + catv_reed_solomon_enc_bb_impl::catv_reed_solomon_enc_bb_impl() + : gr::block("catv_reed_solomon_enc_bb", + gr::io_signature::make(1, 1, sizeof(unsigned char)), + gr::io_signature::make(1, 1, sizeof(unsigned char))) + { + set_output_multiple(128); + init_rs(); + } + + /* + * Our virtual destructor. + */ + catv_reed_solomon_enc_bb_impl::~catv_reed_solomon_enc_bb_impl() + { + } + + void + catv_reed_solomon_enc_bb_impl::init_rs() + { + unsigned char x; + int i, j; + + gf_exp[0] = 1; + gf_log[1] = 0; + + x = 1; + for (i = 1; i < 127; i++) { + x <<= 1; + if (x & 0x80) { + x = (x & 0x7F) ^ 0x09; + } + gf_exp[i] = x; + gf_log[x] = i; + } + for (; i < 256; i++) { + gf_exp[i] = gf_exp[i - 127]; + } + + for (i = 0; i < 128; i++) { + for (j = 0; j < 128; j++) { + if ((i == 0) || (j == 0)) { + gf_mul_table[i][j] = 0; + } else { + gf_mul_table[i][j] = gf_exp[gf_log[i] + gf_log[j]]; + } + } + } + } + + unsigned char + catv_reed_solomon_enc_bb_impl::gf_poly_eval(unsigned char *p, int len, unsigned char x) + { + unsigned char y = p[0]; + int i; + + for (i = 1; i < len; i++) { + y = gf_mul_table[y][x] ^ p[i]; + } + return y; + } + + void + catv_reed_solomon_enc_bb_impl::reed_solomon_enc(const unsigned char *message, unsigned char *output) + { + // Generator polynomial from p.7 of ANSI/SCTE 07 2013 + unsigned char g[] = {1, gf_exp[52], gf_exp[116], gf_exp[119], gf_exp[61], gf_exp[15]}; + int i, j; + + memcpy(output, message, 122); + memset(output + 122, 0, 6); + + for (i = 0; i < 122; i++) { + for (j = 1; j < 6; j++) { + output[i + j] ^= gf_mul_table[output[i]][g[j]]; + } + output[i] = message[i]; + } + + output[127] = gf_poly_eval(output, 128, gf_exp[6]); + } + + void + catv_reed_solomon_enc_bb_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + ninput_items_required[0] = (noutput_items / 128) * 122; + } + + int + catv_reed_solomon_enc_bb_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + unsigned char *out = (unsigned char *) output_items[0]; + int j = 0; + + for (int i = 0; i < noutput_items; i += 128) { + reed_solomon_enc(in + j, out + i); + j += 122; + } + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (j); + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.h b/gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.h new file mode 100644 index 0000000000..84e4cb500e --- /dev/null +++ b/gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.h @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DTV_CATV_REED_SOLOMON_ENC_BB_IMPL_H +#define INCLUDED_DTV_CATV_REED_SOLOMON_ENC_BB_IMPL_H + +#include <gnuradio/dtv/catv_reed_solomon_enc_bb.h> + +namespace gr { + namespace dtv { + + class catv_reed_solomon_enc_bb_impl : public catv_reed_solomon_enc_bb + { + private: + unsigned char gf_mul_table[128][128]; + unsigned char gf_exp[256]; + unsigned char gf_log[128]; + + void init_rs(); + unsigned char gf_poly_eval(unsigned char *p, int len, unsigned char x); + void reed_solomon_enc(const unsigned char *message, unsigned char *output); + + public: + catv_reed_solomon_enc_bb_impl(); + ~catv_reed_solomon_enc_bb_impl(); + + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_CATV_REED_SOLOMON_ENC_BB_IMPL_H */ + diff --git a/gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.cc b/gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.cc new file mode 100644 index 0000000000..4082e8265c --- /dev/null +++ b/gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.cc @@ -0,0 +1,131 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/io_signature.h> +#include "catv_transport_framing_enc_bb_impl.h" + +namespace gr { + namespace dtv { + + catv_transport_framing_enc_bb::sptr + catv_transport_framing_enc_bb::make() + { + return gnuradio::get_initial_sptr + (new catv_transport_framing_enc_bb_impl()); + } + + /* + * The private constructor + */ + catv_transport_framing_enc_bb_impl::catv_transport_framing_enc_bb_impl() + : gr::sync_block("catv_transport_framing_enc_bb", + gr::io_signature::make(1, 1, sizeof(unsigned char)), + gr::io_signature::make(1, 1, sizeof(unsigned char))) + { + set_output_multiple(188); + } + + /* + * Our virtual destructor. + */ + catv_transport_framing_enc_bb_impl::~catv_transport_framing_enc_bb_impl() + { + } + + unsigned char catv_transport_framing_enc_bb_impl::compute_sum(const unsigned char *bytes) + { + unsigned char i, bit, out, out1, out2, out3; + + unsigned char tapsG = 0xB1; // 10110001 + unsigned char tapsB = 0x45; // 1000101 + + unsigned char register1 = 0; + unsigned char register2 = 0; + unsigned char register3 = 0; + + unsigned char result = 0x67; + + unsigned char first7[] = {0, 0, 0, 0, 0, 0, 0, 0}; + + for (i = 0; i < 8; i++) { + bit = (bytes[0] >> (7-i)) & 1; + out = (register1 & 1) ^ bit; + if (i < 7) { + first7[i+1] = out; + } + register1 >>= 1; + if (out == 1) { + register1 ^= tapsG; + } + } + + for (i = 1; i < 187; i++) { + register1 = crctable[((register1) ^ BitReverseTable[bytes[i]]) & 0xff]; + } + + for (i = 0; i < 8; i++) { + out1 = register1 & 1; + register1 >>= 1; + if (out1 == 1) { + register1 ^= tapsG; + } + + out2 = (register2 & 1) ^ first7[i]; + register2 >>= 1; + if (first7[i] == 1) { + register2 ^= tapsB; + } + + out3 = (register3 & 1) ^ out1 ^ out2; + register3 >>= 1; + if ((out1 ^ out2) == 1) { + register3 ^= tapsG; + } + + result ^= (out3 << (7-i)); + } + + return result; + } + + int + catv_transport_framing_enc_bb_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + unsigned char *out = (unsigned char *) output_items[0]; + + for (int i = 0; i < noutput_items; i += 188) { + memcpy(out + i, in + i + 1, 187); + out[i + 187] = compute_sum(in + i + 1); + } + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.h b/gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.h new file mode 100644 index 0000000000..fe69bc01f6 --- /dev/null +++ b/gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.h @@ -0,0 +1,84 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DTV_CATV_TRANSPORT_FRAMING_ENC_BB_IMPL_H +#define INCLUDED_DTV_CATV_TRANSPORT_FRAMING_ENC_BB_IMPL_H + +#include <gnuradio/dtv/catv_transport_framing_enc_bb.h> + +namespace gr { + namespace dtv { + static const unsigned char crctable[] = { + 0x00,0x1b,0x36,0x2d,0x6c,0x77,0x5a,0x41,0xd8,0xc3,0xee,0xf5,0xb4,0xaf,0x82,0x99, + 0xd3,0xc8,0xe5,0xfe,0xbf,0xa4,0x89,0x92,0x0b,0x10,0x3d,0x26,0x67,0x7c,0x51,0x4a, + 0xc5,0xde,0xf3,0xe8,0xa9,0xb2,0x9f,0x84,0x1d,0x06,0x2b,0x30,0x71,0x6a,0x47,0x5c, + 0x16,0x0d,0x20,0x3b,0x7a,0x61,0x4c,0x57,0xce,0xd5,0xf8,0xe3,0xa2,0xb9,0x94,0x8f, + 0xe9,0xf2,0xdf,0xc4,0x85,0x9e,0xb3,0xa8,0x31,0x2a,0x07,0x1c,0x5d,0x46,0x6b,0x70, + 0x3a,0x21,0x0c,0x17,0x56,0x4d,0x60,0x7b,0xe2,0xf9,0xd4,0xcf,0x8e,0x95,0xb8,0xa3, + 0x2c,0x37,0x1a,0x01,0x40,0x5b,0x76,0x6d,0xf4,0xef,0xc2,0xd9,0x98,0x83,0xae,0xb5, + 0xff,0xe4,0xc9,0xd2,0x93,0x88,0xa5,0xbe,0x27,0x3c,0x11,0x0a,0x4b,0x50,0x7d,0x66, + 0xb1,0xaa,0x87,0x9c,0xdd,0xc6,0xeb,0xf0,0x69,0x72,0x5f,0x44,0x05,0x1e,0x33,0x28, + 0x62,0x79,0x54,0x4f,0x0e,0x15,0x38,0x23,0xba,0xa1,0x8c,0x97,0xd6,0xcd,0xe0,0xfb, + 0x74,0x6f,0x42,0x59,0x18,0x03,0x2e,0x35,0xac,0xb7,0x9a,0x81,0xc0,0xdb,0xf6,0xed, + 0xa7,0xbc,0x91,0x8a,0xcb,0xd0,0xfd,0xe6,0x7f,0x64,0x49,0x52,0x13,0x08,0x25,0x3e, + 0x58,0x43,0x6e,0x75,0x34,0x2f,0x02,0x19,0x80,0x9b,0xb6,0xad,0xec,0xf7,0xda,0xc1, + 0x8b,0x90,0xbd,0xa6,0xe7,0xfc,0xd1,0xca,0x53,0x48,0x65,0x7e,0x3f,0x24,0x09,0x12, + 0x9d,0x86,0xab,0xb0,0xf1,0xea,0xc7,0xdc,0x45,0x5e,0x73,0x68,0x29,0x32,0x1f,0x04, + 0x4e,0x55,0x78,0x63,0x22,0x39,0x14,0x0f,0x96,0x8d,0xa0,0xbb,0xfa,0xe1,0xcc,0xd7 + }; + + static const unsigned char BitReverseTable[] = { + 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, + 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, + 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, + 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, + 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, + 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, + 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, + 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, + 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, + 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, + 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, + 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, + 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, + 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, + 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, + 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF + }; + + class catv_transport_framing_enc_bb_impl : public catv_transport_framing_enc_bb + { + private: + unsigned char compute_sum(const unsigned char *bytes); + + public: + catv_transport_framing_enc_bb_impl(); + ~catv_transport_framing_enc_bb_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_CATV_TRANSPORT_FRAMING_ENC_BB_IMPL_H */ + diff --git a/gr-dtv/lib/catv/catv_trellis_enc_bb_impl.cc b/gr-dtv/lib/catv/catv_trellis_enc_bb_impl.cc new file mode 100644 index 0000000000..8fdb8722b6 --- /dev/null +++ b/gr-dtv/lib/catv/catv_trellis_enc_bb_impl.cc @@ -0,0 +1,193 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/io_signature.h> +#include "catv_trellis_enc_bb_impl.h" + +namespace gr { + namespace dtv { + + catv_trellis_enc_bb::sptr + catv_trellis_enc_bb::make() + { + return gnuradio::get_initial_sptr + (new catv_trellis_enc_bb_impl()); + } + + /* + * The private constructor + */ + catv_trellis_enc_bb_impl::catv_trellis_enc_bb_impl() + : gr::block("catv_trellis_enc_bb", + gr::io_signature::make(1, 1, sizeof(unsigned char)), + gr::io_signature::make(1, 1, sizeof(unsigned char))) + { + set_output_multiple(5); + + init_trellis(); + + Xq = 0; + Yq = 0; + XYp = 0; + } + + /* + * Our virtual destructor. + */ + catv_trellis_enc_bb_impl::~catv_trellis_enc_bb_impl() + { + } + + void + catv_trellis_enc_bb_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + ninput_items_required[0] = noutput_items / 5 * 4; + } + + void + catv_trellis_enc_bb_impl::diff_precoder(unsigned char W, unsigned char Z, unsigned char *Xp, unsigned char *Yp) + { + unsigned char common, newX, newY; + + common = (Z & (*Xp ^ *Yp)); + newX = W ^ *Xp ^ common; + newY = Z ^ W ^ *Yp ^ common; + + *Xp = newX; + *Yp = newY; + } + + void + catv_trellis_enc_bb_impl::init_trellis() + { + unsigned char XYp, W, Z, X, Y, Xp, Yp, state, xy, Xq; + int i, n; + + for (XYp = 0; XYp < 4; XYp++) { + for (W = 0; W < 16; W++) { + for (Z = 0; Z < 16; Z++) { + X = 0; + Y = 0; + Xp = (XYp & 0b10) >> 1; + Yp = (XYp & 0b01); + for (i = 0; i < 4; i++) { + diff_precoder((W >> i) & 1, (Z >> i) & 1, &Xp, &Yp); + X |= (Xp << i); + Y |= (Yp << i); + } + diff_precoder_table[XYp][W][Z][0] = (Xp << 1) + Yp; + diff_precoder_table[XYp][W][Z][1] = X; + diff_precoder_table[XYp][W][Z][2] = Y; + } + } + } + + for (i = 0; i < 32; i++) { + G1table[i] = (i >> 4) ^ ((i & 0x04) >> 2) ^ (i & 1); + G2table[i] = (i >> 4) ^ ((i & 0x08) >> 3) ^ ((i & 0x04) >> 2) ^ ((i & 0x02) >> 1) ^ (i & 1); + } + + memset(trellis_table_x, 0, 16*16*6); + memset(trellis_table_y, 0, 16*16*6); + for (state = 0; state < 16; state++) { + for (xy = 0; xy < 16; xy++) { + i = 0; + Xq = state; + for (n = 0; n < 4; n++) { + Xq = (Xq << 1) + ((xy >> n) & 1); + + if (n == 3) { + trellis_table_x[state][xy][i+1] |= G1table[Xq] << 3; + trellis_table_y[state][xy][i+1] |= G1table[Xq]; + i += 1; + } + trellis_table_x[state][xy][i+1] |= G2table[Xq] << 3; + trellis_table_y[state][xy][i+1] |= G2table[Xq]; + i += 1; + + Xq &= 0x0F; + } + + trellis_table_x[state][xy][0] = Xq; + trellis_table_y[state][xy][0] = Xq; + } + } + } + + void + catv_trellis_enc_bb_impl::trellis_code(const unsigned char *rs, unsigned char *qs) + { + unsigned char X, Y; + int A, B, n; + + A = (rs[1] << 7) | rs[0]; + B = (rs[3] << 7) | rs[2]; + + memset(qs, 0, 5); + + for (n = 0; n < 5; n++) { + qs[n] |= ((A >> (2*n)) & 3) << 4; + qs[n] |= ((B >> (2*n)) & 3) << 1; + } + + X = diff_precoder_table[XYp][A >> 10][B >> 10][1]; + Y = diff_precoder_table[XYp][A >> 10][B >> 10][2]; + XYp = diff_precoder_table[XYp][A >> 10][B >> 10][0]; + + for (n = 0; n < 5; n++) { + qs[n] |= trellis_table_x[Xq][X][1+n]; + qs[n] |= trellis_table_y[Yq][Y][1+n]; + } + Xq = trellis_table_x[Xq][X][0]; + Yq = trellis_table_y[Yq][Y][0]; + } + + int + catv_trellis_enc_bb_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + unsigned char *out = (unsigned char *) output_items[0]; + + int i = 0, j = 0; + + while (i < noutput_items) { + trellis_code(in + j, out + i); + i += 5; + j += 4; + } + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (j); + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/catv/catv_trellis_enc_bb_impl.h b/gr-dtv/lib/catv/catv_trellis_enc_bb_impl.h new file mode 100644 index 0000000000..aa7874d929 --- /dev/null +++ b/gr-dtv/lib/catv/catv_trellis_enc_bb_impl.h @@ -0,0 +1,60 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This 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. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DTV_CATV_TRELLIS_ENC_BB_IMPL_H +#define INCLUDED_DTV_CATV_TRELLIS_ENC_BB_IMPL_H + +#include <gnuradio/dtv/catv_trellis_enc_bb.h> + +namespace gr { + namespace dtv { + + class catv_trellis_enc_bb_impl : public catv_trellis_enc_bb + { + private: + unsigned char diff_precoder_table[4][16][16][3]; + unsigned char G1table[32]; + unsigned char G2table[32]; + unsigned char trellis_table_x[16][16][6]; + unsigned char trellis_table_y[16][16][6]; + unsigned char Xq, Yq, XYp; + + void diff_precoder(unsigned char W, unsigned char Z, unsigned char *Xp, unsigned char *Yp); + void init_trellis(); + void trellis_code(const unsigned char *rs, unsigned char *qs); + + public: + catv_trellis_enc_bb_impl(); + ~catv_trellis_enc_bb_impl(); + + // Where all the action really happens + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_CATV_TRELLIS_ENC_BB_IMPL_H */ + diff --git a/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.cc b/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.cc index c8579d1c1e..d1f3b4aa27 100644 --- a/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.cc +++ b/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2015 Free Software Foundation, Inc. + * Copyright 2015,2016 Free Software Foundation, Inc. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,16 +29,16 @@ namespace gr { namespace dtv { dvbs2_modulator_bc::sptr - dvbs2_modulator_bc::make(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation) + dvbs2_modulator_bc::make(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbs2_interpolation_t interpolation) { return gnuradio::get_initial_sptr - (new dvbs2_modulator_bc_impl(framesize, rate, constellation)); + (new dvbs2_modulator_bc_impl(framesize, rate, constellation, interpolation)); } /* * The private constructor */ - dvbs2_modulator_bc_impl::dvbs2_modulator_bc_impl(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation) + dvbs2_modulator_bc_impl::dvbs2_modulator_bc_impl(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbs2_interpolation_t interpolation) : gr::block("dvbs2_modulator_bc", gr::io_signature::make(1, 1, sizeof(unsigned char)), gr::io_signature::make(1, 1, sizeof(gr_complex))) @@ -1660,6 +1660,72 @@ namespace gr { m_256apsk[255] = gr_complex((r6 * cos(43 * M_PI / 32.0)), (r6 * sin(43 * M_PI / 32.0))); } break; + case MOD_64QAM: + m_64apsk[0] = gr_complex( 1.0, 1.0); + m_64apsk[1] = gr_complex( 1.0, -1.0); + m_64apsk[2] = gr_complex( 1.0, -3.0); + m_64apsk[3] = gr_complex( -3.0, -1.0); + m_64apsk[4] = gr_complex( -3.0, 1.0); + m_64apsk[5] = gr_complex( 1.0, 3.0); + m_64apsk[6] = gr_complex( -3.0, -3.0); + m_64apsk[7] = gr_complex( -3.0, 3.0); + m_64apsk[8] = gr_complex( -1.0, 1.0); + m_64apsk[9] = gr_complex( -1.0, -1.0); + m_64apsk[10] = gr_complex( 3.0, 1.0); + m_64apsk[11] = gr_complex(-1.0, 3.0); + m_64apsk[12] = gr_complex(-1.0, -3.0); + m_64apsk[13] = gr_complex( 3.0, -1.0); + m_64apsk[14] = gr_complex( 3.0, -3.0); + m_64apsk[15] = gr_complex( 3.0, 3.0); + m_64apsk[16] = gr_complex( 5.0, 1.0); + m_64apsk[17] = gr_complex( 1.0, -5.0); + m_64apsk[18] = gr_complex( 1.0, -7.0); + m_64apsk[19] = gr_complex(-7.0, -1.0); + m_64apsk[20] = gr_complex(-3.0, 5.0); + m_64apsk[21] = gr_complex( 5.0, 3.0); + m_64apsk[22] = gr_complex(-7.0, -3.0); + m_64apsk[23] = gr_complex(-3.0, 7.0); + m_64apsk[24] = gr_complex(-1.0, 5.0); + m_64apsk[25] = gr_complex(-5.0, -1.0); + m_64apsk[26] = gr_complex( 7.0, 1.0); + m_64apsk[27] = gr_complex(-1.0, 7.0); + m_64apsk[28] = gr_complex(-5.0, -3.0); + m_64apsk[29] = gr_complex( 3.0, -5.0); + m_64apsk[30] = gr_complex( 3.0, -7.0); + m_64apsk[31] = gr_complex( 7.0, 3.0); + m_64apsk[32] = gr_complex( 1.0, 5.0); + m_64apsk[33] = gr_complex( 5.0, -1.0); + m_64apsk[34] = gr_complex( 5.0, -3.0); + m_64apsk[35] = gr_complex(-3.0, -5.0); + m_64apsk[36] = gr_complex(-7.0, 1.0); + m_64apsk[37] = gr_complex( 1.0, 7.0); + m_64apsk[38] = gr_complex(-3.0, -7.0); + m_64apsk[39] = gr_complex(-7.0, 3.0); + m_64apsk[40] = gr_complex(-5.0, 1.0); + m_64apsk[41] = gr_complex(-1.0, -5.0); + m_64apsk[42] = gr_complex( 3.0, 5.0); + m_64apsk[43] = gr_complex(-5.0, 3.0); + m_64apsk[44] = gr_complex(-1.0, -7.0); + m_64apsk[45] = gr_complex( 7.0, -1.0); + m_64apsk[46] = gr_complex( 7.0, -3.0); + m_64apsk[47] = gr_complex( 3.0, 7.0); + m_64apsk[48] = gr_complex( 5.0, 5.0); + m_64apsk[49] = gr_complex( 5.0, -5.0); + m_64apsk[50] = gr_complex( 5.0, -7.0); + m_64apsk[51] = gr_complex(-7.0, -5.0); + m_64apsk[52] = gr_complex(-7.0, 5.0); + m_64apsk[53] = gr_complex( 5.0, 7.0); + m_64apsk[54] = gr_complex(-7.0, -7.0); + m_64apsk[55] = gr_complex(-7.0, 7.0); + m_64apsk[56] = gr_complex(-5.0, 5.0); + m_64apsk[57] = gr_complex(-5.0, -5.0); + m_64apsk[58] = gr_complex( 7.0, 5.0); + m_64apsk[59] = gr_complex(-5.0, 7.0); + m_64apsk[60] = gr_complex(-5.0, -7.0); + m_64apsk[61] = gr_complex( 7.0, -5.0); + m_64apsk[62] = gr_complex( 7.0, -7.0); + m_64apsk[63] = gr_complex( 7.0, 7.0); + break; default: m_qpsk[0] = gr_complex((r1 * cos(M_PI / 4.0)), (r1 * sin(M_PI / 4.0))); m_qpsk[1] = gr_complex((r1 * cos(7 * M_PI / 4.0)), (r1 * sin(7 * M_PI / 4.0))); @@ -1668,6 +1734,7 @@ namespace gr { break; } signal_constellation = constellation; + signal_interpolation = interpolation; set_output_multiple(2); } @@ -1681,7 +1748,12 @@ namespace gr { void dvbs2_modulator_bc_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) { - ninput_items_required[0] = noutput_items; + if (signal_interpolation == INTERPOLATION_OFF) { + ninput_items_required[0] = noutput_items; + } + else { + ninput_items_required[0] = noutput_items / 2; + } } int @@ -1693,67 +1765,145 @@ namespace gr { const unsigned char *in = (const unsigned char *) input_items[0]; gr_complex *out = (gr_complex *) output_items[0]; int index; + gr_complex zero; - switch (signal_constellation) { - case MOD_QPSK: - for (int i = 0; i < noutput_items; i++) { - index = *in++; - *out++ = m_qpsk[index & 0x3]; - } - break; - case MOD_8PSK: - case MOD_8APSK: - for (int i = 0; i < noutput_items; i++) { - index = *in++; - *out++ = m_8psk[index & 0x7]; - } - break; - case MOD_16APSK: - case MOD_8_8APSK: - for (int i = 0; i < noutput_items; i++) { - index = *in++; - *out++ = m_16apsk[index & 0xf]; - } - break; - case MOD_32APSK: - case MOD_4_12_16APSK: - case MOD_4_8_4_16APSK: - for (int i = 0; i < noutput_items; i++) { - index = *in++; - *out++ = m_32apsk[index & 0x1f]; - } - break; - case MOD_64APSK: - case MOD_8_16_20_20APSK: - case MOD_4_12_20_28APSK: - for (int i = 0; i < noutput_items; i++) { - index = *in++; - *out++ = m_64apsk[index & 0x3f]; - } - break; - case MOD_128APSK: - for (int i = 0; i < noutput_items; i++) { - index = *in++; - *out++ = m_128apsk[index & 0x7f]; - } - break; - case MOD_256APSK: - for (int i = 0; i < noutput_items; i++) { - index = *in++; - *out++ = m_256apsk[index & 0xff]; - } - break; - default: - for (int i = 0; i < noutput_items; i++) { - index = *in++; - *out++ = m_qpsk[index & 0x3]; - } - break; + zero = gr_complex(0.0, 0.0); + + if (signal_interpolation == INTERPOLATION_OFF) { + switch (signal_constellation) { + case MOD_QPSK: + for (int i = 0; i < noutput_items; i++) { + index = *in++; + *out++ = m_qpsk[index & 0x3]; + } + break; + case MOD_8PSK: + case MOD_8APSK: + for (int i = 0; i < noutput_items; i++) { + index = *in++; + *out++ = m_8psk[index & 0x7]; + } + break; + case MOD_16APSK: + case MOD_8_8APSK: + for (int i = 0; i < noutput_items; i++) { + index = *in++; + *out++ = m_16apsk[index & 0xf]; + } + break; + case MOD_32APSK: + case MOD_4_12_16APSK: + case MOD_4_8_4_16APSK: + for (int i = 0; i < noutput_items; i++) { + index = *in++; + *out++ = m_32apsk[index & 0x1f]; + } + break; + case MOD_64APSK: + case MOD_64QAM: + case MOD_8_16_20_20APSK: + case MOD_4_12_20_28APSK: + for (int i = 0; i < noutput_items; i++) { + index = *in++; + *out++ = m_64apsk[index & 0x3f]; + } + break; + case MOD_128APSK: + for (int i = 0; i < noutput_items; i++) { + index = *in++; + *out++ = m_128apsk[index & 0x7f]; + } + break; + case MOD_256APSK: + for (int i = 0; i < noutput_items; i++) { + index = *in++; + *out++ = m_256apsk[index & 0xff]; + } + break; + default: + for (int i = 0; i < noutput_items; i++) { + index = *in++; + *out++ = m_qpsk[index & 0x3]; + } + break; + } + } + else { + switch (signal_constellation) { + case MOD_QPSK: + for (int i = 0; i < noutput_items / 2; i++) { + index = *in++; + *out++ = m_qpsk[index & 0x3]; + *out++ = zero; + } + break; + case MOD_8PSK: + case MOD_8APSK: + for (int i = 0; i < noutput_items / 2; i++) { + index = *in++; + *out++ = m_8psk[index & 0x7]; + *out++ = zero; + } + break; + case MOD_16APSK: + case MOD_8_8APSK: + for (int i = 0; i < noutput_items / 2; i++) { + index = *in++; + *out++ = m_16apsk[index & 0xf]; + *out++ = zero; + } + break; + case MOD_32APSK: + case MOD_4_12_16APSK: + case MOD_4_8_4_16APSK: + for (int i = 0; i < noutput_items / 2; i++) { + index = *in++; + *out++ = m_32apsk[index & 0x1f]; + *out++ = zero; + } + break; + case MOD_64APSK: + case MOD_64QAM: + case MOD_8_16_20_20APSK: + case MOD_4_12_20_28APSK: + for (int i = 0; i < noutput_items / 2; i++) { + index = *in++; + *out++ = m_64apsk[index & 0x3f]; + *out++ = zero; + } + break; + case MOD_128APSK: + for (int i = 0; i < noutput_items / 2; i++) { + index = *in++; + *out++ = m_128apsk[index & 0x7f]; + *out++ = zero; + } + break; + case MOD_256APSK: + for (int i = 0; i < noutput_items / 2; i++) { + index = *in++; + *out++ = m_256apsk[index & 0xff]; + *out++ = zero; + } + break; + default: + for (int i = 0; i < noutput_items / 2; i++) { + index = *in++; + *out++ = m_qpsk[index & 0x3]; + *out++ = zero; + } + break; + } } // Tell runtime system how many input items we consumed on // each input stream. - consume_each (noutput_items); + if (signal_interpolation == INTERPOLATION_OFF) { + consume_each (noutput_items); + } + else { + consume_each (noutput_items / 2); + } // Tell runtime system how many output items we produced. return noutput_items; diff --git a/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.h b/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.h index 8507878b0e..4fdbb149df 100644 --- a/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.h +++ b/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.h @@ -31,6 +31,7 @@ namespace gr { { private: int signal_constellation; + int signal_interpolation; gr_complex m_qpsk[4]; gr_complex m_8psk[8]; gr_complex m_16apsk[16]; @@ -40,7 +41,7 @@ namespace gr { gr_complex m_256apsk[256]; public: - dvbs2_modulator_bc_impl(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation); + dvbs2_modulator_bc_impl(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbs2_interpolation_t interpolation); ~dvbs2_modulator_bc_impl(); void forecast (int noutput_items, gr_vector_int &ninput_items_required); diff --git a/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.cc b/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.cc index 84b20f9ad4..abef1d0510 100644 --- a/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.cc +++ b/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.cc @@ -34,12 +34,12 @@ namespace gr { namespace dtv { int - dvbt_ofdm_sym_acquisition_impl::peak_detect_init(float threshold_factor_rise, float threshold_factor_fall, int look_ahead, float alpha) + dvbt_ofdm_sym_acquisition_impl::peak_detect_init(float threshold_factor_rise, float alpha) { d_avg_alpha = alpha; d_threshold_factor_rise = threshold_factor_rise; - d_threshold_factor_fall = threshold_factor_fall; - d_avg = 0; + d_avg_max = - (float)INFINITY; + d_avg_min = (float)INFINITY; return (0); } @@ -47,56 +47,50 @@ namespace gr { int dvbt_ofdm_sym_acquisition_impl::peak_detect_process(const float * datain, const int datain_length, int * peak_pos, int * peak_max) { - int state = 0; - float peak_val = -(float)INFINITY; int peak_index = 0; int peak_pos_length = 0; + unsigned int peak_index = 0; + int peak_pos_length = 0; - int i = 0; + volk_32f_index_max_16u(&peak_index, &datain[0], datain_length); - while(i < datain_length) { - if (state == 0) { - if (datain[i] > d_avg * d_threshold_factor_rise) { - state = 1; - } - else { - d_avg = d_avg_alpha * datain[i] + (1 - d_avg_alpha) * d_avg; - i++; - } + peak_pos_length = 1; + if (datain_length >= d_fft_length) { + float min = datain[(peak_index + d_fft_length / 2) % d_fft_length]; + if (d_avg_min == (float)INFINITY) { + d_avg_min = min; } - else if (state == 1) { - if (datain[i] > peak_val) { - peak_val = datain[i]; - peak_index = i; - d_avg = d_avg_alpha * datain[i] + (1 - d_avg_alpha) * d_avg; - i++; - } - else if (datain[i] > d_avg * d_threshold_factor_fall) { - d_avg = (d_avg_alpha) * datain[i] + (1 - d_avg_alpha) * d_avg; - i++; - } - else { - peak_pos[peak_pos_length] = peak_index; - peak_pos_length++; - state = 0; - peak_val = - (float)INFINITY; - } + else { + d_avg_min = d_avg_alpha * min + (1 - d_avg_alpha) * d_avg_min; } } - // Find peak of peaks - if (peak_pos_length) { - float max = datain[peak_pos[0]]; - int maxi = 0; + if (d_avg_max == -(float)INFINITY) { + // Initialize d_avg_max with the first value. + d_avg_max = datain[peak_index]; + } + else if (datain[peak_index] > d_avg_max - d_threshold_factor_rise * (d_avg_max-d_avg_min)) { + d_avg_max = d_avg_alpha * datain[peak_index] + (1 - d_avg_alpha) * d_avg_max; + } + else { + peak_pos_length = 0; + } - for (int i = 1; i < peak_pos_length; i++) { - if (datain[peak_pos[i]] > max) { - max = datain[peak_pos[i]]; - maxi = i; - } + // We now check whether the peak is in the border of the search interval. This would mean that + // the search interval is not correct, and it should be re-set. This happens for instance when the + // hardware dropped some samples. + // Our definition of "border of the search interval" depends if the search interval is "big" or not. + if (datain_length < d_fft_length) { + if ((peak_index == 0) || (peak_index == (unsigned int)datain_length - 1)) { + peak_pos_length = 0; + } + } + else { + if ((peak_index < 5) || (peak_index > (unsigned int)datain_length - 5)) { + peak_pos_length = 0; } - - *peak_max = maxi; } + peak_pos[0] = peak_index; + *peak_max = 0; return (peak_pos_length); } @@ -119,7 +113,8 @@ namespace gr { volk_32fc_magnitude_squared_32f(&d_norm[low], &in[low], size); // Calculate gamma on each point - low = lookup_stop - d_cp_length + 1; + // TODO check these boundaries!!!!!!! + low = lookup_stop - (d_cp_length - 1); size = lookup_start - low + 1; volk_32fc_x2_multiply_conjugate_32fc(&d_corr[low - d_fft_length], &in[low], &in[low - d_fft_length], size); @@ -220,6 +215,12 @@ namespace gr { this->add_item_tag(0, offset, key, value); } + // Derotates the signal + void dvbt_ofdm_sym_acquisition_impl::derotate(const gr_complex * in, gr_complex * out) + { + volk_32fc_x2_multiply_32fc(&out[0], &d_derot[0], &in[0], d_fft_length); + } + dvbt_ofdm_sym_acquisition::sptr dvbt_ofdm_sym_acquisition::make(int blocks, int fft_length, int occupied_tones, int cp_length, float snr) { @@ -234,11 +235,10 @@ namespace gr { : block("dvbt_ofdm_sym_acquisition", io_signature::make(1, 1, sizeof (gr_complex) * blocks), io_signature::make(1, 1, sizeof (gr_complex) * blocks * fft_length)), - d_blocks(blocks), d_fft_length(fft_length), d_cp_length(cp_length), d_snr(snr), - d_index(0), d_phase(0.0), d_phaseinc(0.0), d_cp_found(0), d_count(0), d_nextphaseinc(0), d_nextpos(0), \ - d_sym_acq_count(0),d_sym_acq_timeout(100), d_initial_acquisition(0), \ - d_freq_correction_count(0), d_freq_correction_timeout(0), d_cp_start(0), \ - d_to_consume(0), d_to_out(0) + d_blocks(blocks), d_fft_length(fft_length), d_cp_length(cp_length), d_snr(snr), \ + d_phase(0.0), d_phaseinc(0.0), d_cp_found(0), d_nextphaseinc(0), d_nextpos(0), \ + d_initial_acquisition(0), d_cp_start(0), \ + d_to_consume(0), d_to_out(0), d_consumed(0), d_out(0) { set_relative_rate(1.0 / (double) (d_cp_length + d_fft_length)); @@ -296,7 +296,7 @@ namespace gr { exit(1); } - peak_detect_init(0.8, 0.9, 30, 0.9); + peak_detect_init(0.3, 0.9); } /* @@ -319,7 +319,7 @@ namespace gr { // make sure we receive at least (symbol_length + fft_length) for (int i = 0; i < ninputs; i++) { - ninput_items_required[i] = (2 * d_fft_length + d_cp_length) * noutput_items; + ninput_items_required[i] = (d_cp_length + d_fft_length) * (noutput_items + 1); } } @@ -336,45 +336,52 @@ namespace gr { { const gr_complex *in = (const gr_complex *) input_items[0]; gr_complex *out = (gr_complex *) output_items[0]; - - int low, size; - - // This is initial acquisition of symbol start - // TODO - make a FSM - if (!d_initial_acquisition) { - d_initial_acquisition = ml_sync(in, 2 * d_fft_length + d_cp_length - 1, d_fft_length + d_cp_length - 1, \ - &d_cp_start, &d_derot[0], &d_to_consume, &d_to_out); - - // Send sync_start downstream - send_sync_start(); - } - - // This is fractional frequency correction (pre FFT) - // It is also called coarse frequency correction - if (d_initial_acquisition) { - d_cp_found = ml_sync(in, d_cp_start + 16, d_cp_start, \ - &d_cp_start, &d_derot[0], &d_to_consume, &d_to_out); + int low; + + d_consumed = 0; + d_out = 0; + + for (int i = 0; i < noutput_items; i++) { + // This is initial acquisition of symbol start + // TODO - make a FSM + if (!d_initial_acquisition) { + d_initial_acquisition = ml_sync(&in[d_consumed], 2 * d_fft_length + d_cp_length - 1, d_fft_length + d_cp_length - 1, \ + &d_cp_start, &d_derot[0], &d_to_consume, &d_to_out); + d_cp_found = d_initial_acquisition; + } + else { + // If we are here it means that in the previous iteration we found the CP. We + // now thus only search near it. + d_cp_found = ml_sync(&in[d_consumed], d_cp_start + 8, std::max(d_cp_start - 8, d_cp_length+d_fft_length - 1), \ + &d_cp_start, &d_derot[0], &d_to_consume, &d_to_out); + if (!d_cp_found) { + // We may have not found the CP because the smaller search range was too small (rare, but possible). + // We re-try with the whole search range. + d_cp_found = ml_sync(&in[d_consumed], 2 * d_fft_length + d_cp_length - 1, d_fft_length + d_cp_length - 1, \ + &d_cp_start, &d_derot[0], &d_to_consume, &d_to_out ); + } + } if (d_cp_found) { - d_freq_correction_count = 0; - - // Derotate the signal and out - low = d_cp_start - d_fft_length + 1; - size = d_cp_start - (d_cp_start - d_fft_length + 1) + 1; - - volk_32fc_x2_multiply_32fc(&out[0], &d_derot[0], &in[low], size); + low = d_consumed + d_cp_start - d_fft_length + 1; + derotate(&in[low], &out[i * d_fft_length]); } else { - // If we have a number of consecutive misses then we restart acquisition - if (++d_freq_correction_count > d_freq_correction_timeout) { - d_initial_acquisition = 0; - d_freq_correction_count = 0; - - // Restart with a half number so that we'll not endup with the same situation - // This will prevent peak_detect to not detect anything - d_to_consume = d_to_consume / 2; - } + // Send sync_start downstream + send_sync_start(); + d_initial_acquisition = 0; + + // Restart wit a half number so that we'll not end up with the same situation + // This will prevent peak_detect to not detect anything + d_to_consume = d_to_consume / 2; + d_consumed += d_to_consume; + consume_each(d_consumed); + + // Tell runtime system how many output items we produced. + return (d_out); } + d_consumed += d_to_consume; + d_out += d_to_out; } // Tell runtime system how many input items we consumed on @@ -386,3 +393,4 @@ namespace gr { } } /* namespace dtv */ } /* namespace gr */ + diff --git a/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.h b/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.h index e7b92cbd41..0964361b1e 100644 --- a/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.h +++ b/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.h @@ -35,8 +35,6 @@ namespace gr { float d_snr; float d_rho; - int d_index; - gr_complex * d_conj; float * d_norm; gr_complex * d_corr; @@ -45,37 +43,35 @@ namespace gr { // For peak detector float d_threshold_factor_rise; - float d_threshold_factor_fall; float d_avg_alpha; - float d_avg; + float d_avg_min; + float d_avg_max; float d_phase; double d_phaseinc; int d_cp_found; - int d_count; double d_nextphaseinc; int d_nextpos; - int d_sym_acq_count; - int d_sym_acq_timeout; - int d_initial_acquisition; - int d_freq_correction_count; - int d_freq_correction_timeout; - int d_cp_start; gr_complex * d_derot; int d_to_consume; int d_to_out; + int d_consumed; + int d_out; int ml_sync(const gr_complex * in, int lookup_start, int lookup_stop, int * cp_pos, gr_complex * derot, int * to_consume, int * to_out); - int peak_detect_init(float threshold_factor_rise, float threshold_factor_fall, int look_ahead, float alpha); + int peak_detect_init(float threshold_factor_rise, float alpha); int peak_detect_process(const float * datain, const int datain_length, int * peak_pos, int * peak_max); void send_sync_start(); + + void derotate(const gr_complex * in, gr_complex *out); + public: dvbt_ofdm_sym_acquisition_impl(int blocks, int fft_length, int occupied_tones, int cp_length, float snr); ~dvbt_ofdm_sym_acquisition_impl(); @@ -92,3 +88,4 @@ namespace gr { } // namespace gr #endif /* INCLUDED_DTV_DVBT_OFDM_SYM_ACQUISITION_IMPL_H */ + diff --git a/gr-dtv/swig/dtv_swig.i b/gr-dtv/swig/dtv_swig.i index c2fa312e05..24960bd2be 100644 --- a/gr-dtv/swig/dtv_swig.i +++ b/gr-dtv/swig/dtv_swig.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2014,2015 Free Software Foundation, Inc. + * Copyright 2014,2015,2016 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -79,6 +79,11 @@ #include "gnuradio/dtv/dvbt_convolutional_deinterleaver.h" #include "gnuradio/dtv/dvbt_reed_solomon_dec.h" #include "gnuradio/dtv/dvbt_energy_descramble.h" +#include "gnuradio/dtv/catv_transport_framing_enc_bb.h" +#include "gnuradio/dtv/catv_reed_solomon_enc_bb.h" +#include "gnuradio/dtv/catv_randomizer_bb.h" +#include "gnuradio/dtv/catv_frame_sync_enc_bb.h" +#include "gnuradio/dtv/catv_trellis_enc_bb.h" %} %include "gnuradio/dtv/atsc_deinterleaver.h" @@ -132,6 +137,11 @@ %include "gnuradio/dtv/dvbt_convolutional_deinterleaver.h" %include "gnuradio/dtv/dvbt_reed_solomon_dec.h" %include "gnuradio/dtv/dvbt_energy_descramble.h" +%include "gnuradio/dtv/catv_transport_framing_enc_bb.h" +%include "gnuradio/dtv/catv_reed_solomon_enc_bb.h" +%include "gnuradio/dtv/catv_randomizer_bb.h" +%include "gnuradio/dtv/catv_frame_sync_enc_bb.h" +%include "gnuradio/dtv/catv_trellis_enc_bb.h" GR_SWIG_BLOCK_MAGIC2(dtv, atsc_deinterleaver); GR_SWIG_BLOCK_MAGIC2(dtv, atsc_depad); @@ -180,3 +190,8 @@ GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_viterbi_decoder); GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_convolutional_deinterleaver); GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_reed_solomon_dec); GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_energy_descramble); +GR_SWIG_BLOCK_MAGIC2(dtv, catv_transport_framing_enc_bb); +GR_SWIG_BLOCK_MAGIC2(dtv, catv_reed_solomon_enc_bb); +GR_SWIG_BLOCK_MAGIC2(dtv, catv_randomizer_bb); +GR_SWIG_BLOCK_MAGIC2(dtv, catv_frame_sync_enc_bb); +GR_SWIG_BLOCK_MAGIC2(dtv, catv_trellis_enc_bb); diff --git a/gr-filter/examples/synth_to_chan.py b/gr-filter/examples/synth_to_chan.py index 9e682021b7..88fb080a65 100755 --- a/gr-filter/examples/synth_to_chan.py +++ b/gr-filter/examples/synth_to_chan.py @@ -54,7 +54,7 @@ def main(): fmtx = list() for fi in freqs: s = analog.sig_source_f(fs, analog.GR_SIN_WAVE, fi, 1) - fm = analog.nbfm_tx(fs, 4*fs, max_dev=10000, tau=75e-6) + fm = analog.nbfm_tx(fs, 4*fs, max_dev=10000, tau=75e-6, fh=0.925*(4*fs)/2.0) sigs.append(s) fmtx.append(fm) diff --git a/gr-filter/lib/pfb_decimator_ccf_impl.cc b/gr-filter/lib/pfb_decimator_ccf_impl.cc index e282b484fd..9d1d6f6139 100644 --- a/gr-filter/lib/pfb_decimator_ccf_impl.cc +++ b/gr-filter/lib/pfb_decimator_ccf_impl.cc @@ -73,6 +73,26 @@ namespace gr { else { set_history(d_taps_per_filter); } + + d_tmp = NULL; + } + + bool pfb_decimator_ccf_impl::start() + { + if(d_use_fft_filters) { + d_tmp = fft::malloc_complex(max_noutput_items()*d_rate); + } + + return block::start(); + } + + bool pfb_decimator_ccf_impl::stop() + { + if((d_use_fft_filters) && (d_tmp)) { + fft::free(d_tmp); + } + + return block::stop(); } pfb_decimator_ccf_impl::~pfb_decimator_ccf_impl() @@ -198,14 +218,13 @@ namespace gr { gr_complex *out = (gr_complex *)output_items[0]; int i; - gr_complex *tmp = fft::malloc_complex(noutput_items*d_rate); // Filter each input stream by the FFT filters; do all // noutput_items at once to avoid repeated calls to the FFT // setup and operation. for(unsigned int j = 0; j < d_rate; j++) { in = (gr_complex*)input_items[d_rate-j-1]; - d_fft_filters[j]->filter(noutput_items, in, &(tmp[j*noutput_items])); + d_fft_filters[j]->filter(noutput_items, in, &(d_tmp[j*noutput_items])); } // Rotate and add filter outputs (k=channel number; M=number of @@ -214,11 +233,10 @@ namespace gr { for(i = 0; i < noutput_items; i++) { out[i] = 0; for(unsigned int j = 0; j < d_rate; j++) { - out[i] += tmp[j*noutput_items+i]*d_rotator[j]; + out[i] += d_tmp[j*noutput_items+i]*d_rotator[j]; } } - fft::free(tmp); return noutput_items; } @@ -231,18 +249,17 @@ namespace gr { gr_complex *out = (gr_complex *)output_items[0]; int i; - gr_complex *tmp = fft::malloc_complex(noutput_items*d_rate); for(unsigned int j = 0; j < d_rate; j++) { in = (gr_complex*)input_items[d_rate-j-1]; - d_fft_filters[j]->filter(noutput_items, in, &tmp[j*noutput_items]); + d_fft_filters[j]->filter(noutput_items, in, &d_tmp[j*noutput_items]); } // Performs the rotate and add operations by implementing it as // an FFT. for(i = 0; i < noutput_items; i++) { for(unsigned int j = 0; j < d_rate; j++) { - d_fft->get_inbuf()[j] = tmp[j*noutput_items + i]; + d_fft->get_inbuf()[j] = d_tmp[j*noutput_items + i]; } // Perform the FFT to do the complex multiply despinning for all channels @@ -252,7 +269,6 @@ namespace gr { out[i] = d_fft->get_outbuf()[d_chan]; } - fft::free(tmp); return noutput_items; } diff --git a/gr-filter/lib/pfb_decimator_ccf_impl.h b/gr-filter/lib/pfb_decimator_ccf_impl.h index 3397701cf9..5e0b70177d 100644 --- a/gr-filter/lib/pfb_decimator_ccf_impl.h +++ b/gr-filter/lib/pfb_decimator_ccf_impl.h @@ -40,6 +40,7 @@ namespace gr { bool d_use_fft_rotator; bool d_use_fft_filters; gr_complex *d_rotator; + gr_complex *d_tmp; // used for fft filters gr::thread::mutex d_mutex; // mutex to protect set/work access inline int work_fir_exp(int noutput_items, @@ -55,7 +56,6 @@ namespace gr { gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - public: pfb_decimator_ccf_impl(unsigned int decim, const std::vector<float> &taps, @@ -70,6 +70,10 @@ namespace gr { std::vector<std::vector<float> > taps() const; void set_channel(const unsigned int channel); + // Overload to create/destroy d_tmp based on max_noutput_items. + bool start(); + bool stop(); + int work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); diff --git a/gr-qtgui/grc/qtgui_const_sink_x.xml b/gr-qtgui/grc/qtgui_const_sink_x.xml index 956a1694ec..755f12f964 100644 --- a/gr-qtgui/grc/qtgui_const_sink_x.xml +++ b/gr-qtgui/grc/qtgui_const_sink_x.xml @@ -22,6 +22,7 @@ self.$(id).set_x_axis($xmin, $xmax) self.$(id).set_trigger_mode($tr_mode, $tr_slope, $tr_level, $tr_chan, $tr_tag) self.$(id).enable_autoscale($autoscale) self.$(id).enable_grid($grid) +self.$(id).enable_axis_labels($axislabels) if not $legend: self.$(id).disable_legend() @@ -276,6 +277,23 @@ $(gui_hint()($win))</make> </param> <param> + <name>Axis Labels</name> + <key>axislabels</key> + <value>True</value> + <type>enum</type> + <hide>part</hide> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + <tab>Config</tab> + </param> + + <param> <name>Line 1 Label</name> <key>label1</key> <type>string</type> diff --git a/gr-qtgui/grc/qtgui_freq_sink_x.xml b/gr-qtgui/grc/qtgui_freq_sink_x.xml index d7c3139849..009a184327 100644 --- a/gr-qtgui/grc/qtgui_freq_sink_x.xml +++ b/gr-qtgui/grc/qtgui_freq_sink_x.xml @@ -22,10 +22,12 @@ qtgui.$(type.fcn)( ) self.$(id).set_update_time($update_time) self.$(id).set_y_axis($ymin, $ymax) +self.$(id).set_y_label($label, $units) self.$(id).set_trigger_mode($tr_mode, $tr_level, $tr_chan, $tr_tag) self.$(id).enable_autoscale($autoscale) self.$(id).enable_grid($grid) self.$(id).set_fft_average($average) +self.$(id).enable_axis_labels($axislabels) self.$(id).enable_control_panel($ctrlpanel) if not $legend: @@ -252,6 +254,22 @@ $(gui_hint()($win))</make> </param> <param> + <name>Y label</name> + <key>label</key> + <value>Relative Gain</value> + <type>string</type> + <hide>part</hide> + </param> + + <param> + <name>Y units</name> + <key>units</key> + <value>dB</value> + <type>string</type> + <hide>part</hide> + </param> + + <param> <name>Number of Inputs</name> <key>nconnections</key> <value>1</value> @@ -383,6 +401,23 @@ $(gui_hint()($win))</make> </param> <param> + <name>Axis Labels</name> + <key>axislabels</key> + <value>True</value> + <type>enum</type> + <hide>part</hide> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + <tab>Config</tab> + </param> + + <param> <name>Line 1 Label</name> <key>label1</key> <type>string</type> diff --git a/gr-qtgui/grc/qtgui_histogram_sink_x.xml b/gr-qtgui/grc/qtgui_histogram_sink_x.xml index a9966fd7ec..a789d2e4fa 100644 --- a/gr-qtgui/grc/qtgui_histogram_sink_x.xml +++ b/gr-qtgui/grc/qtgui_histogram_sink_x.xml @@ -24,6 +24,7 @@ self.$(id).set_update_time($update_time) self.$(id).enable_autoscale($autoscale) self.$(id).enable_accumulate($accum) self.$(id).enable_grid($grid) +self.$(id).enable_axis_labels($axislabels) if not $legend: self.$(id).disable_legend() @@ -211,6 +212,23 @@ $(gui_hint()($win)) </param> <param> + <name>Axis Labels</name> + <key>axislabels</key> + <value>True</value> + <type>enum</type> + <hide>part</hide> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + <tab>Config</tab> + </param> + + <param> <name>Line 1 Label</name> <key>label1</key> <type>string</type> diff --git a/gr-qtgui/grc/qtgui_time_raster_x.xml b/gr-qtgui/grc/qtgui_time_raster_x.xml index b36944c1e5..0359dc3b71 100644 --- a/gr-qtgui/grc/qtgui_time_raster_x.xml +++ b/gr-qtgui/grc/qtgui_time_raster_x.xml @@ -24,6 +24,7 @@ qtgui.$(type.fcn)( self.$(id).set_update_time($update_time) self.$(id).set_intensity_range($zmin, $zmax) self.$(id).enable_grid($grid) +self.$(id).enable_axis_labels($axislabels) labels = [$label1, $label2, $label3, $label4, $label5, $label6, $label7, $label8, $label9, $label10] @@ -185,6 +186,22 @@ $(gui_hint()($win))</make> <hide>part</hide> </param> + <param> + <name>Axis Labels</name> + <key>axislabels</key> + <value>True</value> + <type>enum</type> + <hide>part</hide> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + <tab>Config</tab> + </param> <param> <name>Line 1 Label</name> diff --git a/gr-qtgui/grc/qtgui_time_sink_x.xml b/gr-qtgui/grc/qtgui_time_sink_x.xml index b17b55fc48..c0584b6d34 100644 --- a/gr-qtgui/grc/qtgui_time_sink_x.xml +++ b/gr-qtgui/grc/qtgui_time_sink_x.xml @@ -27,6 +27,7 @@ self.$(id).enable_tags(-1, $entags) self.$(id).set_trigger_mode($tr_mode, $tr_slope, $tr_level, $tr_delay, $tr_chan, $tr_tag) self.$(id).enable_autoscale($autoscale) self.$(id).enable_grid($grid) +self.$(id).enable_axis_labels($axislabels) self.$(id).enable_control_panel($ctrlpanel) if not $legend: @@ -363,6 +364,23 @@ $(gui_hint()($win))</make> </param> <param> + <name>Axis Labels</name> + <key>axislabels</key> + <value>True</value> + <type>enum</type> + <hide>part</hide> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + <tab>Config</tab> + </param> + + <param> <name>Line 1 Label</name> <key>label1</key> <type>string</type> diff --git a/gr-qtgui/grc/qtgui_waterfall_sink_x.xml b/gr-qtgui/grc/qtgui_waterfall_sink_x.xml index 1d8461b8c4..cdecd5cce1 100644 --- a/gr-qtgui/grc/qtgui_waterfall_sink_x.xml +++ b/gr-qtgui/grc/qtgui_waterfall_sink_x.xml @@ -22,6 +22,7 @@ qtgui.$(type.fcn)( ) self.$(id).set_update_time($update_time) self.$(id).enable_grid($grid) +self.$(id).enable_axis_labels($axislabels) if not $legend: self.$(id).disable_legend() @@ -271,6 +272,23 @@ $(gui_hint()($win))</make> </param> <param> + <name>Axis Labels</name> + <key>axislabels</key> + <value>True</value> + <type>enum</type> + <hide>part</hide> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + <tab>Config</tab> + </param> + + <param> <name>Line 1 Color</name> <key>color1</key> <type>enum</type> diff --git a/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h b/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h index 9edff7b183..eba12e2635 100644 --- a/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h +++ b/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h @@ -190,6 +190,7 @@ public: public slots: virtual void disableLegend(); + virtual void setAxisLabels(bool en); virtual void setYaxis(double min, double max); virtual void setXaxis(double min, double max); virtual void setLineLabel(int which, QString label); diff --git a/gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h b/gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h index 8b2ef457fb..5c6b2c71b0 100644 --- a/gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h +++ b/gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h @@ -118,6 +118,9 @@ public slots: void setPlotPosHalf(bool half); + void setYLabel(const std::string &label, + const std::string &unit); + void clearMaxData(); void clearMinData(); diff --git a/gr-qtgui/include/gnuradio/qtgui/const_sink_c.h b/gr-qtgui/include/gnuradio/qtgui/const_sink_c.h index 851f3be7ca..9905eb7690 100644 --- a/gr-qtgui/include/gnuradio/qtgui/const_sink_c.h +++ b/gr-qtgui/include/gnuradio/qtgui/const_sink_c.h @@ -144,6 +144,7 @@ namespace gr { virtual void enable_menu(bool en=true) = 0; virtual void enable_autoscale(bool en) = 0; virtual void enable_grid(bool en) = 0; + virtual void enable_axis_labels(bool en=true) = 0; virtual void disable_legend() = 0; virtual int nsamps() const = 0; virtual void reset() = 0; diff --git a/gr-qtgui/include/gnuradio/qtgui/displayform.h b/gr-qtgui/include/gnuradio/qtgui/displayform.h index 2ef4b801cf..1da1383370 100644 --- a/gr-qtgui/include/gnuradio/qtgui/displayform.h +++ b/gr-qtgui/include/gnuradio/qtgui/displayform.h @@ -83,6 +83,7 @@ public slots: void setStop(); void setGrid(bool on); + void setAxisLabels(bool en); void saveFigure(); @@ -117,6 +118,8 @@ protected: bool d_stop_state; QAction *d_grid_act; bool d_grid_state; + QAction *d_axislabelsmenu; + bool d_axislabels; QAction *d_autoscale_act; bool d_autoscale_state; diff --git a/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h b/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h index bf5a91f0df..3aea2d1b84 100644 --- a/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h +++ b/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h @@ -128,6 +128,7 @@ namespace gr { virtual void set_update_time(double t) = 0; virtual void set_title(const std::string &title) = 0; + virtual void set_y_label(const std::string &label, const std::string &unit) = 0; virtual void set_line_label(int which, const std::string &label) = 0; virtual void set_line_color(int which, const std::string &color) = 0; virtual void set_line_width(int which, int width) = 0; @@ -182,6 +183,7 @@ namespace gr { virtual void clear_min_hold() = 0; virtual void disable_legend() = 0; virtual void reset() = 0; + virtual void enable_axis_labels(bool en=true) = 0; QApplication *d_qApplication; }; diff --git a/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h index f13d5c6e40..eb68806c07 100644 --- a/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h +++ b/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h @@ -126,7 +126,9 @@ namespace gr { virtual void set_y_axis(double min, double max) = 0; virtual void set_update_time(double t) = 0; + virtual void set_title(const std::string &title) = 0; + virtual void set_y_label(const std::string &label, const std::string &unit) = 0; virtual void set_line_label(int which, const std::string &label) = 0; virtual void set_line_color(int which, const std::string &color) = 0; virtual void set_line_width(int which, int width) = 0; @@ -188,6 +190,7 @@ namespace gr { virtual void clear_min_hold() = 0; virtual void disable_legend() = 0; virtual void reset() = 0; + virtual void enable_axis_labels(bool en=true) = 0; QApplication *d_qApplication; }; diff --git a/gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h b/gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h index ce0aeedf9f..ec3ef6cfd1 100644 --- a/gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h +++ b/gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h @@ -76,6 +76,7 @@ private: QVBoxLayout *d_axes_layout; QCheckBox *d_grid_check; + QCheckBox *d_axislabels_check; QHBoxLayout *d_yrange_layout; QLabel *d_yrange_label; QPushButton *d_yrange_plus; diff --git a/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h b/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h index e7b95cb30e..4d8ed3e2a1 100644 --- a/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h +++ b/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h @@ -75,6 +75,8 @@ public slots: void setFrequencyRange(const double centerfreq, const double bandwidth); void setYaxis(double min, double max); + void setYLabel(const std::string &label, + const std::string &unit=""); void setYMax(const QString &m); void setYMin(const QString &m); void autoScale(bool en); @@ -108,7 +110,6 @@ public slots: void notifyTriggerLevelPlus(); void notifyTriggerLevelMinus(); - signals: void signalFFTSize(int size); void signalFFTWindow(gr::filter::firdes::win_type win); diff --git a/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h index 431941a414..6e7dee005d 100644 --- a/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h +++ b/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h @@ -121,6 +121,7 @@ namespace gr { virtual void enable_semilogx(bool en=true) = 0; virtual void enable_semilogy(bool en=true) = 0; virtual void enable_accumulate(bool en=true) = 0; + virtual void enable_axis_labels(bool en=true) = 0; virtual void autoscalex() = 0; virtual int nsamps() const = 0; virtual int bins() const = 0; diff --git a/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_b.h b/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_b.h index ed55e2ed50..efaef1cc4b 100644 --- a/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_b.h +++ b/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_b.h @@ -131,6 +131,7 @@ namespace gr { virtual void enable_menu(bool en) = 0; virtual void enable_grid(bool en) = 0; virtual void enable_autoscale(bool en) = 0; + virtual void enable_axis_labels(bool en=true) = 0; virtual void reset() = 0; QApplication *d_qApplication; diff --git a/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_f.h index 5610dabdda..ae2ec8d11b 100644 --- a/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_f.h +++ b/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_f.h @@ -127,6 +127,7 @@ namespace gr { virtual void enable_menu(bool en) = 0; virtual void enable_grid(bool en) = 0; virtual void enable_autoscale(bool en) = 0; + virtual void enable_axis_labels(bool en=true) = 0; virtual void reset() = 0; QApplication *d_qApplication; diff --git a/gr-qtgui/include/gnuradio/qtgui/time_sink_c.h b/gr-qtgui/include/gnuradio/qtgui/time_sink_c.h index 10c87c8bf2..af921afc1b 100644 --- a/gr-qtgui/include/gnuradio/qtgui/time_sink_c.h +++ b/gr-qtgui/include/gnuradio/qtgui/time_sink_c.h @@ -170,6 +170,7 @@ namespace gr { virtual void enable_semilogy(bool en=true) = 0; virtual void enable_control_panel(bool en=true) = 0; virtual void enable_tags(int which, bool en) = 0; + virtual void enable_axis_labels(bool en=true) = 0; virtual void disable_legend() = 0; virtual int nsamps() const = 0; diff --git a/gr-qtgui/include/gnuradio/qtgui/time_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/time_sink_f.h index d96383c0e8..7ddca46297 100644 --- a/gr-qtgui/include/gnuradio/qtgui/time_sink_f.h +++ b/gr-qtgui/include/gnuradio/qtgui/time_sink_f.h @@ -160,6 +160,7 @@ namespace gr { virtual void enable_semilogy(bool en=true) = 0; virtual void enable_control_panel(bool en=true) = 0; virtual void enable_tags(int which, bool en) = 0; + virtual void enable_axis_labels(bool en=true) = 0; virtual void disable_legend() = 0; virtual int nsamps() const = 0; diff --git a/gr-qtgui/include/gnuradio/qtgui/timecontrolpanel.h b/gr-qtgui/include/gnuradio/qtgui/timecontrolpanel.h index aabd890e6e..d7cbf5431b 100644 --- a/gr-qtgui/include/gnuradio/qtgui/timecontrolpanel.h +++ b/gr-qtgui/include/gnuradio/qtgui/timecontrolpanel.h @@ -75,6 +75,8 @@ private: QCheckBox *d_autoscale_check; QCheckBox *d_grid_check; + QCheckBox *d_axislabels_check; + QPushButton *d_yoff_plus, *d_yoff_minus; QPushButton *d_yrange_plus, *d_yrange_minus; QPushButton *d_xmax_plus, *d_xmax_minus; diff --git a/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_c.h b/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_c.h index 71a8b925bb..1e4073aa01 100644 --- a/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_c.h +++ b/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_c.h @@ -156,6 +156,7 @@ namespace gr { virtual void enable_menu(bool en=true) = 0; virtual void enable_grid(bool en=true) = 0; virtual void disable_legend() = 0; + virtual void enable_axis_labels(bool en=true) = 0; QApplication *d_qApplication; }; diff --git a/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_f.h index 2a51fba865..93c93bdd5e 100644 --- a/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_f.h +++ b/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_f.h @@ -164,6 +164,7 @@ namespace gr { virtual void enable_menu(bool en=true) = 0; virtual void enable_grid(bool en=true) = 0; virtual void disable_legend() = 0; + virtual void enable_axis_labels(bool en=true) = 0; QApplication *d_qApplication; }; diff --git a/gr-qtgui/lib/DisplayPlot.cc b/gr-qtgui/lib/DisplayPlot.cc index 30fd837772..59384c88f6 100644 --- a/gr-qtgui/lib/DisplayPlot.cc +++ b/gr-qtgui/lib/DisplayPlot.cc @@ -443,3 +443,12 @@ DisplayPlot::onPickerPointSelected6(const QPointF & p) //fprintf(stderr,"onPickerPointSelected %f %f\n", point.x(), point.y()); emit plotPointSelected(point); } + +void +DisplayPlot::setAxisLabels(bool en) +{ + enableAxis(0,en); + enableAxis(2,en); +} + + diff --git a/gr-qtgui/lib/FrequencyDisplayPlot.cc b/gr-qtgui/lib/FrequencyDisplayPlot.cc index aef975d332..233c786d0a 100644 --- a/gr-qtgui/lib/FrequencyDisplayPlot.cc +++ b/gr-qtgui/lib/FrequencyDisplayPlot.cc @@ -97,7 +97,7 @@ FrequencyDisplayPlot::FrequencyDisplayPlot(int nplots, QWidget* parent) d_ymax = 10; setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine); setAxisScale(QwtPlot::yLeft, d_ymin, d_ymax); - setAxisTitle(QwtPlot::yLeft, "Power (dB)"); + setAxisTitle(QwtPlot::yLeft, "Relative Gain (dB)"); QList<QColor> default_colors; default_colors << QColor(Qt::blue) << QColor(Qt::red) << QColor(Qt::green) @@ -600,6 +600,17 @@ FrequencyDisplayPlot::onPickerPointSelected6(const QPointF & p) } void +FrequencyDisplayPlot::setYLabel(const std::string &label, + const std::string &unit) +{ + std::string l = label; + if(unit.length() > 0) + l += " (" + unit + ")"; + setAxisTitle(QwtPlot::yLeft, QString(l.c_str())); + ((FreqDisplayZoomer*)d_zoomer)->setUnitType(unit); +} + +void FrequencyDisplayPlot::setMinFFTColor (QColor c) { d_min_fft_color = c; diff --git a/gr-qtgui/lib/WaterfallDisplayPlot.cc b/gr-qtgui/lib/WaterfallDisplayPlot.cc index 676e4077db..b16c32bf9d 100644 --- a/gr-qtgui/lib/WaterfallDisplayPlot.cc +++ b/gr-qtgui/lib/WaterfallDisplayPlot.cc @@ -657,8 +657,6 @@ WaterfallDisplayPlot::_updateIntensityRangeDisplay() setAxisScale(QwtPlot::yRight, intv.minValue(), intv.maxValue()); #endif - enableAxis(d_legend_enabled); - plotLayout()->setAlignCanvasToScales(true); // Tell the display to redraw everything diff --git a/gr-qtgui/lib/const_sink_c_impl.cc b/gr-qtgui/lib/const_sink_c_impl.cc index 7ef8db393d..eaaf5f570a 100644 --- a/gr-qtgui/lib/const_sink_c_impl.cc +++ b/gr-qtgui/lib/const_sink_c_impl.cc @@ -375,6 +375,12 @@ namespace gr { } void + const_sink_c_impl::enable_axis_labels(bool en) + { + d_main_gui->setAxisLabels(en); + } + + void const_sink_c_impl::disable_legend() { d_main_gui->disableLegend(); diff --git a/gr-qtgui/lib/const_sink_c_impl.h b/gr-qtgui/lib/const_sink_c_impl.h index 7d52c3ae15..f2dcb6e73e 100644 --- a/gr-qtgui/lib/const_sink_c_impl.h +++ b/gr-qtgui/lib/const_sink_c_impl.h @@ -118,6 +118,7 @@ namespace gr { void enable_menu(bool en); void enable_autoscale(bool en); void enable_grid(bool en); + void enable_axis_labels(bool en); void disable_legend(); void reset(); diff --git a/gr-qtgui/lib/displayform.cc b/gr-qtgui/lib/displayform.cc index 27a09512fc..13c2d8a193 100644 --- a/gr-qtgui/lib/displayform.cc +++ b/gr-qtgui/lib/displayform.cc @@ -29,6 +29,7 @@ DisplayForm::DisplayForm(int nplots, QWidget* parent) : QWidget(parent), d_nplots(nplots), d_system_specified_flag(false) { d_isclosed = false; + d_axislabels = true; // Set the initial plot size resize(QSize(800, 600)); @@ -53,11 +54,18 @@ DisplayForm::DisplayForm(int nplots, QWidget* parent) this, SLOT(setGrid(bool))); d_grid_state = false; + d_axislabelsmenu = new QAction("Axis Labels", this); + d_axislabelsmenu->setCheckable(true); + d_axislabelsmenu->setStatusTip(tr("Toggle Axis Labels on/off")); + connect(d_axislabelsmenu, SIGNAL(triggered(bool)), + this, SLOT(setAxisLabels(bool))); + // Create a pop-up menu for manipulating the figure d_menu_on = true; d_menu = new QMenu(this); d_menu->addAction(d_stop_act); d_menu->addAction(d_grid_act); + d_menu->addAction(d_axislabelsmenu); for(int i = 0; i < d_nplots; i++) { d_line_title_act.push_back(new LineTitleAction(i, this)); @@ -339,6 +347,14 @@ DisplayForm::setGrid(bool on) } void +DisplayForm::setAxisLabels(bool en) +{ + d_axislabels = en; + d_axislabelsmenu->setChecked(en); + getPlot()->setAxisLabels(d_axislabels); +} + +void DisplayForm::saveFigure() { QPixmap qpix = QPixmap::grabWidget(this); diff --git a/gr-qtgui/lib/freq_sink_c_impl.cc b/gr-qtgui/lib/freq_sink_c_impl.cc index 7dc0b2cf89..517786d58d 100644 --- a/gr-qtgui/lib/freq_sink_c_impl.cc +++ b/gr-qtgui/lib/freq_sink_c_impl.cc @@ -266,6 +266,13 @@ namespace gr { } void + freq_sink_c_impl::set_y_label(const std::string &label, + const std::string &unit) + { + d_main_gui->setYLabel(label, unit); + } + + void freq_sink_c_impl::set_update_time(double t) { //convert update time to ticks @@ -407,6 +414,12 @@ namespace gr { } void + freq_sink_c_impl::enable_axis_labels(bool en) + { + d_main_gui->setAxisLabels(en); + } + + void freq_sink_c_impl::enable_control_panel(bool en) { if(en) diff --git a/gr-qtgui/lib/freq_sink_c_impl.h b/gr-qtgui/lib/freq_sink_c_impl.h index 8da193bf29..b102209359 100644 --- a/gr-qtgui/lib/freq_sink_c_impl.h +++ b/gr-qtgui/lib/freq_sink_c_impl.h @@ -123,6 +123,7 @@ namespace gr { void set_update_time(double t); void set_title(const std::string &title); + void set_y_label(const std::string &label, const std::string &unit); void set_line_label(int which, const std::string &label); void set_line_color(int which, const std::string &color); void set_line_width(int which, int width); @@ -153,6 +154,7 @@ namespace gr { void clear_min_hold(); void disable_legend(); void reset(); + void enable_axis_labels(bool en); int work(int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gr-qtgui/lib/freq_sink_f_impl.cc b/gr-qtgui/lib/freq_sink_f_impl.cc index 5418eca9ec..90624e78eb 100644 --- a/gr-qtgui/lib/freq_sink_f_impl.cc +++ b/gr-qtgui/lib/freq_sink_f_impl.cc @@ -265,6 +265,13 @@ namespace gr { } void + freq_sink_f_impl::set_y_label(const std::string &label, + const std::string &unit) + { + d_main_gui->setYLabel(label, unit); + } + + void freq_sink_f_impl::set_update_time(double t) { //convert update time to ticks @@ -412,6 +419,12 @@ namespace gr { } void + freq_sink_f_impl::enable_axis_labels(bool en) + { + d_main_gui->setAxisLabels(en); + } + + void freq_sink_f_impl::enable_control_panel(bool en) { if(en) diff --git a/gr-qtgui/lib/freq_sink_f_impl.h b/gr-qtgui/lib/freq_sink_f_impl.h index 39e5c92eac..85d45b3f4c 100644 --- a/gr-qtgui/lib/freq_sink_f_impl.h +++ b/gr-qtgui/lib/freq_sink_f_impl.h @@ -122,6 +122,7 @@ namespace gr { void set_update_time(double t); void set_title(const std::string &title); + void set_y_label(const std::string &label, const std::string &unit); void set_line_label(int which, const std::string &label); void set_line_color(int which, const std::string &color); void set_line_width(int which, int width); @@ -153,6 +154,7 @@ namespace gr { void clear_min_hold(); void disable_legend(); void reset(); + void enable_axis_labels(bool en); int work(int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gr-qtgui/lib/freqcontrolpanel.cc b/gr-qtgui/lib/freqcontrolpanel.cc index 5840989949..9729005f50 100644 --- a/gr-qtgui/lib/freqcontrolpanel.cc +++ b/gr-qtgui/lib/freqcontrolpanel.cc @@ -50,6 +50,7 @@ FreqControlPanel::FreqControlPanel(FreqDisplayForm *form) d_axes_layout = new QVBoxLayout; d_grid_check = new QCheckBox("Grid"); + d_axislabels_check = new QCheckBox("Axis Labels"); d_yrange_layout = new QHBoxLayout; d_yrange_label = new QLabel("Y Range:"); d_yrange_plus = new QPushButton("+"); @@ -133,6 +134,7 @@ FreqControlPanel::FreqControlPanel(FreqDisplayForm *form) d_trace_box->setLayout(d_trace_layout); d_axes_layout->addWidget(d_grid_check); + d_axes_layout->addWidget(d_axislabels_check); d_axes_layout->addLayout(d_yrange_layout); d_axes_layout->addLayout(d_ymin_layout); d_axes_layout->addWidget(d_autoscale_button); @@ -171,6 +173,9 @@ FreqControlPanel::FreqControlPanel(FreqDisplayForm *form) connect(d_grid_check, SIGNAL(clicked(bool)), d_parent, SLOT(setGrid(bool))); + connect(d_axislabels_check, SIGNAL(clicked(bool)), + d_parent, SLOT(setAxisLabels(bool))); + connect(d_ymin_plus, SIGNAL(pressed(void)), d_parent, SLOT(notifyYAxisPlus(void))); connect(d_ymin_minus, SIGNAL(pressed(void)), diff --git a/gr-qtgui/lib/freqdisplayform.cc b/gr-qtgui/lib/freqdisplayform.cc index a51da3f35d..141df5475c 100644 --- a/gr-qtgui/lib/freqdisplayform.cc +++ b/gr-qtgui/lib/freqdisplayform.cc @@ -323,6 +323,12 @@ FreqDisplayForm::setYaxis(double min, double max) getPlot()->setYaxis(min, max); } +void FreqDisplayForm::setYLabel(const std::string &label, + const std::string &unit) +{ + getPlot()->setYLabel(label, unit); +} + void FreqDisplayForm::setYMax(const QString &m) { diff --git a/gr-qtgui/lib/histogram_sink_f_impl.cc b/gr-qtgui/lib/histogram_sink_f_impl.cc index 0ac494d751..4a1267c129 100644 --- a/gr-qtgui/lib/histogram_sink_f_impl.cc +++ b/gr-qtgui/lib/histogram_sink_f_impl.cc @@ -346,6 +346,12 @@ namespace gr { } void + histogram_sink_f_impl::enable_axis_labels(bool en) + { + d_main_gui->setAxisLabels(en); + } + + void histogram_sink_f_impl::enable_autoscale(bool en) { d_main_gui->autoScale(en); diff --git a/gr-qtgui/lib/histogram_sink_f_impl.h b/gr-qtgui/lib/histogram_sink_f_impl.h index acacf1a745..d397beeb6b 100644 --- a/gr-qtgui/lib/histogram_sink_f_impl.h +++ b/gr-qtgui/lib/histogram_sink_f_impl.h @@ -88,6 +88,7 @@ namespace gr { void set_line_alpha(int which, double alpha); void set_nsamps(const int newsize); void set_bins(const int bins); + void enable_axis_labels(bool en); std::string title(); std::string line_label(int which); diff --git a/gr-qtgui/lib/time_raster_sink_b_impl.cc b/gr-qtgui/lib/time_raster_sink_b_impl.cc index 26fed4b062..c0990a9890 100644 --- a/gr-qtgui/lib/time_raster_sink_b_impl.cc +++ b/gr-qtgui/lib/time_raster_sink_b_impl.cc @@ -418,6 +418,12 @@ namespace gr { } void + time_raster_sink_b_impl::enable_axis_labels(bool en) + { + d_main_gui->setAxisLabels(en); + } + + void time_raster_sink_b_impl::enable_autoscale(bool en) { d_main_gui->autoScale(en); diff --git a/gr-qtgui/lib/time_raster_sink_b_impl.h b/gr-qtgui/lib/time_raster_sink_b_impl.h index 4da6990a18..48037b5e5e 100644 --- a/gr-qtgui/lib/time_raster_sink_b_impl.h +++ b/gr-qtgui/lib/time_raster_sink_b_impl.h @@ -122,6 +122,7 @@ namespace gr { void enable_menu(bool en); void enable_grid(bool en); void enable_autoscale(bool en); + void enable_axis_labels(bool en); void reset(); int work(int noutput_items, diff --git a/gr-qtgui/lib/time_raster_sink_f_impl.cc b/gr-qtgui/lib/time_raster_sink_f_impl.cc index 419d52cad6..2fb3e7db68 100644 --- a/gr-qtgui/lib/time_raster_sink_f_impl.cc +++ b/gr-qtgui/lib/time_raster_sink_f_impl.cc @@ -408,6 +408,12 @@ namespace gr { } void + time_raster_sink_f_impl::enable_axis_labels(bool en) + { + d_main_gui->setAxisLabels(en); + } + + void time_raster_sink_f_impl::enable_autoscale(bool en) { d_main_gui->autoScale(en); diff --git a/gr-qtgui/lib/time_raster_sink_f_impl.h b/gr-qtgui/lib/time_raster_sink_f_impl.h index ad63e4d777..1f25dc5534 100644 --- a/gr-qtgui/lib/time_raster_sink_f_impl.h +++ b/gr-qtgui/lib/time_raster_sink_f_impl.h @@ -121,6 +121,7 @@ namespace gr { void enable_menu(bool en); void enable_grid(bool en); void enable_autoscale(bool en); + void enable_axis_labels(bool en); void reset(); int work(int noutput_items, diff --git a/gr-qtgui/lib/time_sink_c_impl.cc b/gr-qtgui/lib/time_sink_c_impl.cc index fff12b070a..98f603a8b0 100644 --- a/gr-qtgui/lib/time_sink_c_impl.cc +++ b/gr-qtgui/lib/time_sink_c_impl.cc @@ -441,10 +441,16 @@ namespace gr { d_main_gui->setTagMenu(which, en); } + void + time_sink_c_impl::enable_axis_labels(bool en) + { + d_main_gui->setAxisLabels(en); + } + void time_sink_c_impl::disable_legend() { - d_main_gui->disableLegend(); + d_main_gui->disableLegend(); } void diff --git a/gr-qtgui/lib/time_sink_c_impl.h b/gr-qtgui/lib/time_sink_c_impl.h index ce6bd94d51..ff938f8ea1 100644 --- a/gr-qtgui/lib/time_sink_c_impl.h +++ b/gr-qtgui/lib/time_sink_c_impl.h @@ -130,6 +130,7 @@ namespace gr { void enable_semilogy(bool en); void enable_control_panel(bool en); void enable_tags(int which, bool en); + void enable_axis_labels(bool en); void disable_legend(); void reset(); diff --git a/gr-qtgui/lib/time_sink_f_impl.cc b/gr-qtgui/lib/time_sink_f_impl.cc index 579dfd9906..50a86d7dff 100644 --- a/gr-qtgui/lib/time_sink_f_impl.cc +++ b/gr-qtgui/lib/time_sink_f_impl.cc @@ -437,6 +437,12 @@ namespace gr { } void + time_sink_f_impl::enable_axis_labels(bool en) + { + d_main_gui->setAxisLabels(en); + } + + void time_sink_f_impl::disable_legend() { d_main_gui->disableLegend(); diff --git a/gr-qtgui/lib/time_sink_f_impl.h b/gr-qtgui/lib/time_sink_f_impl.h index 25d920c0da..a7a304aee1 100644 --- a/gr-qtgui/lib/time_sink_f_impl.h +++ b/gr-qtgui/lib/time_sink_f_impl.h @@ -130,6 +130,7 @@ namespace gr { void enable_semilogy(bool en); void enable_control_panel(bool en); void enable_tags(int which, bool en); + void enable_axis_labels(bool en); void disable_legend(); void reset(); diff --git a/gr-qtgui/lib/timecontrolpanel.cc b/gr-qtgui/lib/timecontrolpanel.cc index 4c5a718f97..95d2cb7a1c 100644 --- a/gr-qtgui/lib/timecontrolpanel.cc +++ b/gr-qtgui/lib/timecontrolpanel.cc @@ -31,6 +31,8 @@ TimeControlPanel::TimeControlPanel(TimeDisplayForm *form) d_axes_layout = new QVBoxLayout; d_autoscale_check = new QCheckBox("Autoscale"); d_grid_check = new QCheckBox("Grid"); + d_axislabels_check = new QCheckBox("Axis Labels"); + d_axislabels_check->setChecked(true); d_yoff_layout = new QHBoxLayout; d_yoff_label = new QLabel("Y Offset:"); @@ -106,6 +108,7 @@ TimeControlPanel::TimeControlPanel(TimeDisplayForm *form) // Set up the boxes into the layout d_axes_layout->addWidget(d_autoscale_check); d_axes_layout->addWidget(d_grid_check); + d_axes_layout->addWidget(d_axislabels_check); d_axes_layout->addLayout(d_yoff_layout); d_axes_layout->addLayout(d_yrange_layout); d_axes_layout->addLayout(d_xmax_layout); @@ -132,6 +135,8 @@ TimeControlPanel::TimeControlPanel(TimeDisplayForm *form) d_parent, SLOT(autoScale(bool))); connect(d_grid_check, SIGNAL(clicked(bool)), d_parent, SLOT(setGrid(bool))); + connect(d_axislabels_check, SIGNAL(clicked(bool)), + d_parent, SLOT(setAxisLabels(bool))); connect(d_yoff_plus, SIGNAL(pressed(void)), d_parent, SLOT(notifyYAxisPlus(void))); connect(d_yoff_minus, SIGNAL(pressed(void)), diff --git a/gr-qtgui/lib/waterfall_sink_c_impl.cc b/gr-qtgui/lib/waterfall_sink_c_impl.cc index 694ef4dac7..7395aaf2a9 100644 --- a/gr-qtgui/lib/waterfall_sink_c_impl.cc +++ b/gr-qtgui/lib/waterfall_sink_c_impl.cc @@ -368,6 +368,12 @@ namespace gr { } void + waterfall_sink_c_impl::enable_axis_labels(bool en) + { + d_main_gui->setAxisLabels(en); + } + + void waterfall_sink_c_impl::disable_legend() { d_main_gui->disableLegend(); diff --git a/gr-qtgui/lib/waterfall_sink_c_impl.h b/gr-qtgui/lib/waterfall_sink_c_impl.h index 3e7f9ddd2d..49766cd3dc 100644 --- a/gr-qtgui/lib/waterfall_sink_c_impl.h +++ b/gr-qtgui/lib/waterfall_sink_c_impl.h @@ -132,6 +132,7 @@ namespace gr { void enable_menu(bool en); void enable_grid(bool en); void disable_legend(); + void enable_axis_labels(bool en); int work(int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gr-qtgui/lib/waterfall_sink_f_impl.cc b/gr-qtgui/lib/waterfall_sink_f_impl.cc index 56c2061f25..b6f50de31d 100644 --- a/gr-qtgui/lib/waterfall_sink_f_impl.cc +++ b/gr-qtgui/lib/waterfall_sink_f_impl.cc @@ -374,6 +374,12 @@ namespace gr { } void + waterfall_sink_f_impl::enable_axis_labels(bool en) + { + d_main_gui->setAxisLabels(en); + } + + void waterfall_sink_f_impl::disable_legend() { d_main_gui->disableLegend(); diff --git a/gr-qtgui/lib/waterfall_sink_f_impl.h b/gr-qtgui/lib/waterfall_sink_f_impl.h index e4f855c9f5..db0f4239bc 100644 --- a/gr-qtgui/lib/waterfall_sink_f_impl.h +++ b/gr-qtgui/lib/waterfall_sink_f_impl.h @@ -133,6 +133,7 @@ namespace gr { void enable_menu(bool en); void enable_grid(bool en); void disable_legend(); + void enable_axis_labels(bool en); int work(int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gr-uhd/apps/uhd_app.py b/gr-uhd/apps/uhd_app.py index 59bebe24ec..ff4412a140 100644 --- a/gr-uhd/apps/uhd_app.py +++ b/gr-uhd/apps/uhd_app.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2015 Free Software Foundation, Inc. +# Copyright 2015-2016 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -141,6 +141,9 @@ class UHDApp(object): if args.spec: for mb_idx in xrange(self.usrp.get_num_mboards()): self.usrp.set_subdev_spec(args.spec, mb_idx) + # Set the clock source: + if args.clock_source is not None: + self.usrp.set_clock_source(args.clock_source) # Sampling rate: self.usrp.set_samp_rate(args.samp_rate) self.samp_rate = self.usrp.get_samp_rate() @@ -305,5 +308,7 @@ class UHDApp(object): help="Show asynchronous message notifications from UHD") group.add_argument("--sync", choices=('default', 'pps', 'auto'), default='auto', help="Set to 'pps' to sync devices to PPS") + group.add_argument("--clock-source", + help="Set the clock source; typically 'internal', 'external' or 'gpsdo'") return parser diff --git a/gr-uhd/examples/python/fm_tx4.py b/gr-uhd/examples/python/fm_tx4.py index fefa67861b..516033dae1 100755 --- a/gr-uhd/examples/python/fm_tx4.py +++ b/gr-uhd/examples/python/fm_tx4.py @@ -63,7 +63,8 @@ class pipeline(gr.hier_block2): sys.exit(1) print audio_rate, if_rate - fmtx = analog.nbfm_tx(audio_rate, if_rate, max_dev=5e3, tau=75e-6) + fmtx = analog.nbfm_tx(audio_rate, if_rate, max_dev=5e3, + tau=75e-6, fh=0.925*if_rate/2.0) # Local oscillator lo = analog.sig_source_c(if_rate, # sample rate diff --git a/gr-uhd/include/gnuradio/uhd/usrp_source.h b/gr-uhd/include/gnuradio/uhd/usrp_source.h index 19b3feb61f..19201c031c 100644 --- a/gr-uhd/include/gnuradio/uhd/usrp_source.h +++ b/gr-uhd/include/gnuradio/uhd/usrp_source.h @@ -96,10 +96,13 @@ namespace gr { /*! * \param device_addr the address to identify the hardware * \param stream_args the IO format and channel specification + * \param issue_stream_cmd_on_start enable or disable continuous streaming when flowgraph + * starts (default true) * \return a new USRP source block object */ static sptr make(const ::uhd::device_addr_t &device_addr, - const ::uhd::stream_args_t &stream_args); + const ::uhd::stream_args_t &stream_args, + const bool issue_stream_cmd_on_start = true); /*! * Set the start time for incoming samples. diff --git a/gr-uhd/lib/usrp_source_impl.cc b/gr-uhd/lib/usrp_source_impl.cc index eeb9521a5a..7ad2280955 100644 --- a/gr-uhd/lib/usrp_source_impl.cc +++ b/gr-uhd/lib/usrp_source_impl.cc @@ -53,20 +53,23 @@ namespace gr { usrp_source::sptr usrp_source::make(const ::uhd::device_addr_t &device_addr, - const ::uhd::stream_args_t &stream_args) + const ::uhd::stream_args_t &stream_args, + const bool issue_stream_cmd_on_start) { check_abi(); return usrp_source::sptr - (new usrp_source_impl(device_addr, stream_args_ensure(stream_args))); + (new usrp_source_impl(device_addr, stream_args_ensure(stream_args), issue_stream_cmd_on_start)); } usrp_source_impl::usrp_source_impl(const ::uhd::device_addr_t &device_addr, - const ::uhd::stream_args_t &stream_args): + const ::uhd::stream_args_t &stream_args, + const bool issue_stream_cmd_on_start): usrp_block("gr uhd usrp source", io_signature::make(0, 0, 0), args_to_io_sig(stream_args)), usrp_block_impl(device_addr, stream_args, ""), - _tag_now(false) + _tag_now(false), + _issue_stream_cmd_on_start(issue_stream_cmd_on_start) { std::stringstream str; str << name() << unique_id(); @@ -382,18 +385,20 @@ namespace gr { _samps_per_packet = _rx_stream->get_max_num_samps(); } #endif - //setup a stream command that starts streaming slightly in the future - static const double reasonable_delay = 0.1; //order of magnitude over RTT - ::uhd::stream_cmd_t stream_cmd(::uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - stream_cmd.stream_now = _stream_now; - if(_start_time_set) { - _start_time_set = false; //cleared for next run - stream_cmd.time_spec = _start_time; - } - else { - stream_cmd.time_spec = get_time_now() + ::uhd::time_spec_t(reasonable_delay); + if(_issue_stream_cmd_on_start){ + //setup a stream command that starts streaming slightly in the future + static const double reasonable_delay = 0.1; //order of magnitude over RTT + ::uhd::stream_cmd_t stream_cmd(::uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); + stream_cmd.stream_now = _stream_now; + if(_start_time_set) { + _start_time_set = false; //cleared for next run + stream_cmd.time_spec = _start_time; + } + else { + stream_cmd.time_spec = get_time_now() + ::uhd::time_spec_t(reasonable_delay); + } + this->issue_stream_cmd(stream_cmd); } - this->issue_stream_cmd(stream_cmd); _tag_now = true; return true; } diff --git a/gr-uhd/lib/usrp_source_impl.h b/gr-uhd/lib/usrp_source_impl.h index 98af816c02..b43df4dab3 100644 --- a/gr-uhd/lib/usrp_source_impl.h +++ b/gr-uhd/lib/usrp_source_impl.h @@ -55,7 +55,8 @@ namespace gr { { public: usrp_source_impl(const ::uhd::device_addr_t &device_addr, - const ::uhd::stream_args_t &stream_args); + const ::uhd::stream_args_t &stream_args, + const bool issue_stream_cmd_on_start = true); ~usrp_source_impl(); // Get Commands @@ -119,6 +120,7 @@ namespace gr { bool _tag_now; ::uhd::rx_metadata_t _metadata; pmt::pmt_t _id; + bool _issue_stream_cmd_on_start; //tag shadows double _samp_rate; diff --git a/gr-utils/python/modtool/gr-newmod/CMakeLists.txt b/gr-utils/python/modtool/gr-newmod/CMakeLists.txt index 9b41b99f14..6f32f21833 100644 --- a/gr-utils/python/modtool/gr-newmod/CMakeLists.txt +++ b/gr-utils/python/modtool/gr-newmod/CMakeLists.txt @@ -24,6 +24,12 @@ cmake_minimum_required(VERSION 2.6) project(gr-howto CXX C) enable_testing() +#install to PyBOMBS target prefix if defined +if(DEFINED ENV{PYBOMBS_PREFIX}) + set(CMAKE_INSTALL_PREFIX $ENV{PYBOMBS_PREFIX}) + message(STATUS "PyBOMBS installed GNU Radio. Setting CMAKE_INSTALL_PREFIX to $ENV{PYBOMBS_PREFIX}") +endif() + #select the release build type by default to get optimization flags if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") diff --git a/gr-utils/python/modtool/modtool_add.py b/gr-utils/python/modtool/modtool_add.py index a4812c8105..3627dc6ad1 100644 --- a/gr-utils/python/modtool/modtool_add.py +++ b/gr-utils/python/modtool/modtool_add.py @@ -53,6 +53,8 @@ class ModToolAdd(ModTool): choices=self._block_types, default=None, help="One of %s." % ', '.join(self._block_types)) ogroup.add_option("--license-file", type="string", default=None, help="File containing the license header for every source code file.") + ogroup.add_option("--copyright", type="string", default=None, + help="Name of the copyright holder (you or your company) MUST be a quoted string.") ogroup.add_option("--argument-list", type="string", default=None, help="The argument list for the constructor and make functions.") ogroup.add_option("--add-python-qa", action="store_true", default=None, @@ -77,7 +79,6 @@ class ModToolAdd(ModTool): self._info['blocktype'] = raw_input("Enter block type: ") if self._info['blocktype'] not in self._block_types: print 'Must be one of ' + str(self._block_types) - # Allow user to specify language interactively if not set self._info['lang'] = options.lang if self._info['lang'] is None: @@ -102,8 +103,14 @@ class ModToolAdd(ModTool): raise ModToolException('Invalid block name.') print "Block/code identifier: " + self._info['blockname'] self._info['fullblockname'] = self._info['modname'] + '_' + self._info['blockname'] + if not options.license_file: + self._info['copyrightholder'] = options.copyright + if self._info['copyrightholder'] is None: + self._info['copyrightholder'] = '<+YOU OR YOUR COMPANY+>' + elif self._info['is_component']: + print "For GNU Radio components the FSF is added as copyright holder" + self._license_file = options.license_file self._info['license'] = self.setup_choose_license() - if options.argument_list is not None: self._info['arglist'] = options.argument_list else: @@ -122,7 +129,6 @@ class ModToolAdd(ModTool): print "Warning: Autotools modules are not supported. ", print "Files will be created, but Makefiles will not be edited." self._skip_cmakefiles = True - self._license_file = options.license_file def setup_choose_license(self): """ Select a license by the following rules, in this order: @@ -140,7 +146,7 @@ class ModToolAdd(ModTool): elif self._info['is_component']: return Templates['grlicense'] else: - return Templates['defaultlicense'] + return get_template('defaultlicense', **self._info) def _write_tpl(self, tpl, path, fname): """ Shorthand for writing a substituted template to a file""" diff --git a/gr-utils/python/modtool/templates.py b/gr-utils/python/modtool/templates.py index dc840df392..9caf658194 100644 --- a/gr-utils/python/modtool/templates.py +++ b/gr-utils/python/modtool/templates.py @@ -26,7 +26,7 @@ Templates = {} # Default licence Templates['defaultlicense'] = ''' -Copyright %d <+YOU OR YOUR COMPANY+>. +Copyright %d ${copyrightholder}. This is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index 859b9e9045..4c782a7f7d 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -96,8 +96,10 @@ install( COMPONENT "grc" ) +file(GLOB py_files "*.py") + GR_PYTHON_INSTALL( - FILES __init__.py + FILES ${py_files} DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc COMPONENT "grc" ) @@ -133,13 +135,9 @@ endif(WIN32) ######################################################################## # Add subdirectories ######################################################################## -add_subdirectory(base) add_subdirectory(blocks) -add_subdirectory(freedesktop) -add_subdirectory(grc_gnuradio) add_subdirectory(gui) -add_subdirectory(python) +add_subdirectory(core) add_subdirectory(scripts) -add_subdirectory(examples) endif(ENABLE_GRC) diff --git a/grc/__main__.py b/grc/__main__.py new file mode 100644 index 0000000000..899d0195d1 --- /dev/null +++ b/grc/__main__.py @@ -0,0 +1,20 @@ +# Copyright 2016 Free Software Foundation, Inc. +# This file is part of GNU Radio +# +# GNU Radio Companion is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +from .main import main + +main() diff --git a/grc/base/Block.py b/grc/base/Block.py deleted file mode 100644 index 77c3145173..0000000000 --- a/grc/base/Block.py +++ /dev/null @@ -1,542 +0,0 @@ -""" -Copyright 2008-2011 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from . import odict -from . Constants import ADVANCED_PARAM_TAB, DEFAULT_PARAM_TAB -from . Constants import BLOCK_FLAG_THROTTLE, BLOCK_FLAG_DISABLE_BYPASS -from . Constants import BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED -from Element import Element - -from Cheetah.Template import Template -from UserDict import UserDict -from itertools import imap - - -class TemplateArg(UserDict): - """ - A cheetah template argument created from a param. - The str of this class evaluates to the param's to code method. - The use of this class as a dictionary (enum only) will reveal the enum opts. - The __call__ or () method can return the param evaluated to a raw python data type. - """ - - def __init__(self, param): - UserDict.__init__(self) - self._param = param - if param.is_enum(): - for key in param.get_opt_keys(): - self[key] = str(param.get_opt(key)) - - def __str__(self): - return str(self._param.to_code()) - - def __call__(self): - return self._param.get_evaluated() - - -def _get_keys(lst): - return [elem.get_key() for elem in lst] - - -def _get_elem(lst, key): - try: return lst[_get_keys(lst).index(key)] - except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst)) - - -class Block(Element): - - def __init__(self, flow_graph, n): - """ - Make a new block from nested data. - - Args: - flow: graph the parent element - n: the nested odict - - Returns: - block a new block - """ - #build the block - Element.__init__(self, flow_graph) - #grab the data - params = n.findall('param') - sources = n.findall('source') - sinks = n.findall('sink') - self._name = n.find('name') - self._key = n.find('key') - self._category = n.find('category') or '' - self._flags = n.find('flags') or '' - # Backwards compatibility - if n.find('throttle') and BLOCK_FLAG_THROTTLE not in self._flags: - self._flags += BLOCK_FLAG_THROTTLE - self._grc_source = n.find('grc_source') or '' - self._block_wrapper_path = n.find('block_wrapper_path') - self._bussify_sink = n.find('bus_sink') - self._bussify_source = n.find('bus_source') - self._var_value = n.find('var_value') or '$value' - - # get list of param tabs - n_tabs = n.find('param_tab_order') or None - self._param_tab_labels = n_tabs.findall('tab') if n_tabs is not None else [DEFAULT_PARAM_TAB] - - #create the param objects - self._params = list() - #add the id param - self.get_params().append(self.get_parent().get_parent().Param( - block=self, - n=odict({ - 'name': 'ID', - 'key': 'id', - 'type': 'id', - }) - )) - self.get_params().append(self.get_parent().get_parent().Param( - block=self, - n=odict({ - 'name': 'Enabled', - 'key': '_enabled', - 'type': 'raw', - 'value': 'True', - 'hide': 'all', - }) - )) - for param in imap(lambda n: self.get_parent().get_parent().Param(block=self, n=n), params): - key = param.get_key() - #test against repeated keys - if key in self.get_param_keys(): - raise Exception, 'Key "%s" already exists in params'%key - #store the param - self.get_params().append(param) - #create the source objects - self._sources = list() - for source in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='source'), sources): - key = source.get_key() - #test against repeated keys - if key in self.get_source_keys(): - raise Exception, 'Key "%s" already exists in sources'%key - #store the port - self.get_sources().append(source) - self.back_ofthe_bus(self.get_sources()) - #create the sink objects - self._sinks = list() - for sink in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='sink'), sinks): - key = sink.get_key() - #test against repeated keys - if key in self.get_sink_keys(): - raise Exception, 'Key "%s" already exists in sinks'%key - #store the port - self.get_sinks().append(sink) - self.back_ofthe_bus(self.get_sinks()) - self.current_bus_structure = {'source':'','sink':''}; - - # Virtual source/sink and pad source/sink blocks are - # indistinguishable from normal GR blocks. Make explicit - # checks for them here since they have no work function or - # buffers to manage. - is_virtual_or_pad = self._key in ( - "virtual_source", "virtual_sink", "pad_source", "pad_sink") - is_variable = self._key.startswith('variable') - - # Disable blocks that are virtual/pads or variables - if is_virtual_or_pad or is_variable: - self._flags += BLOCK_FLAG_DISABLE_BYPASS - - if not (is_virtual_or_pad or is_variable or self._key == 'options'): - self.get_params().append(self.get_parent().get_parent().Param( - block=self, - n=odict({'name': 'Block Alias', - 'key': 'alias', - 'type': 'string', - 'hide': 'part', - 'tab': ADVANCED_PARAM_TAB - }) - )) - - if (len(sources) or len(sinks)) and not is_virtual_or_pad: - self.get_params().append(self.get_parent().get_parent().Param( - block=self, - n=odict({'name': 'Core Affinity', - 'key': 'affinity', - 'type': 'int_vector', - 'hide': 'part', - 'tab': ADVANCED_PARAM_TAB - }) - )) - if len(sources) and not is_virtual_or_pad: - self.get_params().append(self.get_parent().get_parent().Param( - block=self, - n=odict({'name': 'Min Output Buffer', - 'key': 'minoutbuf', - 'type': 'int', - 'hide': 'part', - 'value': '0', - 'tab': ADVANCED_PARAM_TAB - }) - )) - self.get_params().append(self.get_parent().get_parent().Param( - block=self, - n=odict({'name': 'Max Output Buffer', - 'key': 'maxoutbuf', - 'type': 'int', - 'hide': 'part', - 'value': '0', - 'tab': ADVANCED_PARAM_TAB - }) - )) - - self.get_params().append(self.get_parent().get_parent().Param( - block=self, - n=odict({'name': 'Comment', - 'key': 'comment', - 'type': '_multiline', - 'hide': 'part', - 'value': '', - 'tab': ADVANCED_PARAM_TAB - }) - )) - - def back_ofthe_bus(self, portlist): - portlist.sort(key=lambda p: p._type == 'bus') - - def filter_bus_port(self, ports): - buslist = [p for p in ports if p._type == 'bus'] - return buslist or ports - - # Main functions to get and set the block state - # Also kept get_enabled and set_enabled to keep compatibility - def get_state(self): - """ - Gets the block's current state. - - Returns: - ENABLED - 0 - BYPASSED - 1 - DISABLED - 2 - """ - try: return int(eval(self.get_param('_enabled').get_value())) - except: return BLOCK_ENABLED - - def set_state(self, state): - """ - Sets the state for the block. - - Args: - ENABLED - 0 - BYPASSED - 1 - DISABLED - 2 - """ - if state in [BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED]: - self.get_param('_enabled').set_value(str(state)) - else: - self.get_param('_enabled').set_value(str(BLOCK_ENABLED)) - - # Enable/Disable Aliases - def get_enabled(self): - """ - Get the enabled state of the block. - - Returns: - true for enabled - """ - return not (self.get_state() == BLOCK_DISABLED) - - def set_enabled(self, enabled): - """ - Set the enabled state of the block. - - Args: - enabled: true for enabled - - Returns: - True if block changed state - """ - old_state = self.get_state() - new_state = BLOCK_ENABLED if enabled else BLOCK_DISABLED - self.set_state(new_state) - return old_state != new_state - - # Block bypassing - def get_bypassed(self): - """ - Check if the block is bypassed - """ - return self.get_state() == BLOCK_BYPASSED - - def set_bypassed(self): - """ - Bypass the block - - Returns: - True if block chagnes state - """ - if self.get_state() != BLOCK_BYPASSED and self.can_bypass(): - self.set_state(BLOCK_BYPASSED) - return True - return False - - def can_bypass(self): - """ Check the number of sinks and sources and see if this block can be bypassed """ - # Check to make sure this is a single path block - # Could possibly support 1 to many blocks - if len(self.get_sources()) != 1 or len(self.get_sinks()) != 1: - return False - if not (self.get_sources()[0].get_type() == self.get_sinks()[0].get_type()): - return False - if self.bypass_disabled(): - return False - return True - - def __str__(self): return 'Block - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key()) - - def get_id(self): return self.get_param('id').get_value() - def is_block(self): return True - def get_name(self): return self._name - def get_key(self): return self._key - def get_category(self): return self._category - def set_category(self, cat): self._category = cat - def get_doc(self): return '' - def get_ports(self): return self.get_sources() + self.get_sinks() - def get_ports_gui(self): return self.filter_bus_port(self.get_sources()) + self.filter_bus_port(self.get_sinks()); - def get_children(self): return self.get_ports() + self.get_params() - def get_children_gui(self): return self.get_ports_gui() + self.get_params() - def get_block_wrapper_path(self): return self._block_wrapper_path - def get_comment(self): return self.get_param('comment').get_value() - - def get_flags(self): return self._flags - def throtteling(self): return BLOCK_FLAG_THROTTLE in self._flags - def bypass_disabled(self): return BLOCK_FLAG_DISABLE_BYPASS in self._flags - - ############################################## - # Access Params - ############################################## - def get_param_tab_labels(self): return self._param_tab_labels - def get_param_keys(self): return _get_keys(self._params) - def get_param(self, key): return _get_elem(self._params, key) - def get_params(self): return self._params - def has_param(self, key): - try: - _get_elem(self._params, key); - return True; - except: - return False; - - ############################################## - # Access Sinks - ############################################## - def get_sink_keys(self): return _get_keys(self._sinks) - def get_sink(self, key): return _get_elem(self._sinks, key) - def get_sinks(self): return self._sinks - def get_sinks_gui(self): return self.filter_bus_port(self.get_sinks()) - - ############################################## - # Access Sources - ############################################## - def get_source_keys(self): return _get_keys(self._sources) - def get_source(self, key): return _get_elem(self._sources, key) - def get_sources(self): return self._sources - def get_sources_gui(self): return self.filter_bus_port(self.get_sources()); - - def get_connections(self): - return sum([port.get_connections() for port in self.get_ports()], []) - - def resolve_dependencies(self, tmpl): - """ - Resolve a paramater dependency with cheetah templates. - - Args: - tmpl: the string with dependencies - - Returns: - the resolved value - """ - tmpl = str(tmpl) - if '$' not in tmpl: return tmpl - n = dict((p.get_key(), TemplateArg(p)) for p in self.get_params()) - try: - return str(Template(tmpl, n)) - except Exception as err: - return "Template error: %s\n %s" % (tmpl, err) - - ############################################## - # Controller Modify - ############################################## - def type_controller_modify(self, direction): - """ - Change the type controller. - - Args: - direction: +1 or -1 - - Returns: - true for change - """ - changed = False - type_param = None - for param in filter(lambda p: p.is_enum(), self.get_params()): - children = self.get_ports() + self.get_params() - #priority to the type controller - if param.get_key() in ' '.join(map(lambda p: p._type, children)): type_param = param - #use param if type param is unset - if not type_param: type_param = param - if type_param: - #try to increment the enum by direction - try: - keys = type_param.get_option_keys() - old_index = keys.index(type_param.get_value()) - new_index = (old_index + direction + len(keys))%len(keys) - type_param.set_value(keys[new_index]) - changed = True - except: pass - return changed - - def port_controller_modify(self, direction): - """ - Change the port controller. - - Args: - direction: +1 or -1 - - Returns: - true for change - """ - return False - - def form_bus_structure(self, direc): - if direc == 'source': - get_p = self.get_sources; - get_p_gui = self.get_sources_gui; - bus_structure = self.get_bus_structure('source'); - else: - get_p = self.get_sinks; - get_p_gui = self.get_sinks_gui - bus_structure = self.get_bus_structure('sink'); - - struct = [range(len(get_p()))]; - if True in map(lambda a: isinstance(a.get_nports(), int), get_p()): - - - structlet = []; - last = 0; - for j in [i.get_nports() for i in get_p() if isinstance(i.get_nports(), int)]: - structlet.extend(map(lambda a: a+last, range(j))); - last = structlet[-1] + 1; - struct = [structlet]; - if bus_structure: - - struct = bus_structure - - self.current_bus_structure[direc] = struct; - return struct - - def bussify(self, n, direc): - if direc == 'source': - get_p = self.get_sources; - get_p_gui = self.get_sources_gui; - bus_structure = self.get_bus_structure('source'); - else: - get_p = self.get_sinks; - get_p_gui = self.get_sinks_gui - bus_structure = self.get_bus_structure('sink'); - - - for elt in get_p(): - for connect in elt.get_connections(): - self.get_parent().remove_element(connect); - - - - - - - if (not 'bus' in map(lambda a: a.get_type(), get_p())) and len(get_p()) > 0: - - struct = self.form_bus_structure(direc); - self.current_bus_structure[direc] = struct; - if get_p()[0].get_nports(): - n['nports'] = str(1); - - for i in range(len(struct)): - n['key'] = str(len(get_p())); - n = odict(n); - port = self.get_parent().get_parent().Port(block=self, n=n, dir=direc); - get_p().append(port); - - - - - elif 'bus' in map(lambda a: a.get_type(), get_p()): - for elt in get_p_gui(): - get_p().remove(elt); - self.current_bus_structure[direc] = '' - ############################################## - ## Import/Export Methods - ############################################## - def export_data(self): - """ - Export this block's params to nested data. - - Returns: - a nested data odict - """ - n = odict() - n['key'] = self.get_key() - n['param'] = map(lambda p: p.export_data(), sorted(self.get_params(), key=str)) - if 'bus' in map(lambda a: a.get_type(), self.get_sinks()): - n['bus_sink'] = str(1); - if 'bus' in map(lambda a: a.get_type(), self.get_sources()): - n['bus_source'] = str(1); - return n - - def import_data(self, n): - """ - Import this block's params from nested data. - Any param keys that do not exist will be ignored. - Since params can be dynamically created based another param, - call rewrite, and repeat the load until the params stick. - This call to rewrite will also create any dynamic ports - that are needed for the connections creation phase. - - Args: - n: the nested data odict - """ - get_hash = lambda: hash(tuple(map(hash, self.get_params()))) - my_hash = 0 - while get_hash() != my_hash: - params_n = n.findall('param') - for param_n in params_n: - key = param_n.find('key') - value = param_n.find('value') - #the key must exist in this block's params - if key in self.get_param_keys(): - self.get_param(key).set_value(value) - #store hash and call rewrite - my_hash = get_hash() - self.rewrite() - bussinks = n.findall('bus_sink'); - if len(bussinks) > 0 and not self._bussify_sink: - self.bussify({'name':'bus','type':'bus'}, 'sink') - elif len(bussinks) > 0: - self.bussify({'name':'bus','type':'bus'}, 'sink') - self.bussify({'name':'bus','type':'bus'}, 'sink') - bussrcs = n.findall('bus_source'); - if len(bussrcs) > 0 and not self._bussify_source: - self.bussify({'name':'bus','type':'bus'}, 'source') - elif len(bussrcs) > 0: - self.bussify({'name':'bus','type':'bus'}, 'source') - self.bussify({'name':'bus','type':'bus'}, 'source') diff --git a/grc/base/Constants.py b/grc/base/Constants.py deleted file mode 100644 index 1e83de63b5..0000000000 --- a/grc/base/Constants.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Copyright 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import os - -#data files -DATA_DIR = os.path.dirname(__file__) -FLOW_GRAPH_DTD = os.path.join(DATA_DIR, 'flow_graph.dtd') -BLOCK_TREE_DTD = os.path.join(DATA_DIR, 'block_tree.dtd') - -# file format versions: -# 0: undefined / legacy -# 1: non-numeric message port keys (label is used instead) -FLOW_GRAPH_FILE_FORMAT_VERSION = 1 - -# Param tabs -DEFAULT_PARAM_TAB = "General" -ADVANCED_PARAM_TAB = "Advanced" - -# Port domains -DOMAIN_DTD = os.path.join(DATA_DIR, 'domain.dtd') -GR_STREAM_DOMAIN = "gr_stream" -GR_MESSAGE_DOMAIN = "gr_message" -DEFAULT_DOMAIN = GR_STREAM_DOMAIN - -BLOCK_FLAG_THROTTLE = 'throttle' -BLOCK_FLAG_DISABLE_BYPASS = 'disable_bypass' -BLOCK_FLAG_NEED_QT_GUI = 'need_qt_gui' -BLOCK_FLAG_NEED_WX_GUI = 'need_ex_gui' - -# Block States -BLOCK_DISABLED = 0 -BLOCK_ENABLED = 1 -BLOCK_BYPASSED = 2 diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py deleted file mode 100644 index 0398dfd011..0000000000 --- a/grc/base/FlowGraph.py +++ /dev/null @@ -1,484 +0,0 @@ -""" -Copyright 2008-2011 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import time -from operator import methodcaller -from itertools import ifilter - -from .. gui import Messages - -from . import odict -from .Element import Element -from .Constants import FLOW_GRAPH_FILE_FORMAT_VERSION - - -class FlowGraph(Element): - - def __init__(self, platform): - """ - Make a flow graph from the arguments. - - Args: - platform: a platforms with blocks and contrcutors - - Returns: - the flow graph object - """ - #initialize - Element.__init__(self, platform) - self._elements = [] - self._timestamp = time.ctime() - #inital blank import - self.import_data() - - def _get_unique_id(self, base_id=''): - """ - Get a unique id starting with the base id. - - Args: - base_id: the id starts with this and appends a count - - Returns: - a unique id - """ - index = 0 - while True: - id = '%s_%d' % (base_id, index) - index += 1 - #make sure that the id is not used by another block - if not filter(lambda b: b.get_id() == id, self.get_blocks()): return id - - def __str__(self): - return 'FlowGraph - %s(%s)' % (self.get_option('title'), self.get_option('id')) - - def get_complexity(self): - """ - Determines the complexity of a flowgraph - """ - dbal = 0 - block_list = self.get_blocks() - for block in block_list: - # Skip options block - if block.get_key() == 'options': - continue - - # Don't worry about optional sinks? - sink_list = filter(lambda c: not c.get_optional(), block.get_sinks()) - source_list = filter(lambda c: not c.get_optional(), block.get_sources()) - sinks = float(len(sink_list)) - sources = float(len(source_list)) - base = max(min(sinks, sources), 1) - - # Port ratio multiplier - if min(sinks, sources) > 0: - multi = sinks / sources - multi = (1 / multi) if multi > 1 else multi - else: - multi = 1 - - # Connection ratio multiplier - sink_multi = max(float(sum(map(lambda c: len(c.get_connections()), sink_list)) / max(sinks, 1.0)), 1.0) - source_multi = max(float(sum(map(lambda c: len(c.get_connections()), source_list)) / max(sources, 1.0)), 1.0) - dbal = dbal + (base * multi * sink_multi * source_multi) - - elements = float(len(self.get_elements())) - connections = float(len(self.get_connections())) - disabled_connections = len(filter(lambda c: not c.get_enabled(), self.get_connections())) - blocks = float(len(block_list)) - variables = elements - blocks - connections - enabled = float(len(self.get_enabled_blocks())) - - # Disabled multiplier - if enabled > 0: - disabled_multi = 1 / (max(1 - ((blocks - enabled) / max(blocks, 1)), 0.05)) - else: - disabled_multi = 1 - - # Connection multiplier (How many connections ) - if (connections - disabled_connections) > 0: - conn_multi = 1 / (max(1 - (disabled_connections / max(connections, 1)), 0.05)) - else: - conn_multi = 1 - - final = round(max((dbal - 1) * disabled_multi * conn_multi * connections, 0.0) / 1000000, 6) - return final - - def rewrite(self): - def refactor_bus_structure(): - - for block in self.get_blocks(): - for direc in ['source', 'sink']: - if direc == 'source': - get_p = block.get_sources; - get_p_gui = block.get_sources_gui; - bus_structure = block.form_bus_structure('source'); - else: - get_p = block.get_sinks; - get_p_gui = block.get_sinks_gui - bus_structure = block.form_bus_structure('sink'); - - if 'bus' in map(lambda a: a.get_type(), get_p_gui()): - if len(get_p_gui()) > len(bus_structure): - times = range(len(bus_structure), len(get_p_gui())); - for i in times: - for connect in get_p_gui()[-1].get_connections(): - block.get_parent().remove_element(connect); - get_p().remove(get_p_gui()[-1]); - elif len(get_p_gui()) < len(bus_structure): - n = {'name':'bus','type':'bus'}; - if True in map(lambda a: isinstance(a.get_nports(), int), get_p()): - n['nports'] = str(1); - - times = range(len(get_p_gui()), len(bus_structure)); - - for i in times: - n['key'] = str(len(get_p())); - n = odict(n); - port = block.get_parent().get_parent().Port(block=block, n=n, dir=direc); - get_p().append(port); - - for child in self.get_children(): child.rewrite() - refactor_bus_structure() - - def get_option(self, key): - """ - Get the option for a given key. - The option comes from the special options block. - - Args: - key: the param key for the options block - - Returns: - the value held by that param - """ - return self._options_block.get_param(key).get_evaluated() - - def is_flow_graph(self): return True - - ############################################## - ## Access Elements - ############################################## - def get_block(self, id): - for block in self.iter_blocks(): - if block.get_id() == id: - return block - raise KeyError('No block with ID {0!r}'.format(id)) - - def iter_blocks(self): - return ifilter(methodcaller('is_block'), self.get_elements()) - - def get_blocks(self): - return list(self.iter_blocks()) - - def iter_connections(self): - return ifilter(methodcaller('is_connection'), self.get_elements()) - - def get_connections(self): - return list(self.iter_connections()) - - def get_elements(self): - """ - Get a list of all the elements. - Always ensure that the options block is in the list (only once). - - Returns: - the element list - """ - options_block_count = self._elements.count(self._options_block) - if not options_block_count: - self._elements.append(self._options_block) - for i in range(options_block_count-1): - self._elements.remove(self._options_block) - return self._elements - - get_children = get_elements - - def iter_enabled_blocks(self): - """ - Get an iterator of all blocks that are enabled and not bypassed. - """ - return ifilter(methodcaller('get_enabled'), self.iter_blocks()) - - def get_enabled_blocks(self): - """ - Get a list of all blocks that are enabled and not bypassed. - - Returns: - a list of blocks - """ - return list(self.iter_enabled_blocks()) - - def get_bypassed_blocks(self): - """ - Get a list of all blocks that are bypassed. - - Returns: - a list of blocks - """ - return filter(methodcaller('get_bypassed'), self.iter_blocks()) - - def get_enabled_connections(self): - """ - Get a list of all connections that are enabled. - - Returns: - a list of connections - """ - return filter(methodcaller('get_enabled'), self.get_connections()) - - def get_new_block(self, key): - """ - Get a new block of the specified key. - Add the block to the list of elements. - - Args: - key: the block key - - Returns: - the new block or None if not found - """ - if key not in self.get_parent().get_block_keys(): return None - block = self.get_parent().get_new_block(self, key) - self.get_elements().append(block); - if block._bussify_sink: - block.bussify({'name':'bus','type':'bus'}, 'sink') - if block._bussify_source: - block.bussify({'name':'bus','type':'bus'}, 'source') - return block; - - def connect(self, porta, portb): - """ - Create a connection between porta and portb. - - Args: - porta: a port - portb: another port - @throw Exception bad connection - - Returns: - the new connection - """ - connection = self.get_parent().Connection(flow_graph=self, porta=porta, portb=portb) - self.get_elements().append(connection) - return connection - - def remove_element(self, element): - """ - Remove the element from the list of elements. - If the element is a port, remove the whole block. - If the element is a block, remove its connections. - If the element is a connection, just remove the connection. - """ - if element not in self.get_elements(): return - #found a port, set to parent signal block - if element.is_port(): - element = element.get_parent() - #remove block, remove all involved connections - if element.is_block(): - for port in element.get_ports(): - map(self.remove_element, port.get_connections()) - if element.is_connection(): - if element.is_bus(): - cons_list = [] - for i in map(lambda a: a.get_connections(), element.get_source().get_associated_ports()): - cons_list.extend(i); - map(self.remove_element, cons_list); - self.get_elements().remove(element) - - def evaluate(self, expr): - """ - Evaluate the expression. - - Args: - expr: the string expression - @throw NotImplementedError - """ - raise NotImplementedError - - ############################################## - ## Import/Export Methods - ############################################## - def export_data(self): - """ - Export this flow graph to nested data. - Export all block and connection data. - - Returns: - a nested data odict - """ - # sort blocks and connections for nicer diffs - blocks = sorted(self.iter_blocks(), key=lambda b: ( - b.get_key() != 'options', # options to the front - not b.get_key().startswith('variable'), # then vars - str(b) - )) - connections = sorted(self.get_connections(), key=str) - n = odict() - n['timestamp'] = self._timestamp - n['block'] = [b.export_data() for b in blocks] - n['connection'] = [c.export_data() for c in connections] - instructions = odict({ - 'created': self.get_parent().get_version_short(), - 'format': FLOW_GRAPH_FILE_FORMAT_VERSION, - }) - return odict({'flow_graph': n, '_instructions': instructions}) - - def import_data(self, n=None): - """ - Import blocks and connections into this flow graph. - Clear this flowgraph of all previous blocks and connections. - Any blocks or connections in error will be ignored. - - Args: - n: the nested data odict - """ - errors = False - self._elements = list() # remove previous elements - # set file format - try: - instructions = n.find('_instructions') or {} - file_format = int(instructions.get('format', '0')) or _guess_file_format_1(n) - except: - file_format = 0 - - fg_n = n and n.find('flow_graph') or odict() # use blank data if none provided - self._timestamp = fg_n.find('timestamp') or time.ctime() - - # build the blocks - self._options_block = self.get_parent().get_new_block(self, 'options') - for block_n in fg_n.findall('block'): - key = block_n.find('key') - block = self._options_block if key == 'options' else self.get_new_block(key) - - if not block: # looks like this block key cannot be found - # create a dummy block instead - block = self.get_new_block('dummy_block') - # Ugly ugly ugly - _initialize_dummy_block(block, block_n) - Messages.send_error_msg_load('Block key "%s" not found' % key) - - block.import_data(block_n) - - self.rewrite() # evaluate stuff like nports before adding connections - - # build the connections - def verify_and_get_port(key, block, dir): - ports = block.get_sinks() if dir == 'sink' else block.get_sources() - for port in ports: - if key == port.get_key(): - break - if not key.isdigit() and port.get_type() == '' and key == port.get_name(): - break - else: - if block.is_dummy_block(): - port = _dummy_block_add_port(block, key, dir) - else: - raise LookupError('%s key %r not in %s block keys' % (dir, key, dir)) - return port - - for connection_n in fg_n.findall('connection'): - # get the block ids and port keys - source_block_id = connection_n.find('source_block_id') - sink_block_id = connection_n.find('sink_block_id') - source_key = connection_n.find('source_key') - sink_key = connection_n.find('sink_key') - try: - source_block = self.get_block(source_block_id) - sink_block = self.get_block(sink_block_id) - - # fix old, numeric message ports keys - if file_format < 1: - source_key, sink_key = _update_old_message_port_keys( - source_key, sink_key, source_block, sink_block) - - # build the connection - source_port = verify_and_get_port(source_key, source_block, 'source') - sink_port = verify_and_get_port(sink_key, sink_block, 'sink') - self.connect(source_port, sink_port) - except LookupError as e: - Messages.send_error_load( - 'Connection between %s(%s) and %s(%s) could not be made.\n\t%s' % ( - source_block_id, source_key, sink_block_id, sink_key, e)) - errors = True - - self.rewrite() # global rewrite - return errors - - -def _update_old_message_port_keys(source_key, sink_key, source_block, sink_block): - """Backward compatibility for message port keys - - Message ports use their names as key (like in the 'connect' method). - Flowgraph files from former versions still have numeric keys stored for - message connections. These have to be replaced by the name of the - respective port. The correct message port is deduced from the integer - value of the key (assuming the order has not changed). - - The connection ends are updated only if both ends translate into a - message port. - """ - try: - # get ports using the "old way" (assuming liner indexed keys) - source_port = source_block.get_sources()[int(source_key)] - sink_port = sink_block.get_sinks()[int(sink_key)] - if source_port.get_type() == "message" and sink_port.get_type() == "message": - source_key, sink_key = source_port.get_key(), sink_port.get_key() - except (ValueError, IndexError): - pass - return source_key, sink_key # do nothing - - -def _guess_file_format_1(n): - """Try to guess the file format for flow-graph files without version tag""" - try: - has_non_numeric_message_keys = any(not ( - connection_n.find('source_key').isdigit() and - connection_n.find('sink_key').isdigit() - ) for connection_n in n.find('flow_graph').findall('connection')) - if has_non_numeric_message_keys: - return 1 - except: - pass - return 0 - - -def _initialize_dummy_block(block, block_n): - """This is so ugly... dummy-fy a block - - Modify block object to get the behaviour for a missing block - """ - block._key = block_n.find('key') - block.is_dummy_block = lambda: True - block.is_valid = lambda: False - block.get_enabled = lambda: False - for param_n in block_n.findall('param'): - if param_n['key'] not in block.get_param_keys(): - new_param_n = odict({'key': param_n['key'], 'name': param_n['key'], 'type': 'string'}) - block.get_params().append(block.get_parent().get_parent().Param(block=block, n=new_param_n)) - - -def _dummy_block_add_port(block, key, dir): - """This is so ugly... Add a port to a dummy-field block""" - port_n = odict({'name': '?', 'key': key, 'type': ''}) - port = block.get_parent().get_parent().Port(block=block, n=port_n, dir=dir) - if port.is_source(): - block.get_sources().append(port) - else: - block.get_sinks().append(port) - return port diff --git a/grc/base/Param.py b/grc/base/Param.py deleted file mode 100644 index 34dd36e790..0000000000 --- a/grc/base/Param.py +++ /dev/null @@ -1,205 +0,0 @@ -""" -Copyright 2008-2011 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from . import odict -from Element import Element - -def _get_keys(lst): return [elem.get_key() for elem in lst] -def _get_elem(lst, key): - try: return lst[_get_keys(lst).index(key)] - except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst)) - -class Option(Element): - - def __init__(self, param, n): - Element.__init__(self, param) - self._name = n.find('name') - self._key = n.find('key') - self._opts = dict() - opts = n.findall('opt') - #test against opts when non enum - if not self.get_parent().is_enum() and opts: - raise Exception, 'Options for non-enum types cannot have sub-options' - #extract opts - for opt in opts: - #separate the key:value - try: key, value = opt.split(':') - except: raise Exception, 'Error separating "%s" into key:value'%opt - #test against repeated keys - if self._opts.has_key(key): - raise Exception, 'Key "%s" already exists in option'%key - #store the option - self._opts[key] = value - - def __str__(self): return 'Option %s(%s)'%(self.get_name(), self.get_key()) - def get_name(self): return self._name - def get_key(self): return self._key - - ############################################## - # Access Opts - ############################################## - def get_opt_keys(self): return self._opts.keys() - def get_opt(self, key): return self._opts[key] - def get_opts(self): return self._opts.values() - -class Param(Element): - - def __init__(self, block, n): - """ - Make a new param from nested data. - - Args: - block: the parent element - n: the nested odict - """ - # if the base key is a valid param key, copy its data and overlay this params data - base_key = n.find('base_key') - if base_key and base_key in block.get_param_keys(): - n_expanded = block.get_param(base_key)._n.copy() - n_expanded.update(n) - n = n_expanded - # save odict in case this param will be base for another - self._n = n - # parse the data - self._name = n.find('name') - self._key = n.find('key') - value = n.find('value') or '' - self._type = n.find('type') or 'raw' - self._hide = n.find('hide') or '' - self._tab_label = n.find('tab') or block.get_param_tab_labels()[0] - if not self._tab_label in block.get_param_tab_labels(): - block.get_param_tab_labels().append(self._tab_label) - #build the param - Element.__init__(self, block) - #create the Option objects from the n data - self._options = list() - for option in map(lambda o: Option(param=self, n=o), n.findall('option')): - key = option.get_key() - #test against repeated keys - if key in self.get_option_keys(): - raise Exception, 'Key "%s" already exists in options'%key - #store the option - self.get_options().append(option) - #test the enum options - if self.is_enum(): - #test against options with identical keys - if len(set(self.get_option_keys())) != len(self.get_options()): - raise Exception, 'Options keys "%s" are not unique.'%self.get_option_keys() - #test against inconsistent keys in options - opt_keys = self.get_options()[0].get_opt_keys() - for option in self.get_options(): - if set(opt_keys) != set(option.get_opt_keys()): - raise Exception, 'Opt keys "%s" are not identical across all options.'%opt_keys - #if a value is specified, it must be in the options keys - self._value = value if value or value in self.get_option_keys() else self.get_option_keys()[0] - if self.get_value() not in self.get_option_keys(): - raise Exception, 'The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys()) - else: self._value = value or '' - self._default = value - - def validate(self): - """ - Validate the param. - The value must be evaluated and type must a possible type. - """ - Element.validate(self) - if self.get_type() not in self.get_types(): - self.add_error_message('Type "%s" is not a possible type.'%self.get_type()) - - def get_evaluated(self): raise NotImplementedError - - def to_code(self): - """ - Convert the value to code. - @throw NotImplementedError - """ - raise NotImplementedError - - def get_types(self): - """ - Get a list of all possible param types. - @throw NotImplementedError - """ - raise NotImplementedError - - def get_color(self): return '#FFFFFF' - def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key()) - def is_param(self): return True - def get_name(self): return self.get_parent().resolve_dependencies(self._name).strip() - def get_key(self): return self._key - def get_hide(self): return self.get_parent().resolve_dependencies(self._hide).strip() - - def get_value(self): - value = self._value - if self.is_enum() and value not in self.get_option_keys(): - value = self.get_option_keys()[0] - self.set_value(value) - return value - - def set_value(self, value): self._value = str(value) #must be a string - - def set_default(self, value): - if self._default == self._value: - self.set_value(value) - self._default = str(value) - - def get_type(self): return self.get_parent().resolve_dependencies(self._type) - def get_tab_label(self): return self._tab_label - def is_enum(self): return self._type == 'enum' - - def __repr__(self): - """ - Get the repr (nice string format) for this param. - Just return the value (special case enum). - Derived classes can handle complex formatting. - - Returns: - the string representation - """ - if self.is_enum(): return self.get_option(self.get_value()).get_name() - return self.get_value() - - ############################################## - # Access Options - ############################################## - def get_option_keys(self): return _get_keys(self.get_options()) - def get_option(self, key): return _get_elem(self.get_options(), key) - def get_options(self): return self._options - - ############################################## - # Access Opts - ############################################## - def get_opt_keys(self): return self.get_option(self.get_value()).get_opt_keys() - def get_opt(self, key): return self.get_option(self.get_value()).get_opt(key) - def get_opts(self): return self.get_option(self.get_value()).get_opts() - - ############################################## - ## Import/Export Methods - ############################################## - def export_data(self): - """ - Export this param's key/value. - - Returns: - a nested data odict - """ - n = odict() - n['key'] = self.get_key() - n['value'] = self.get_value() - return n diff --git a/grc/base/Platform.py b/grc/base/Platform.py deleted file mode 100644 index 0cc3fcf1dd..0000000000 --- a/grc/base/Platform.py +++ /dev/null @@ -1,271 +0,0 @@ -""" -Copyright 2008-2011 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import os -import sys -from .. base import ParseXML, odict -from Element import Element as _Element -from FlowGraph import FlowGraph as _FlowGraph -from Connection import Connection as _Connection -from Block import Block as _Block -from Port import Port as _Port -from Param import Param as _Param -from Constants import BLOCK_TREE_DTD, FLOW_GRAPH_DTD, DOMAIN_DTD - - -class Platform(_Element): - def __init__(self, name, version, key, - block_paths, block_dtd, default_flow_graph, generator, - license='', website=None, colors=None): - """ - Make a platform from the arguments. - - Args: - name: the platform name - version: the version string - key: the unique platform key - block_paths: the file paths to blocks in this platform - block_dtd: the dtd validator for xml block wrappers - default_flow_graph: the default flow graph file path - generator: the generator class for this platform - colors: a list of title, color_spec tuples - license: a multi-line license (first line is copyright) - website: the website url for this platform - - Returns: - a platform object - """ - _Element.__init__(self) - self._name = name - # Save the verion string to the first - self._version = version[0] - self._version_major = version[1] - self._version_api = version[2] - self._version_minor = version[3] - self._version_short = version[1] + "." + version[2] + "." + version[3] - - self._key = key - self._license = license - self._website = website - self._block_paths = list(set(block_paths)) - self._block_dtd = block_dtd - self._default_flow_graph = default_flow_graph - self._generator = generator - self._colors = colors or [] - #create a dummy flow graph for the blocks - self._flow_graph = _Element(self) - - self._blocks = None - self._blocks_n = None - self._category_trees_n = None - self._domains = dict() - self._connection_templates = dict() - self.load_blocks() - - def load_blocks(self): - """load the blocks and block tree from the search paths""" - # reset - self._blocks = odict() - self._blocks_n = odict() - self._category_trees_n = list() - self._domains.clear() - self._connection_templates.clear() - ParseXML.xml_failures.clear() - # try to parse and load blocks - for xml_file in self.iter_xml_files(): - try: - if xml_file.endswith("block_tree.xml"): - self.load_category_tree_xml(xml_file) - elif xml_file.endswith('domain.xml'): - self.load_domain_xml(xml_file) - else: - self.load_block_xml(xml_file) - except ParseXML.XMLSyntaxError as e: - # print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s' % (e, xml_file) - pass - except Exception as e: - print >> sys.stderr, 'Warning: XML parsing failed:\n\t%s\n\tIgnoring: %s' % (e, xml_file) - - def iter_xml_files(self): - """Iterator for block descriptions and category trees""" - get_path = lambda x: os.path.abspath(os.path.expanduser(x)) - for block_path in map(get_path, self._block_paths): - if os.path.isfile(block_path): - yield block_path - elif os.path.isdir(block_path): - for dirpath, dirnames, filenames in os.walk(block_path): - for filename in sorted(filter(lambda f: f.endswith('.xml'), filenames)): - yield os.path.join(dirpath, filename) - - def load_block_xml(self, xml_file): - """Load block description from xml file""" - # validate and import - ParseXML.validate_dtd(xml_file, self._block_dtd) - n = ParseXML.from_file(xml_file).find('block') - n['block_wrapper_path'] = xml_file # inject block wrapper path - # get block instance and add it to the list of blocks - block = self.Block(self._flow_graph, n) - key = block.get_key() - if key in self._blocks: - print >> sys.stderr, 'Warning: Block with key "%s" already exists.\n\tIgnoring: %s' % (key, xml_file) - else: # store the block - self._blocks[key] = block - self._blocks_n[key] = n - return block - - def load_category_tree_xml(self, xml_file): - """Validate and parse category tree file and add it to list""" - ParseXML.validate_dtd(xml_file, BLOCK_TREE_DTD) - n = ParseXML.from_file(xml_file).find('cat') - self._category_trees_n.append(n) - - def load_domain_xml(self, xml_file): - """Load a domain properties and connection templates from XML""" - ParseXML.validate_dtd(xml_file, DOMAIN_DTD) - n = ParseXML.from_file(xml_file).find('domain') - - key = n.find('key') - if not key: - print >> sys.stderr, 'Warning: Domain with emtpy key.\n\tIgnoring: %s' % xml_file - return - if key in self.get_domains(): # test against repeated keys - print >> sys.stderr, 'Warning: Domain with key "%s" already exists.\n\tIgnoring: %s' % (key, xml_file) - return - - to_bool = lambda s, d: d if s is None else \ - s.lower() not in ('false', 'off', '0', '') - - color = n.find('color') or '' - try: - import gtk # ugly but handy - gtk.gdk.color_parse(color) - except (ValueError, ImportError): - if color: # no color is okay, default set in GUI - print >> sys.stderr, 'Warning: Can\'t parse color code "%s" for domain "%s" ' % (color, key) - color = None - - self._domains[key] = dict( - name=n.find('name') or key, - multiple_sinks=to_bool(n.find('multiple_sinks'), True), - multiple_sources=to_bool(n.find('multiple_sources'), False), - color=color - ) - for connection_n in n.findall('connection'): - key = (connection_n.find('source_domain'), connection_n.find('sink_domain')) - if not all(key): - print >> sys.stderr, 'Warning: Empty domain key(s) in connection template.\n\t%s' % xml_file - elif key in self._connection_templates: - print >> sys.stderr, 'Warning: Connection template "%s" already exists.\n\t%s' % (key, xml_file) - else: - self._connection_templates[key] = connection_n.find('make') or '' - - def parse_flow_graph(self, flow_graph_file): - """ - Parse a saved flow graph file. - Ensure that the file exists, and passes the dtd check. - - Args: - flow_graph_file: the flow graph file - - Returns: - nested data - @throws exception if the validation fails - """ - flow_graph_file = flow_graph_file or self._default_flow_graph - open(flow_graph_file, 'r') # test open - ParseXML.validate_dtd(flow_graph_file, FLOW_GRAPH_DTD) - return ParseXML.from_file(flow_graph_file) - - def load_block_tree(self, block_tree): - """ - Load a block tree with categories and blocks. - Step 1: Load all blocks from the xml specification. - Step 2: Load blocks with builtin category specifications. - - Args: - block_tree: the block tree object - """ - #recursive function to load categories and blocks - def load_category(cat_n, parent=None): - #add this category - parent = (parent or []) + [cat_n.find('name')] - block_tree.add_block(parent) - #recursive call to load sub categories - map(lambda c: load_category(c, parent), cat_n.findall('cat')) - #add blocks in this category - for block_key in cat_n.findall('block'): - if block_key not in self.get_block_keys(): - print >> sys.stderr, 'Warning: Block key "%s" not found when loading category tree.' % (block_key) - continue - block = self.get_block(block_key) - #if it exists, the block's category shall not be overridden by the xml tree - if not block.get_category(): - block.set_category(parent) - - # recursively load the category trees and update the categories for each block - for category_tree_n in self._category_trees_n: - load_category(category_tree_n) - - #add blocks to block tree - for block in self.get_blocks(): - #blocks with empty categories are hidden - if not block.get_category(): continue - block_tree.add_block(block.get_category(), block) - - def __str__(self): return 'Platform - %s(%s)'%(self.get_key(), self.get_name()) - - def is_platform(self): return True - - def get_new_flow_graph(self): return self.FlowGraph(platform=self) - - def get_generator(self): return self._generator - - ############################################## - # Access Blocks - ############################################## - def get_block_keys(self): return self._blocks.keys() - def get_block(self, key): return self._blocks[key] - def get_blocks(self): return self._blocks.values() - def get_new_block(self, flow_graph, key): return self.Block(flow_graph, n=self._blocks_n[key]) - - def get_domains(self): return self._domains - def get_domain(self, key): return self._domains.get(key) - def get_connection_templates(self): return self._connection_templates - - def get_name(self): return self._name - def get_version(self): return self._version - def get_version_major(self): return self._version_major - def get_version_api(self): return self._version_api - def get_version_minor(self): return self._version_minor - def get_version_short(self): return self._version_short - - def get_key(self): return self._key - def get_license(self): return self._license - def get_website(self): return self._website - def get_colors(self): return self._colors - def get_block_paths(self): return self._block_paths - - ############################################## - # Constructors - ############################################## - FlowGraph = _FlowGraph - Connection = _Connection - Block = _Block - Port = _Port - Param = _Param diff --git a/grc/base/Port.py b/grc/base/Port.py deleted file mode 100644 index d1c35163f5..0000000000 --- a/grc/base/Port.py +++ /dev/null @@ -1,136 +0,0 @@ -""" -Copyright 2008-2011 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from Element import Element -from . Constants import GR_STREAM_DOMAIN, GR_MESSAGE_DOMAIN - -class Port(Element): - - def __init__(self, block, n, dir): - """ - Make a new port from nested data. - - Args: - block: the parent element - n: the nested odict - dir: the direction source or sink - """ - #build the port - Element.__init__(self, block) - #grab the data - self._name = n['name'] - self._key = n['key'] - self._type = n['type'] or '' - self._domain = n['domain'] - self._hide = n.find('hide') or '' - self._dir = dir - self._hide_evaluated = False # updated on rewrite() - - def validate(self): - """ - Validate the port. - The port must be non-empty and type must a possible type. - """ - Element.validate(self) - if self.get_type() not in self.get_types(): - self.add_error_message('Type "%s" is not a possible type.' % self.get_type()) - platform = self.get_parent().get_parent().get_parent() - if self.get_domain() not in platform.get_domains(): - self.add_error_message('Domain key "%s" is not registered.' % self.get_domain()) - - def rewrite(self): - """resolve dependencies in for type and hide""" - Element.rewrite(self) - hide = self.get_parent().resolve_dependencies(self._hide).strip().lower() - self._hide_evaluated = False if hide in ('false', 'off', '0') else bool(hide) - # update domain if was deduced from (dynamic) port type - type_ = self.get_type() - if self._domain == GR_STREAM_DOMAIN and type_ == "message": - self._domain = GR_MESSAGE_DOMAIN - self._key = self._name - if self._domain == GR_MESSAGE_DOMAIN and type_ != "message": - self._domain = GR_STREAM_DOMAIN - self._key = '0' # is rectified in rewrite() - - def __str__(self): - if self.is_source(): - return 'Source - %s(%s)'%(self.get_name(), self.get_key()) - if self.is_sink(): - return 'Sink - %s(%s)'%(self.get_name(), self.get_key()) - - def get_types(self): - """ - Get a list of all possible port types. - @throw NotImplementedError - """ - raise NotImplementedError - - def is_port(self): return True - def get_color(self): return '#FFFFFF' - def get_name(self): - number = '' - if self.get_type() == 'bus': - busses = filter(lambda a: a._dir == self._dir, self.get_parent().get_ports_gui()) - number = str(busses.index(self)) + '#' + str(len(self.get_associated_ports())) - return self._name + number - - def get_key(self): return self._key - def is_sink(self): return self._dir == 'sink' - def is_source(self): return self._dir == 'source' - def get_type(self): return self.get_parent().resolve_dependencies(self._type) - def get_domain(self): return self._domain - def get_hide(self): return self._hide_evaluated - - def get_connections(self): - """ - Get all connections that use this port. - - Returns: - a list of connection objects - """ - connections = self.get_parent().get_parent().get_connections() - connections = filter(lambda c: c.get_source() is self or c.get_sink() is self, connections) - return connections - - def get_enabled_connections(self): - """ - Get all enabled connections that use this port. - - Returns: - a list of connection objects - """ - return filter(lambda c: c.get_enabled(), self.get_connections()) - - def get_associated_ports(self): - if not self.get_type() == 'bus': - return [self] - else: - if self.is_source(): - get_ports = self.get_parent().get_sources - bus_structure = self.get_parent().current_bus_structure['source'] - else: - get_ports = self.get_parent().get_sinks - bus_structure = self.get_parent().current_bus_structure['sink'] - - ports = [i for i in get_ports() if not i.get_type() == 'bus'] - if bus_structure: - busses = [i for i in get_ports() if i.get_type() == 'bus'] - bus_index = busses.index(self) - ports = filter(lambda a: ports.index(a) in bus_structure[bus_index], ports) - return ports diff --git a/grc/base/__init__.py b/grc/base/__init__.py deleted file mode 100644 index 2682db8125..0000000000 --- a/grc/base/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -Copyright 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from odict import odict diff --git a/grc/blocks/block_tree.xml b/grc/blocks/block_tree.xml index d07c52e9c5..a8775d6872 100644 --- a/grc/blocks/block_tree.xml +++ b/grc/blocks/block_tree.xml @@ -20,23 +20,6 @@ <block>note</block> <block>import</block> - - <block>blks2_selector</block> - <block>blks2_valve</block> - <block>blks2_error_rate</block> - - <block>xmlrpc_server</block> - <block>xmlrpc_client</block> - </cat> - <cat> - <name>Networking Tools</name> - <block>blks2_tcp_source</block> - <block>blks2_tcp_sink</block> - </cat> - <cat> - <name>Packet Operators</name> - <block>blks2_packet_decoder</block> - <block>blks2_packet_encoder</block> </cat> <cat> <name>Variables</name> diff --git a/grc/checks.py b/grc/checks.py new file mode 100755 index 0000000000..fd0e5de06a --- /dev/null +++ b/grc/checks.py @@ -0,0 +1,80 @@ +# Copyright 2009-2016 Free Software Foundation, Inc. +# This file is part of GNU Radio +# +# GNU Radio Companion is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +import os +import warnings + + +GR_IMPORT_ERROR_MESSAGE = """\ +Cannot import gnuradio. + +Is the model path environment variable set correctly? + All OS: PYTHONPATH + +Is the library path environment variable set correctly? + Linux: LD_LIBRARY_PATH + Windows: PATH + MacOSX: DYLD_LIBRARY_PATH +""" + + +def die(error, message): + msg = "{0}\n\n({1})".format(message, error) + try: + import gtk + d = gtk.MessageDialog( + type=gtk.MESSAGE_ERROR, + buttons=gtk.BUTTONS_CLOSE, + message_format=msg, + ) + d.set_title(type(error).__name__) + d.run() + exit(1) + except ImportError: + exit(type(error).__name__ + '\n\n' + msg) + + +def check_gtk(): + try: + warnings.filterwarnings("error") + import pygtk + pygtk.require('2.0') + import gtk + gtk.init_check() + warnings.filterwarnings("always") + except Exception as err: + die(err, "Failed to initialize GTK. If you are running over ssh, " + "did you enable X forwarding and start ssh with -X?") + + +def check_gnuradio_import(): + try: + from gnuradio import gr + except ImportError as err: + die(err, GR_IMPORT_ERROR_MESSAGE) + + +def check_blocks_path(): + if 'GR_DONT_LOAD_PREFS' in os.environ and not os.environ.get('GRC_BLOCKS_PATH', ''): + die(EnvironmentError("No block definitions available"), + "Can't find block definitions. Use config.conf or GRC_BLOCKS_PATH.") + + +def do_all(): + check_gnuradio_import() + check_gtk() + check_blocks_path() diff --git a/grc/core/Block.py b/grc/core/Block.py new file mode 100644 index 0000000000..cb4eb0db61 --- /dev/null +++ b/grc/core/Block.py @@ -0,0 +1,846 @@ +""" +Copyright 2008-2015 Free Software Foundation, Inc. +This file is part of GNU Radio + +GNU Radio Companion is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +GNU Radio Companion is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +""" + +import collections +import itertools + +from Cheetah.Template import Template + +from .utils import epy_block_io, odict +from . Constants import ( + BLOCK_FLAG_NEED_QT_GUI, BLOCK_FLAG_NEED_WX_GUI, + ADVANCED_PARAM_TAB, DEFAULT_PARAM_TAB, + BLOCK_FLAG_THROTTLE, BLOCK_FLAG_DISABLE_BYPASS, + BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED +) +from . Element import Element +from . FlowGraph import _variable_matcher + + +def _get_keys(lst): + return [elem.get_key() for elem in lst] + + +def _get_elem(lst, key): + try: + return lst[_get_keys(lst).index(key)] + except ValueError: + raise ValueError('Key "{}" not found in {}.'.format(key, _get_keys(lst))) + + +class Block(Element): + + is_block = True + + def __init__(self, flow_graph, n): + """ + Make a new block from nested data. + + Args: + flow: graph the parent element + n: the nested odict + + Returns: + block a new block + """ + # Grab the data + self._doc = (n.find('doc') or '').strip('\n').replace('\\\n', '') + self._imports = map(lambda i: i.strip(), n.findall('import')) + self._make = n.find('make') + self._var_make = n.find('var_make') + self._checks = n.findall('check') + self._callbacks = n.findall('callback') + self._bus_structure_source = n.find('bus_structure_source') or '' + self._bus_structure_sink = n.find('bus_structure_sink') or '' + self.port_counters = [itertools.count(), itertools.count()] + + # Build the block + Element.__init__(self, flow_graph) + + # Grab the data + params = n.findall('param') + sources = n.findall('source') + sinks = n.findall('sink') + self._name = n.find('name') + self._key = n.find('key') + self._category = n.find('category') or '' + self._flags = n.find('flags') or '' + # Backwards compatibility + if n.find('throttle') and BLOCK_FLAG_THROTTLE not in self._flags: + self._flags += BLOCK_FLAG_THROTTLE + self._grc_source = n.find('grc_source') or '' + self._block_wrapper_path = n.find('block_wrapper_path') + self._bussify_sink = n.find('bus_sink') + self._bussify_source = n.find('bus_source') + self._var_value = n.find('var_value') or '$value' + + # Get list of param tabs + n_tabs = n.find('param_tab_order') or None + self._param_tab_labels = n_tabs.findall('tab') if n_tabs is not None else [DEFAULT_PARAM_TAB] + + # Create the param objects + self._params = list() + + # Add the id param + self.get_params().append(self.get_parent().get_parent().Param( + block=self, + n=odict({ + 'name': 'ID', + 'key': 'id', + 'type': 'id', + }) + )) + self.get_params().append(self.get_parent().get_parent().Param( + block=self, + n=odict({ + 'name': 'Enabled', + 'key': '_enabled', + 'type': 'raw', + 'value': 'True', + 'hide': 'all', + }) + )) + for param in itertools.imap(lambda n: self.get_parent().get_parent().Param(block=self, n=n), params): + key = param.get_key() + # Test against repeated keys + if key in self.get_param_keys(): + raise Exception('Key "{}" already exists in params'.format(key)) + # Store the param + self.get_params().append(param) + # Create the source objects + self._sources = list() + for source in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='source'), sources): + key = source.get_key() + # Test against repeated keys + if key in self.get_source_keys(): + raise Exception('Key "{}" already exists in sources'.format(key)) + # Store the port + self.get_sources().append(source) + self.back_ofthe_bus(self.get_sources()) + # Create the sink objects + self._sinks = list() + for sink in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='sink'), sinks): + key = sink.get_key() + # Test against repeated keys + if key in self.get_sink_keys(): + raise Exception('Key "{}" already exists in sinks'.format(key)) + # Store the port + self.get_sinks().append(sink) + self.back_ofthe_bus(self.get_sinks()) + self.current_bus_structure = {'source': '', 'sink': ''} + + # Virtual source/sink and pad source/sink blocks are + # indistinguishable from normal GR blocks. Make explicit + # checks for them here since they have no work function or + # buffers to manage. + is_virtual_or_pad = self._key in ( + "virtual_source", "virtual_sink", "pad_source", "pad_sink") + is_variable = self._key.startswith('variable') + + # Disable blocks that are virtual/pads or variables + if is_virtual_or_pad or is_variable: + self._flags += BLOCK_FLAG_DISABLE_BYPASS + + if not (is_virtual_or_pad or is_variable or self._key == 'options'): + self.get_params().append(self.get_parent().get_parent().Param( + block=self, + n=odict({'name': 'Block Alias', + 'key': 'alias', + 'type': 'string', + 'hide': 'part', + 'tab': ADVANCED_PARAM_TAB + }) + )) + + if (len(sources) or len(sinks)) and not is_virtual_or_pad: + self.get_params().append(self.get_parent().get_parent().Param( + block=self, + n=odict({'name': 'Core Affinity', + 'key': 'affinity', + 'type': 'int_vector', + 'hide': 'part', + 'tab': ADVANCED_PARAM_TAB + }) + )) + if len(sources) and not is_virtual_or_pad: + self.get_params().append(self.get_parent().get_parent().Param( + block=self, + n=odict({'name': 'Min Output Buffer', + 'key': 'minoutbuf', + 'type': 'int', + 'hide': 'part', + 'value': '0', + 'tab': ADVANCED_PARAM_TAB + }) + )) + self.get_params().append(self.get_parent().get_parent().Param( + block=self, + n=odict({'name': 'Max Output Buffer', + 'key': 'maxoutbuf', + 'type': 'int', + 'hide': 'part', + 'value': '0', + 'tab': ADVANCED_PARAM_TAB + }) + )) + + self.get_params().append(self.get_parent().get_parent().Param( + block=self, + n=odict({'name': 'Comment', + 'key': 'comment', + 'type': '_multiline', + 'hide': 'part', + 'value': '', + 'tab': ADVANCED_PARAM_TAB + }) + )) + + self._epy_source_hash = -1 # for epy blocks + self._epy_reload_error = None + + if self._bussify_sink: + self.bussify({'name': 'bus', 'type': 'bus'}, 'sink') + if self._bussify_source: + self.bussify({'name': 'bus', 'type': 'bus'}, 'source') + + def get_bus_structure(self, direction): + if direction == 'source': + bus_structure = self._bus_structure_source + else: + bus_structure = self._bus_structure_sink + + bus_structure = self.resolve_dependencies(bus_structure) + + if not bus_structure: + return '' # TODO: Don't like empty strings. should change this to None eventually + + try: + clean_bus_structure = self.get_parent().evaluate(bus_structure) + return clean_bus_structure + except: + return '' + + def validate(self): + """ + Validate this block. + Call the base class validate. + Evaluate the checks: each check must evaluate to True. + """ + Element.validate(self) + # Evaluate the checks + for check in self._checks: + check_res = self.resolve_dependencies(check) + try: + if not self.get_parent().evaluate(check_res): + self.add_error_message('Check "{}" failed.'.format(check)) + except: + self.add_error_message('Check "{}" did not evaluate.'.format(check)) + + # For variables check the value (only if var_value is used + if _variable_matcher.match(self.get_key()) and self._var_value != '$value': + value = self._var_value + try: + value = self.get_var_value() + self.get_parent().evaluate(value) + except Exception as err: + self.add_error_message('Value "{}" cannot be evaluated:\n{}'.format(value, err)) + + # check if this is a GUI block and matches the selected generate option + current_generate_option = self.get_parent().get_option('generate_options') + + def check_generate_mode(label, flag, valid_options): + block_requires_mode = ( + flag in self.get_flags() or + self.get_name().upper().startswith(label) + ) + if block_requires_mode and current_generate_option not in valid_options: + self.add_error_message("Can't generate this block in mode: {} ".format( + repr(current_generate_option))) + + check_generate_mode('WX GUI', BLOCK_FLAG_NEED_WX_GUI, ('wx_gui',)) + check_generate_mode('QT GUI', BLOCK_FLAG_NEED_QT_GUI, ('qt_gui', 'hb_qt_gui')) + if self._epy_reload_error: + self.get_param('_source_code').add_error_message(str(self._epy_reload_error)) + + def rewrite(self): + """ + Add and remove ports to adjust for the nports. + """ + Element.rewrite(self) + # Check and run any custom rewrite function for this block + getattr(self, 'rewrite_' + self._key, lambda: None)() + + # Adjust nports, disconnect hidden ports + for ports in (self.get_sources(), self.get_sinks()): + for i, master_port in enumerate(ports): + nports = master_port.get_nports() or 1 + num_ports = 1 + len(master_port.get_clones()) + if master_port.get_hide(): + for connection in master_port.get_connections(): + self.get_parent().remove_element(connection) + if not nports and num_ports == 1: # Not a master port and no left-over clones + continue + # Remove excess cloned ports + for port in master_port.get_clones()[nports-1:]: + # Remove excess connections + for connection in port.get_connections(): + self.get_parent().remove_element(connection) + master_port.remove_clone(port) + ports.remove(port) + # Add more cloned ports + for j in range(num_ports, nports): + port = master_port.add_clone() + ports.insert(ports.index(master_port) + j, port) + + self.back_ofthe_bus(ports) + # Renumber non-message/message ports + domain_specific_port_index = collections.defaultdict(int) + for port in filter(lambda p: p.get_key().isdigit(), ports): + domain = port.get_domain() + port._key = str(domain_specific_port_index[domain]) + domain_specific_port_index[domain] += 1 + + def port_controller_modify(self, direction): + """ + Change the port controller. + + Args: + direction: +1 or -1 + + Returns: + true for change + """ + changed = False + # Concat the nports string from the private nports settings of all ports + nports_str = ' '.join([port._nports for port in self.get_ports()]) + # Modify all params whose keys appear in the nports string + for param in self.get_params(): + if param.is_enum() or param.get_key() not in nports_str: + continue + # Try to increment the port controller by direction + try: + value = param.get_evaluated() + value = value + direction + if 0 < value: + param.set_value(value) + changed = True + except: + pass + return changed + + def get_doc(self): + platform = self.get_parent().get_parent() + documentation = platform.block_docstrings.get(self._key, {}) + from_xml = self._doc.strip() + if from_xml: + documentation[''] = from_xml + return documentation + + def get_imports(self, raw=False): + """ + Resolve all import statements. + Split each import statement at newlines. + Combine all import statments into a list. + Filter empty imports. + + Returns: + a list of import statements + """ + if raw: + return self._imports + return filter(lambda i: i, sum(map(lambda i: self.resolve_dependencies(i).split('\n'), self._imports), [])) + + def get_make(self, raw=False): + if raw: + return self._make + return self.resolve_dependencies(self._make) + + def get_var_make(self): + return self.resolve_dependencies(self._var_make) + + def get_var_value(self): + return self.resolve_dependencies(self._var_value) + + def get_callbacks(self): + """ + Get a list of function callbacks for this block. + + Returns: + a list of strings + """ + def make_callback(callback): + callback = self.resolve_dependencies(callback) + if 'self.' in callback: + return callback + return 'self.{}.{}'.format(self.get_id(), callback) + return map(make_callback, self._callbacks) + + def is_virtual_sink(self): + return self.get_key() == 'virtual_sink' + + def is_virtual_source(self): + return self.get_key() == 'virtual_source' + + ########################################################################### + # Custom rewrite functions + ########################################################################### + + def rewrite_epy_block(self): + flowgraph = self.get_parent() + platform = flowgraph.get_parent() + param_blk = self.get_param('_io_cache') + param_src = self.get_param('_source_code') + + src = param_src.get_value() + src_hash = hash((self.get_id(), src)) + if src_hash == self._epy_source_hash: + return + + try: + blk_io = epy_block_io.extract(src) + + except Exception as e: + self._epy_reload_error = ValueError(str(e)) + try: # Load last working block io + blk_io = epy_block_io.BlockIO(*eval(param_blk.get_value())) + except: + return + else: + self._epy_reload_error = None # Clear previous errors + param_blk.set_value(repr(tuple(blk_io))) + + # print "Rewriting embedded python block {!r}".format(self.get_id()) + + self._epy_source_hash = src_hash + self._name = blk_io.name or blk_io.cls + self._doc = blk_io.doc + self._imports[0] = 'import ' + self.get_id() + self._make = '{0}.{1}({2})'.format(self.get_id(), blk_io.cls, ', '.join( + '{0}=${0}'.format(key) for key, _ in blk_io.params)) + + params = {} + for param in list(self._params): + if hasattr(param, '__epy_param__'): + params[param.get_key()] = param + self._params.remove(param) + + for key, value in blk_io.params: + try: + param = params[key] + param.set_default(value) + except KeyError: # need to make a new param + name = key.replace('_', ' ').title() + n = odict(dict(name=name, key=key, type='raw', value=value)) + param = platform.Param(block=self, n=n) + setattr(param, '__epy_param__', True) + self._params.append(param) + + def update_ports(label, ports, port_specs, direction): + ports_to_remove = list(ports) + iter_ports = iter(ports) + ports_new = [] + port_current = next(iter_ports, None) + for key, port_type in port_specs: + reuse_port = ( + port_current is not None and + port_current.get_type() == port_type and + (key.isdigit() or port_current.get_key() == key) + ) + if reuse_port: + ports_to_remove.remove(port_current) + port, port_current = port_current, next(iter_ports, None) + else: + n = odict(dict(name=label + str(key), type=port_type, key=key)) + if port_type == 'message': + n['name'] = key + n['optional'] = '1' + port = platform.Port(block=self, n=n, dir=direction) + ports_new.append(port) + # replace old port list with new one + del ports[:] + ports.extend(ports_new) + # remove excess port connections + for port in ports_to_remove: + for connection in port.get_connections(): + flowgraph.remove_element(connection) + + update_ports('in', self.get_sinks(), blk_io.sinks, 'sink') + update_ports('out', self.get_sources(), blk_io.sources, 'source') + self.rewrite() + + def back_ofthe_bus(self, portlist): + portlist.sort(key=lambda p: p._type == 'bus') + + def filter_bus_port(self, ports): + buslist = [p for p in ports if p._type == 'bus'] + return buslist or ports + + # Main functions to get and set the block state + # Also kept get_enabled and set_enabled to keep compatibility + def get_state(self): + """ + Gets the block's current state. + + Returns: + ENABLED - 0 + BYPASSED - 1 + DISABLED - 2 + """ + try: + return int(eval(self.get_param('_enabled').get_value())) + except: + return BLOCK_ENABLED + + def set_state(self, state): + """ + Sets the state for the block. + + Args: + ENABLED - 0 + BYPASSED - 1 + DISABLED - 2 + """ + if state in [BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED]: + self.get_param('_enabled').set_value(str(state)) + else: + self.get_param('_enabled').set_value(str(BLOCK_ENABLED)) + + # Enable/Disable Aliases + def get_enabled(self): + """ + Get the enabled state of the block. + + Returns: + true for enabled + """ + return not (self.get_state() == BLOCK_DISABLED) + + def set_enabled(self, enabled): + """ + Set the enabled state of the block. + + Args: + enabled: true for enabled + + Returns: + True if block changed state + """ + old_state = self.get_state() + new_state = BLOCK_ENABLED if enabled else BLOCK_DISABLED + self.set_state(new_state) + return old_state != new_state + + # Block bypassing + def get_bypassed(self): + """ + Check if the block is bypassed + """ + return self.get_state() == BLOCK_BYPASSED + + def set_bypassed(self): + """ + Bypass the block + + Returns: + True if block chagnes state + """ + if self.get_state() != BLOCK_BYPASSED and self.can_bypass(): + self.set_state(BLOCK_BYPASSED) + return True + return False + + def can_bypass(self): + """ Check the number of sinks and sources and see if this block can be bypassed """ + # Check to make sure this is a single path block + # Could possibly support 1 to many blocks + if len(self.get_sources()) != 1 or len(self.get_sinks()) != 1: + return False + if not (self.get_sources()[0].get_type() == self.get_sinks()[0].get_type()): + return False + if self.bypass_disabled(): + return False + return True + + def __str__(self): + return 'Block - {} - {}({})'.format(self.get_id(), self.get_name(), self.get_key()) + + def get_id(self): + return self.get_param('id').get_value() + + def get_name(self): + return self._name + + def get_key(self): + return self._key + + def get_category(self): + return self._category + + def set_category(self, cat): + self._category = cat + + def get_ports(self): + return self.get_sources() + self.get_sinks() + + def get_ports_gui(self): + return self.filter_bus_port(self.get_sources()) + self.filter_bus_port(self.get_sinks()) + + def get_children(self): + return self.get_ports() + self.get_params() + + def get_children_gui(self): + return self.get_ports_gui() + self.get_params() + + def get_block_wrapper_path(self): + return self._block_wrapper_path + + def get_comment(self): + return self.get_param('comment').get_value() + + def get_flags(self): + return self._flags + + def throtteling(self): + return BLOCK_FLAG_THROTTLE in self._flags + + def bypass_disabled(self): + return BLOCK_FLAG_DISABLE_BYPASS in self._flags + + ############################################## + # Access Params + ############################################## + def get_param_tab_labels(self): + return self._param_tab_labels + + def get_param_keys(self): + return _get_keys(self._params) + + def get_param(self, key): + return _get_elem(self._params, key) + + def get_params(self): + return self._params + + def has_param(self, key): + try: + _get_elem(self._params, key) + return True + except: + return False + + ############################################## + # Access Sinks + ############################################## + def get_sink_keys(self): + return _get_keys(self._sinks) + + def get_sink(self, key): + return _get_elem(self._sinks, key) + + def get_sinks(self): + return self._sinks + + def get_sinks_gui(self): + return self.filter_bus_port(self.get_sinks()) + + ############################################## + # Access Sources + ############################################## + def get_source_keys(self): + return _get_keys(self._sources) + + def get_source(self, key): + return _get_elem(self._sources, key) + + def get_sources(self): + return self._sources + + def get_sources_gui(self): + return self.filter_bus_port(self.get_sources()) + + def get_connections(self): + return sum([port.get_connections() for port in self.get_ports()], []) + + def resolve_dependencies(self, tmpl): + """ + Resolve a paramater dependency with cheetah templates. + + Args: + tmpl: the string with dependencies + + Returns: + the resolved value + """ + tmpl = str(tmpl) + if '$' not in tmpl: + return tmpl + n = dict((param.get_key(), param.template_arg) + for param in self.get_params()) # TODO: cache that + try: + return str(Template(tmpl, n)) + except Exception as err: + return "Template error: {}\n {}".format(tmpl, err) + + ############################################## + # Controller Modify + ############################################## + def type_controller_modify(self, direction): + """ + Change the type controller. + + Args: + direction: +1 or -1 + + Returns: + true for change + """ + changed = False + type_param = None + for param in filter(lambda p: p.is_enum(), self.get_params()): + children = self.get_ports() + self.get_params() + # Priority to the type controller + if param.get_key() in ' '.join(map(lambda p: p._type, children)): type_param = param + # Use param if type param is unset + if not type_param: + type_param = param + if type_param: + # Try to increment the enum by direction + try: + keys = type_param.get_option_keys() + old_index = keys.index(type_param.get_value()) + new_index = (old_index + direction + len(keys)) % len(keys) + type_param.set_value(keys[new_index]) + changed = True + except: + pass + return changed + + def form_bus_structure(self, direc): + if direc == 'source': + get_p = self.get_sources + get_p_gui = self.get_sources_gui + bus_structure = self.get_bus_structure('source') + else: + get_p = self.get_sinks + get_p_gui = self.get_sinks_gui + bus_structure = self.get_bus_structure('sink') + + struct = [range(len(get_p()))] + if True in map(lambda a: isinstance(a.get_nports(), int), get_p()): + structlet = [] + last = 0 + for j in [i.get_nports() for i in get_p() if isinstance(i.get_nports(), int)]: + structlet.extend(map(lambda a: a+last, range(j))) + last = structlet[-1] + 1 + struct = [structlet] + if bus_structure: + + struct = bus_structure + + self.current_bus_structure[direc] = struct + return struct + + def bussify(self, n, direc): + if direc == 'source': + get_p = self.get_sources + get_p_gui = self.get_sources_gui + bus_structure = self.get_bus_structure('source') + else: + get_p = self.get_sinks + get_p_gui = self.get_sinks_gui + bus_structure = self.get_bus_structure('sink') + + for elt in get_p(): + for connect in elt.get_connections(): + self.get_parent().remove_element(connect) + + if ('bus' not in map(lambda a: a.get_type(), get_p())) and len(get_p()) > 0: + struct = self.form_bus_structure(direc) + self.current_bus_structure[direc] = struct + if get_p()[0].get_nports(): + n['nports'] = str(1) + + for i in range(len(struct)): + n['key'] = str(len(get_p())) + n = odict(n) + port = self.get_parent().get_parent().Port(block=self, n=n, dir=direc) + get_p().append(port) + elif 'bus' in map(lambda a: a.get_type(), get_p()): + for elt in get_p_gui(): + get_p().remove(elt) + self.current_bus_structure[direc] = '' + + ############################################## + # Import/Export Methods + ############################################## + def export_data(self): + """ + Export this block's params to nested data. + + Returns: + a nested data odict + """ + n = odict() + n['key'] = self.get_key() + n['param'] = map(lambda p: p.export_data(), sorted(self.get_params(), key=str)) + if 'bus' in map(lambda a: a.get_type(), self.get_sinks()): + n['bus_sink'] = str(1) + if 'bus' in map(lambda a: a.get_type(), self.get_sources()): + n['bus_source'] = str(1) + return n + + def get_hash(self): + return hash(tuple(map(hash, self.get_params()))) + + def import_data(self, n): + """ + Import this block's params from nested data. + Any param keys that do not exist will be ignored. + Since params can be dynamically created based another param, + call rewrite, and repeat the load until the params stick. + This call to rewrite will also create any dynamic ports + that are needed for the connections creation phase. + + Args: + n: the nested data odict + """ + my_hash = 0 + while self.get_hash() != my_hash: + params_n = n.findall('param') + for param_n in params_n: + key = param_n.find('key') + value = param_n.find('value') + # The key must exist in this block's params + if key in self.get_param_keys(): + self.get_param(key).set_value(value) + # Store hash and call rewrite + my_hash = self.get_hash() + self.rewrite() + bussinks = n.findall('bus_sink') + if len(bussinks) > 0 and not self._bussify_sink: + self.bussify({'name': 'bus', 'type': 'bus'}, 'sink') + elif len(bussinks) > 0: + self.bussify({'name': 'bus', 'type': 'bus'}, 'sink') + self.bussify({'name': 'bus', 'type': 'bus'}, 'sink') + bussrcs = n.findall('bus_source') + if len(bussrcs) > 0 and not self._bussify_source: + self.bussify({'name': 'bus', 'type': 'bus'}, 'source') + elif len(bussrcs) > 0: + self.bussify({'name': 'bus', 'type': 'bus'}, 'source') + self.bussify({'name': 'bus', 'type': 'bus'}, 'source') diff --git a/grc/examples/CMakeLists.txt b/grc/core/CMakeLists.txt index a218dbe500..51b0dacba6 100644 --- a/grc/examples/CMakeLists.txt +++ b/grc/core/CMakeLists.txt @@ -17,21 +17,21 @@ # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. -# SIMPLE -install( - FILES - simple/variable_config.grc - DESTINATION ${GR_PKG_DATA_DIR}/examples/grc/simple +file(GLOB py_files "*.py") + +GR_PYTHON_INSTALL( + FILES ${py_files} + DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core COMPONENT "grc" ) -# XMLRPC +file(GLOB dtd_files "*.dtd") + install( - FILES - xmlrpc/readme.txt - xmlrpc/xmlrpc_client.grc - xmlrpc/xmlrpc_client_script.py - xmlrpc/xmlrpc_server.grc - DESTINATION ${GR_PKG_DATA_DIR}/examples/grc/xmlrpc + FILES ${dtd_files} default_flow_graph.grc + DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core COMPONENT "grc" ) + +add_subdirectory(generator) +add_subdirectory(utils) diff --git a/grc/core/Config.py b/grc/core/Config.py new file mode 100644 index 0000000000..ac38d9978c --- /dev/null +++ b/grc/core/Config.py @@ -0,0 +1,55 @@ +""" +Copyright 2016 Free Software Foundation, Inc. +This file is part of GNU Radio + +GNU Radio Companion is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +GNU Radio Companion is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +""" + +import os +from os.path import expanduser, normpath, expandvars, exists + + +class Config(object): + + key = 'grc' + name = 'GNU Radio Companion (no gui)' + license = __doc__.strip() + website = 'http://gnuradio.org' + + hier_block_lib_dir = os.environ.get('GRC_HIER_PATH', expanduser('~/.grc_gnuradio')) + + def __init__(self, prefs_file, version, version_parts=None): + self.prefs = prefs_file + self.version = version + self.version_parts = version_parts or version[1:].split('-', 1)[0].split('.')[:3] + + @property + def block_paths(self): + path_list_sep = {'/': ':', '\\': ';'}[os.path.sep] + + paths_sources = ( + self.hier_block_lib_dir, + os.environ.get('GRC_BLOCKS_PATH', ''), + self.prefs.get_string('grc', 'local_blocks_path', ''), + self.prefs.get_string('grc', 'global_blocks_path', ''), + ) + + collected_paths = sum((paths.split(path_list_sep) + for paths in paths_sources), []) + + valid_paths = [normpath(expanduser(expandvars(path))) + for path in collected_paths if exists(path)] + + return valid_paths diff --git a/grc/base/Connection.py b/grc/core/Connection.py index bf3c75277c..3aa32ef183 100644 --- a/grc/base/Connection.py +++ b/grc/core/Connection.py @@ -1,5 +1,5 @@ """ -Copyright 2008-2011 Free Software Foundation, Inc. +Copyright 2008-2015 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -17,11 +17,15 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from Element import Element -from . import odict +from . import Constants +from .Element import Element +from .utils import odict + class Connection(Element): + is_connection = True + def __init__(self, flow_graph, porta, portb): """ Make a new connection given the parent and 2 ports. @@ -37,72 +41,88 @@ class Connection(Element): """ Element.__init__(self, flow_graph) source = sink = None - #separate the source and sink + # Separate the source and sink for port in (porta, portb): - if port.is_source(): source = port - if port.is_sink(): sink = port - if not source: raise ValueError('Connection could not isolate source') - if not sink: raise ValueError('Connection could not isolate sink') - busses = len(filter(lambda a: a.get_type() == 'bus', [source, sink]))%2 - if not busses == 0: raise ValueError('busses must get with busses') + if port.is_source: + source = port + else: + sink = port + if not source: + raise ValueError('Connection could not isolate source') + if not sink: + raise ValueError('Connection could not isolate sink') + busses = len(filter(lambda a: a.get_type() == 'bus', [source, sink])) % 2 + if not busses == 0: + raise ValueError('busses must get with busses') if not len(source.get_associated_ports()) == len(sink.get_associated_ports()): - raise ValueError('port connections must have same cardinality'); - #ensure that this connection (source -> sink) is unique - for connection in self.get_parent().get_connections(): + raise ValueError('port connections must have same cardinality') + # Ensure that this connection (source -> sink) is unique + for connection in flow_graph.connections: if connection.get_source() is source and connection.get_sink() is sink: raise LookupError('This connection between source and sink is not unique.') self._source = source self._sink = sink if source.get_type() == 'bus': - sources = source.get_associated_ports(); - sinks = sink.get_associated_ports(); + sources = source.get_associated_ports() + sinks = sink.get_associated_ports() for i in range(len(sources)): try: - flow_graph.connect(sources[i], sinks[i]); + flow_graph.connect(sources[i], sinks[i]) except: pass def __str__(self): - return 'Connection (\n\t%s\n\t\t%s\n\t%s\n\t\t%s\n)'%( + return 'Connection (\n\t{}\n\t\t{}\n\t{}\n\t\t{}\n)'.format( self.get_source().get_parent(), self.get_source(), self.get_sink().get_parent(), self.get_sink(), ) - def is_connection(self): return True + def is_msg(self): + return self.get_source().get_type() == self.get_sink().get_type() == 'msg' + + def is_bus(self): + return self.get_source().get_type() == self.get_sink().get_type() == 'bus' def validate(self): """ Validate the connections. + The ports must match in io size. + """ + """ + Validate the connections. The ports must match in type. """ Element.validate(self) platform = self.get_parent().get_parent() source_domain = self.get_source().get_domain() sink_domain = self.get_sink().get_domain() - if (source_domain, sink_domain) not in platform.get_connection_templates(): - self.add_error_message('No connection known for domains "%s", "%s"' - % (source_domain, sink_domain)) + if (source_domain, sink_domain) not in platform.connection_templates: + self.add_error_message('No connection known for domains "{}", "{}"'.format( + source_domain, sink_domain)) too_many_other_sinks = ( - source_domain in platform.get_domains() and - not platform.get_domain(key=source_domain)['multiple_sinks'] and + not platform.domains.get(source_domain, []).get('multiple_sinks', False) and len(self.get_source().get_enabled_connections()) > 1 ) too_many_other_sources = ( - sink_domain in platform.get_domains() and - not platform.get_domain(key=sink_domain)['multiple_sources'] and + not platform.domains.get(sink_domain, []).get('multiple_sources', False) and len(self.get_sink().get_enabled_connections()) > 1 ) if too_many_other_sinks: self.add_error_message( - 'Domain "%s" can have only one downstream block' % source_domain) + 'Domain "{}" can have only one downstream block'.format(source_domain)) if too_many_other_sources: self.add_error_message( - 'Domain "%s" can have only one upstream block' % sink_domain) + 'Domain "{}" can have only one upstream block'.format(sink_domain)) + + source_size = Constants.TYPE_TO_SIZEOF[self.get_source().get_type()] * self.get_source().get_vlen() + sink_size = Constants.TYPE_TO_SIZEOF[self.get_sink().get_type()] * self.get_sink().get_vlen() + if source_size != sink_size: + self.add_error_message('Source IO size "{}" does not match sink IO size "{}".'.format(source_size, sink_size)) def get_enabled(self): """ @@ -117,11 +137,14 @@ class Connection(Element): ############################# # Access Ports ############################# - def get_sink(self): return self._sink - def get_source(self): return self._source + def get_sink(self): + return self._sink + + def get_source(self): + return self._source ############################################## - ## Import/Export Methods + # Import/Export Methods ############################################## def export_data(self): """ diff --git a/grc/python/Constants.py b/grc/core/Constants.py index b7a370cad7..9fe805f854 100644 --- a/grc/python/Constants.py +++ b/grc/core/Constants.py @@ -1,5 +1,5 @@ """ -Copyright 2008-2011 Free Software Foundation, Inc. +Copyright 2008-2015 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -18,49 +18,53 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ import os -from os.path import expanduser import numpy import stat -from gnuradio import gr -_gr_prefs = gr.prefs() - -# setup paths -PATH_SEP = {'/': ':', '\\': ';'}[os.path.sep] - -HIER_BLOCKS_LIB_DIR = os.environ.get('GRC_HIER_PATH', expanduser('~/.grc_gnuradio')) - -PREFS_FILE = os.environ.get('GRC_PREFS_PATH', expanduser('~/.gnuradio/grc.conf')) -PREFS_FILE_OLD = os.environ.get('GRC_PREFS_PATH', expanduser('~/.grc')) - -BLOCKS_DIRS = filter( # filter blank strings - lambda x: x, PATH_SEP.join([ - os.environ.get('GRC_BLOCKS_PATH', ''), - _gr_prefs.get_string('grc', 'local_blocks_path', ''), - _gr_prefs.get_string('grc', 'global_blocks_path', ''), - ]).split(PATH_SEP), -) + [HIER_BLOCKS_LIB_DIR] - -# user settings -XTERM_EXECUTABLE = _gr_prefs.get_string('grc', 'xterm_executable', 'xterm') - -# file creation modes -TOP_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH -HIER_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH - -# data files +# Data files DATA_DIR = os.path.dirname(__file__) -FLOW_GRAPH_TEMPLATE = os.path.join(DATA_DIR, 'flow_graph.tmpl') +FLOW_GRAPH_DTD = os.path.join(DATA_DIR, 'flow_graph.dtd') +BLOCK_TREE_DTD = os.path.join(DATA_DIR, 'block_tree.dtd') BLOCK_DTD = os.path.join(DATA_DIR, 'block.dtd') DEFAULT_FLOW_GRAPH = os.path.join(DATA_DIR, 'default_flow_graph.grc') +DOMAIN_DTD = os.path.join(DATA_DIR, 'domain.dtd') + +# File format versions: +# 0: undefined / legacy +# 1: non-numeric message port keys (label is used instead) +FLOW_GRAPH_FILE_FORMAT_VERSION = 1 + +# Param tabs +DEFAULT_PARAM_TAB = "General" +ADVANCED_PARAM_TAB = "Advanced" + +# Port domains +GR_STREAM_DOMAIN = "gr_stream" +GR_MESSAGE_DOMAIN = "gr_message" +DEFAULT_DOMAIN = GR_STREAM_DOMAIN + +BLOCK_FLAG_THROTTLE = 'throttle' +BLOCK_FLAG_DISABLE_BYPASS = 'disable_bypass' +BLOCK_FLAG_NEED_QT_GUI = 'need_qt_gui' +BLOCK_FLAG_NEED_WX_GUI = 'need_wx_gui' + +# Block States +BLOCK_DISABLED = 0 +BLOCK_ENABLED = 1 +BLOCK_BYPASSED = 2 + +# File creation modes +TOP_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | \ + stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH +HIER_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH -#define types, native python + numpy +# Define types, native python + numpy VECTOR_TYPES = (tuple, list, set, numpy.ndarray) COMPLEX_TYPES = [complex, numpy.complex, numpy.complex64, numpy.complex128] REAL_TYPES = [float, numpy.float, numpy.float32, numpy.float64] INT_TYPES = [int, long, numpy.int, numpy.int8, numpy.int16, numpy.int32, numpy.uint64, - numpy.uint, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64] -#cast to tuple for isinstance, concat subtypes + numpy.uint, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64] +# Cast to tuple for isinstance, concat subtypes COMPLEX_TYPES = tuple(COMPLEX_TYPES + REAL_TYPES + INT_TYPES) REAL_TYPES = tuple(REAL_TYPES + INT_TYPES) INT_TYPES = tuple(INT_TYPES) @@ -87,7 +91,6 @@ GRC_COLOR_DARK_GREY = '#72706F' GRC_COLOR_GREY = '#BDBDBD' GRC_COLOR_WHITE = '#FFFFFF' - CORE_TYPES = ( # name, key, sizeof, color ('Complex Float 64', 'fc64', 16, GRC_COLOR_BROWN), ('Complex Float 32', 'fc32', 8, GRC_COLOR_BLUE), @@ -108,23 +111,25 @@ CORE_TYPES = ( # name, key, sizeof, color ) ALIAS_TYPES = { - 'complex' : (8, GRC_COLOR_BLUE), - 'float' : (4, GRC_COLOR_ORANGE), - 'int' : (4, GRC_COLOR_TEAL), - 'short' : (2, GRC_COLOR_YELLOW), - 'byte' : (1, GRC_COLOR_LIGHT_PURPLE), + 'complex': (8, GRC_COLOR_BLUE), + 'float': (4, GRC_COLOR_ORANGE), + 'int': (4, GRC_COLOR_TEAL), + 'short': (2, GRC_COLOR_YELLOW), + 'byte': (1, GRC_COLOR_LIGHT_PURPLE), } TYPE_TO_COLOR = dict() TYPE_TO_SIZEOF = dict() + for name, key, sizeof, color in CORE_TYPES: TYPE_TO_COLOR[key] = color TYPE_TO_SIZEOF[key] = sizeof + for key, (sizeof, color) in ALIAS_TYPES.iteritems(): TYPE_TO_COLOR[key] = color TYPE_TO_SIZEOF[key] = sizeof -#coloring +# Coloring COMPLEX_COLOR_SPEC = '#3399FF' FLOAT_COLOR_SPEC = '#FF8C69' INT_COLOR_SPEC = '#00FF99' diff --git a/grc/base/Element.py b/grc/core/Element.py index b0f94d0183..b96edb0a72 100644 --- a/grc/base/Element.py +++ b/grc/core/Element.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008, 2009, 2015 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ + class Element(object): def __init__(self, parent=None): @@ -32,7 +33,8 @@ class Element(object): Call this base method before adding error messages in the subclass. """ del self._error_messages[:] - for child in self.get_children(): child.validate() + for child in self.get_children(): + child.validate() def is_valid(self): """ @@ -61,10 +63,10 @@ class Element(object): Returns: a list of error message strings """ - error_messages = list(self._error_messages) #make a copy + error_messages = list(self._error_messages) # Make a copy for child in filter(lambda c: c.get_enabled() and not c.get_bypassed(), self.get_children()): for msg in child.get_error_messages(): - error_messages.append("%s:\n\t%s"%(child, msg.replace("\n", "\n\t"))) + error_messages.append("{}:\n\t{}".format(child, msg.replace("\n", "\n\t"))) return error_messages def rewrite(self): @@ -72,27 +74,36 @@ class Element(object): Rewrite this element and call rewrite on all children. Call this base method before rewriting the element. """ - for child in self.get_children(): child.rewrite() + for child in self.get_children(): + child.rewrite() + + def get_enabled(self): + return True - def get_enabled(self): return True - def get_bypassed(self): return False + def get_bypassed(self): + return False ############################################## - ## Tree-like API + # Tree-like API ############################################## - def get_parent(self): return self._parent - def get_children(self): return list() + def get_parent(self): + return self._parent + + def get_children(self): + return list() ############################################## - ## Type testing methods + # Type testing ############################################## - def is_element(self): return True - def is_platform(self): return False - def is_flow_graph(self): return False - def is_connection(self): return False - def is_block(self): return False - def is_dummy_block(self): return False - def is_source(self): return False - def is_sink(self): return False - def is_port(self): return False - def is_param(self): return False + is_platform = False + + is_flow_graph = False + + is_block = False + is_dummy_block = False + + is_connection = False + + is_port = False + + is_param = False diff --git a/grc/core/FlowGraph.py b/grc/core/FlowGraph.py new file mode 100644 index 0000000000..313af3107a --- /dev/null +++ b/grc/core/FlowGraph.py @@ -0,0 +1,594 @@ +# Copyright 2008-2015 Free Software Foundation, Inc. +# This file is part of GNU Radio +# +# GNU Radio Companion is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +import imp +import time +from itertools import ifilter, chain +from operator import methodcaller + +import re + +from . import Messages +from .Constants import FLOW_GRAPH_FILE_FORMAT_VERSION +from .Element import Element +from .utils import odict, expr_utils + +_variable_matcher = re.compile('^(variable\w*)$') +_parameter_matcher = re.compile('^(parameter)$') +_monitors_searcher = re.compile('(ctrlport_monitor)') +_bussink_searcher = re.compile('^(bus_sink)$') +_bussrc_searcher = re.compile('^(bus_source)$') +_bus_struct_sink_searcher = re.compile('^(bus_structure_sink)$') +_bus_struct_src_searcher = re.compile('^(bus_structure_source)$') + + +class FlowGraph(Element): + + is_flow_graph = True + + def __init__(self, platform): + """ + Make a flow graph from the arguments. + + Args: + platform: a platforms with blocks and contrcutors + + Returns: + the flow graph object + """ + Element.__init__(self, platform) + self._elements = [] + self._timestamp = time.ctime() + + self.platform = platform # todo: make this a lazy prop + self.blocks = [] + self.connections = [] + + self._eval_cache = {} + self.namespace = {} + + self.grc_file_path = '' + self._options_block = self.new_block('options') + + def __str__(self): + return 'FlowGraph - {}({})'.format(self.get_option('title'), self.get_option('id')) + + ############################################## + # TODO: Move these to new generator package + ############################################## + def get_imports(self): + """ + Get a set of all import statments in this flow graph namespace. + + Returns: + a set of import statements + """ + imports = sum([block.get_imports() for block in self.get_enabled_blocks()], []) + imports = sorted(set(imports)) + return imports + + def get_variables(self): + """ + Get a list of all variables in this flow graph namespace. + Exclude paramterized variables. + + Returns: + a sorted list of variable blocks in order of dependency (indep -> dep) + """ + variables = filter(lambda b: _variable_matcher.match(b.get_key()), self.iter_enabled_blocks()) + return expr_utils.sort_objects(variables, methodcaller('get_id'), methodcaller('get_var_make')) + + def get_parameters(self): + """ + Get a list of all paramterized variables in this flow graph namespace. + + Returns: + a list of paramterized variables + """ + parameters = filter(lambda b: _parameter_matcher.match(b.get_key()), self.iter_enabled_blocks()) + return parameters + + def get_monitors(self): + """ + Get a list of all ControlPort monitors + """ + monitors = filter(lambda b: _monitors_searcher.search(b.get_key()), + self.iter_enabled_blocks()) + return monitors + + def get_python_modules(self): + """Iterate over custom code block ID and Source""" + for block in self.iter_enabled_blocks(): + if block.get_key() == 'epy_module': + yield block.get_id(), block.get_param('source_code').get_value() + + def get_bussink(self): + bussink = filter(lambda b: _bussink_searcher.search(b.get_key()), self.get_enabled_blocks()) + + for i in bussink: + for j in i.get_params(): + if j.get_name() == 'On/Off' and j.get_value() == 'on': + return True + return False + + def get_bussrc(self): + bussrc = filter(lambda b: _bussrc_searcher.search(b.get_key()), self.get_enabled_blocks()) + + for i in bussrc: + for j in i.get_params(): + if j.get_name() == 'On/Off' and j.get_value() == 'on': + return True + return False + + def get_bus_structure_sink(self): + bussink = filter(lambda b: _bus_struct_sink_searcher.search(b.get_key()), self.get_enabled_blocks()) + return bussink + + def get_bus_structure_src(self): + bussrc = filter(lambda b: _bus_struct_src_searcher.search(b.get_key()), self.get_enabled_blocks()) + return bussrc + + def iter_enabled_blocks(self): + """ + Get an iterator of all blocks that are enabled and not bypassed. + """ + return ifilter(methodcaller('get_enabled'), self.blocks) + + def get_enabled_blocks(self): + """ + Get a list of all blocks that are enabled and not bypassed. + + Returns: + a list of blocks + """ + return list(self.iter_enabled_blocks()) + + def get_bypassed_blocks(self): + """ + Get a list of all blocks that are bypassed. + + Returns: + a list of blocks + """ + return filter(methodcaller('get_bypassed'), self.blocks) + + def get_enabled_connections(self): + """ + Get a list of all connections that are enabled. + + Returns: + a list of connections + """ + return filter(methodcaller('get_enabled'), self.connections) + + def get_option(self, key): + """ + Get the option for a given key. + The option comes from the special options block. + + Args: + key: the param key for the options block + + Returns: + the value held by that param + """ + return self._options_block.get_param(key).get_evaluated() + + ############################################## + # Access Elements + ############################################## + def get_block(self, id): + for block in self.blocks: + if block.get_id() == id: + return block + raise KeyError('No block with ID {!r}'.format(id)) + + def get_elements(self): + """ + Get a list of all the elements. + Always ensure that the options block is in the list (only once). + + Returns: + the element list + """ + options_block_count = self.blocks.count(self._options_block) + if not options_block_count: + self.blocks.append(self._options_block) + for i in range(options_block_count-1): + self.blocks.remove(self._options_block) + + return self.blocks + self.connections + + get_children = get_elements + + def rewrite(self): + """ + Flag the namespace to be renewed. + """ + + self.renew_namespace() + for child in chain(self.blocks, self.connections): + child.rewrite() + + self.bus_ports_rewrite() + + def renew_namespace(self): + namespace = {} + # Load imports + for expr in self.get_imports(): + try: + exec expr in namespace + except: + pass + + for id, expr in self.get_python_modules(): + try: + module = imp.new_module(id) + exec expr in module.__dict__ + namespace[id] = module + except: + pass + + # Load parameters + np = {} # params don't know each other + for parameter in self.get_parameters(): + try: + value = eval(parameter.get_param('value').to_code(), namespace) + np[parameter.get_id()] = value + except: + pass + namespace.update(np) # Merge param namespace + + # Load variables + for variable in self.get_variables(): + try: + value = eval(variable.get_var_value(), namespace) + namespace[variable.get_id()] = value + except: + pass + + self.namespace.clear() + self._eval_cache.clear() + self.namespace.update(namespace) + + def evaluate(self, expr): + """ + Evaluate the expression. + + Args: + expr: the string expression + @throw Exception bad expression + + Returns: + the evaluated data + """ + # Evaluate + if not expr: + raise Exception('Cannot evaluate empty statement.') + return self._eval_cache.setdefault(expr, eval(expr, self.namespace)) + + ############################################## + # Add/remove stuff + ############################################## + + def new_block(self, key): + """ + Get a new block of the specified key. + Add the block to the list of elements. + + Args: + key: the block key + + Returns: + the new block or None if not found + """ + try: + block = self.platform.get_new_block(self, key) + self.blocks.append(block) + except KeyError: + block = None + return block + + def connect(self, porta, portb): + """ + Create a connection between porta and portb. + + Args: + porta: a port + portb: another port + @throw Exception bad connection + + Returns: + the new connection + """ + + connection = self.platform.Connection( + flow_graph=self, porta=porta, portb=portb) + self.connections.append(connection) + return connection + + def remove_element(self, element): + """ + Remove the element from the list of elements. + If the element is a port, remove the whole block. + If the element is a block, remove its connections. + If the element is a connection, just remove the connection. + """ + if element.is_port: + # Found a port, set to parent signal block + element = element.get_parent() + + if element in self.blocks: + # Remove block, remove all involved connections + for port in element.get_ports(): + map(self.remove_element, port.get_connections()) + self.blocks.remove(element) + + elif element in self.connections: + if element.is_bus(): + cons_list = [] + for i in map(lambda a: a.get_connections(), element.get_source().get_associated_ports()): + cons_list.extend(i) + map(self.remove_element, cons_list) + self.connections.remove(element) + + ############################################## + # Import/Export Methods + ############################################## + def export_data(self): + """ + Export this flow graph to nested data. + Export all block and connection data. + + Returns: + a nested data odict + """ + # sort blocks and connections for nicer diffs + blocks = sorted(self.blocks, key=lambda b: ( + b.get_key() != 'options', # options to the front + not b.get_key().startswith('variable'), # then vars + str(b) + )) + connections = sorted(self.connections, key=str) + n = odict() + n['timestamp'] = self._timestamp + n['block'] = [b.export_data() for b in blocks] + n['connection'] = [c.export_data() for c in connections] + instructions = odict({ + 'created': '.'.join(self.get_parent().config.version_parts), + 'format': FLOW_GRAPH_FILE_FORMAT_VERSION, + }) + return odict({'flow_graph': n, '_instructions': instructions}) + + def import_data(self, n): + """ + Import blocks and connections into this flow graph. + Clear this flowgraph of all previous blocks and connections. + Any blocks or connections in error will be ignored. + + Args: + n: the nested data odict + """ + # Remove previous elements + del self.blocks[:] + del self.connections[:] + # set file format + try: + instructions = n.find('_instructions') or {} + file_format = int(instructions.get('format', '0')) or _guess_file_format_1(n) + except: + file_format = 0 + + fg_n = n and n.find('flow_graph') or odict() # use blank data if none provided + self._timestamp = fg_n.find('timestamp') or time.ctime() + + # build the blocks + self._options_block = self.new_block('options') + for block_n in fg_n.findall('block'): + key = block_n.find('key') + block = self._options_block if key == 'options' else self.new_block(key) + + if not block: + # we're before the initial fg update(), so no evaluated values! + # --> use raw value instead + path_param = self._options_block.get_param('hier_block_src_path') + file_path = self.platform.find_file_in_paths( + filename=key + '.grc', + paths=path_param.get_value(), + cwd=self.grc_file_path + ) + if file_path: # grc file found. load and get block + self.platform.load_and_generate_flow_graph(file_path) + block = self.new_block(key) # can be None + + if not block: # looks like this block key cannot be found + # create a dummy block instead + block = self.new_block('dummy_block') + # Ugly ugly ugly + _initialize_dummy_block(block, block_n) + print('Block key "%s" not found' % key) + + block.import_data(block_n) + + self.rewrite() # evaluate stuff like nports before adding connections + + # build the connections + def verify_and_get_port(key, block, dir): + ports = block.get_sinks() if dir == 'sink' else block.get_sources() + for port in ports: + if key == port.get_key(): + break + if not key.isdigit() and port.get_type() == '' and key == port.get_name(): + break + else: + if block.is_dummy_block: + port = _dummy_block_add_port(block, key, dir) + else: + raise LookupError('%s key %r not in %s block keys' % (dir, key, dir)) + return port + + errors = False + for connection_n in fg_n.findall('connection'): + # get the block ids and port keys + source_block_id = connection_n.find('source_block_id') + sink_block_id = connection_n.find('sink_block_id') + source_key = connection_n.find('source_key') + sink_key = connection_n.find('sink_key') + try: + source_block = self.get_block(source_block_id) + sink_block = self.get_block(sink_block_id) + + # fix old, numeric message ports keys + if file_format < 1: + source_key, sink_key = _update_old_message_port_keys( + source_key, sink_key, source_block, sink_block) + + # build the connection + source_port = verify_and_get_port(source_key, source_block, 'source') + sink_port = verify_and_get_port(sink_key, sink_block, 'sink') + self.connect(source_port, sink_port) + except LookupError as e: + Messages.send_error_load( + 'Connection between {}({}) and {}({}) could not be made.\n\t{}'.format( + source_block_id, source_key, sink_block_id, sink_key, e)) + errors = True + + self.rewrite() # global rewrite + return errors + + ############################################## + # Needs to go + ############################################## + def bus_ports_rewrite(self): + # todo: move to block.rewrite() + for block in self.blocks: + for direc in ['source', 'sink']: + if direc == 'source': + get_p = block.get_sources + get_p_gui = block.get_sources_gui + bus_structure = block.form_bus_structure('source') + else: + get_p = block.get_sinks + get_p_gui = block.get_sinks_gui + bus_structure = block.form_bus_structure('sink') + + if 'bus' in map(lambda a: a.get_type(), get_p_gui()): + if len(get_p_gui()) > len(bus_structure): + times = range(len(bus_structure), len(get_p_gui())) + for i in times: + for connect in get_p_gui()[-1].get_connections(): + block.get_parent().remove_element(connect) + get_p().remove(get_p_gui()[-1]) + elif len(get_p_gui()) < len(bus_structure): + n = {'name': 'bus', 'type': 'bus'} + if True in map( + lambda a: isinstance(a.get_nports(), int), + get_p()): + n['nports'] = str(1) + + times = range(len(get_p_gui()), len(bus_structure)) + + for i in times: + n['key'] = str(len(get_p())) + n = odict(n) + port = block.get_parent().get_parent().Port( + block=block, n=n, dir=direc) + get_p().append(port) + + if 'bus' in map(lambda a: a.get_type(), + block.get_sources_gui()): + for i in range(len(block.get_sources_gui())): + if len(block.get_sources_gui()[ + i].get_connections()) > 0: + source = block.get_sources_gui()[i] + sink = [] + + for j in range(len(source.get_connections())): + sink.append( + source.get_connections()[j].get_sink()) + for elt in source.get_connections(): + self.remove_element(elt) + for j in sink: + self.connect(source, j) + + +def _update_old_message_port_keys(source_key, sink_key, source_block, sink_block): + """ + Backward compatibility for message port keys + + Message ports use their names as key (like in the 'connect' method). + Flowgraph files from former versions still have numeric keys stored for + message connections. These have to be replaced by the name of the + respective port. The correct message port is deduced from the integer + value of the key (assuming the order has not changed). + + The connection ends are updated only if both ends translate into a + message port. + """ + try: + # get ports using the "old way" (assuming liner indexed keys) + source_port = source_block.get_sources()[int(source_key)] + sink_port = sink_block.get_sinks()[int(sink_key)] + if source_port.get_type() == "message" and sink_port.get_type() == "message": + source_key, sink_key = source_port.get_key(), sink_port.get_key() + except (ValueError, IndexError): + pass + return source_key, sink_key # do nothing + + +def _guess_file_format_1(n): + """ + Try to guess the file format for flow-graph files without version tag + """ + try: + has_non_numeric_message_keys = any(not ( + connection_n.find('source_key').isdigit() and + connection_n.find('sink_key').isdigit() + ) for connection_n in n.find('flow_graph').findall('connection')) + if has_non_numeric_message_keys: + return 1 + except: + pass + return 0 + + +def _initialize_dummy_block(block, block_n): + """ + This is so ugly... dummy-fy a block + Modify block object to get the behaviour for a missing block + """ + + block._key = block_n.find('key') + block.is_dummy_block = lambda: True + block.is_valid = lambda: False + block.get_enabled = lambda: False + for param_n in block_n.findall('param'): + if param_n['key'] not in block.get_param_keys(): + new_param_n = odict({'key': param_n['key'], 'name': param_n['key'], 'type': 'string'}) + params = block.get_parent().get_parent().Param(block=block, n=new_param_n) + block.get_params().append(params) + + +def _dummy_block_add_port(block, key, dir): + """ This is so ugly... Add a port to a dummy-field block """ + port_n = odict({'name': '?', 'key': key, 'type': ''}) + port = block.get_parent().get_parent().Port(block=block, n=port_n, dir=dir) + if port.is_source(): + block.get_sources().append(port) + else: + block.get_sinks().append(port) + return port diff --git a/grc/gui/Messages.py b/grc/core/Messages.py index 551a8ce753..da50487e5b 100644 --- a/grc/gui/Messages.py +++ b/grc/core/Messages.py @@ -1,21 +1,20 @@ -""" -Copyright 2007 Free Software Foundation, Inc. -This file is part of GNU Radio +# Copyright 2007, 2015 Free Software Foundation, Inc. +# This file is part of GNU Radio +# +# GNU Radio Companion is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" import traceback import sys @@ -59,20 +58,12 @@ register_messenger(sys.stdout.write) # Special functions for specific program functionalities ########################################################################### def send_init(platform): - p = platform - - def get_paths(x): - return os.path.abspath(os.path.expanduser(x)), x - - send('\n'.join([ - "<<< Welcome to %s %s >>>" % (p.get_name(), p.get_version()), - "", - "Preferences file: " + p.get_prefs_file(), - "Block paths:" - ] + [ - "\t%s" % path + (" (%s)" % opath if opath != path else "") - for path, opath in map(get_paths, p.get_block_paths()) - ]) + "\n") + msg = "<<< Welcome to {config.name} {config.version} >>>\n\n" \ + "Block paths:\n\t{paths}\n" + send(msg.format( + config=platform.config, + paths="\n\t".join(platform.config.block_paths)) + ) def send_page_switch(file_path): diff --git a/grc/core/Param.py b/grc/core/Param.py new file mode 100644 index 0000000000..d155800c43 --- /dev/null +++ b/grc/core/Param.py @@ -0,0 +1,740 @@ +""" +Copyright 2008-2015 Free Software Foundation, Inc. +This file is part of GNU Radio + +GNU Radio Companion is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +GNU Radio Companion is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +""" + +import ast +import weakref +import re + +from . import Constants +from .Constants import VECTOR_TYPES, COMPLEX_TYPES, REAL_TYPES, INT_TYPES +from .Element import Element +from .utils import odict + +# Blacklist certain ids, its not complete, but should help +import __builtin__ + + +ID_BLACKLIST = ['self', 'options', 'gr', 'blks2', 'wxgui', 'wx', 'math', 'forms', 'firdes'] + dir(__builtin__) +try: + from gnuradio import gr + ID_BLACKLIST.extend(attr for attr in dir(gr.top_block()) if not attr.startswith('_')) +except ImportError: + pass + +_check_id_matcher = re.compile('^[a-z|A-Z]\w*$') +_show_id_matcher = re.compile('^(variable\w*|parameter|options|notebook)$') + + +def _get_keys(lst): + return [elem.get_key() for elem in lst] + + +def _get_elem(lst, key): + try: + return lst[_get_keys(lst).index(key)] + except ValueError: + raise ValueError('Key "{}" not found in {}.'.format(key, _get_keys(lst))) + + +def num_to_str(num): + """ Display logic for numbers """ + def eng_notation(value, fmt='g'): + """Convert a number to a string in engineering notation. E.g., 5e-9 -> 5n""" + template = '{:' + fmt + '}{}' + magnitude = abs(value) + for exp, symbol in zip(range(9, -15-1, -3), 'GMk munpf'): + factor = 10 ** exp + if magnitude >= factor: + return template.format(value / factor, symbol.strip()) + return template.format(value, '') + + if isinstance(num, COMPLEX_TYPES): + num = complex(num) # Cast to python complex + if num == 0: + return '0' + output = eng_notation(num.real) if num.real else '' + output += eng_notation(num.imag, '+g' if output else 'g') + 'j' if num.imag else '' + return output + else: + return str(num) + + +class Option(Element): + + def __init__(self, param, n): + Element.__init__(self, param) + self._name = n.find('name') + self._key = n.find('key') + self._opts = dict() + opts = n.findall('opt') + # Test against opts when non enum + if not self.get_parent().is_enum() and opts: + raise Exception('Options for non-enum types cannot have sub-options') + # Extract opts + for opt in opts: + # Separate the key:value + try: + key, value = opt.split(':') + except: + raise Exception('Error separating "{}" into key:value'.format(opt)) + # Test against repeated keys + if key in self._opts: + raise Exception('Key "{}" already exists in option'.format(key)) + # Store the option + self._opts[key] = value + + def __str__(self): + return 'Option {}({})'.format(self.get_name(), self.get_key()) + + def get_name(self): + return self._name + + def get_key(self): + return self._key + + ############################################## + # Access Opts + ############################################## + def get_opt_keys(self): + return self._opts.keys() + + def get_opt(self, key): + return self._opts[key] + + def get_opts(self): + return self._opts.values() + + +class TemplateArg(object): + """ + A cheetah template argument created from a param. + The str of this class evaluates to the param's to code method. + The use of this class as a dictionary (enum only) will reveal the enum opts. + The __call__ or () method can return the param evaluated to a raw python data type. + """ + + def __init__(self, param): + self._param = weakref.proxy(param) + + def __getitem__(self, item): + return str(self._param.get_opt(item)) if self._param.is_enum() else NotImplemented + + def __str__(self): + return str(self._param.to_code()) + + def __call__(self): + return self._param.get_evaluated() + + +class Param(Element): + + is_param = True + + def __init__(self, block, n): + """ + Make a new param from nested data. + + Args: + block: the parent element + n: the nested odict + """ + # If the base key is a valid param key, copy its data and overlay this params data + base_key = n.find('base_key') + if base_key and base_key in block.get_param_keys(): + n_expanded = block.get_param(base_key)._n.copy() + n_expanded.update(n) + n = n_expanded + # Save odict in case this param will be base for another + self._n = n + # Parse the data + self._name = n.find('name') + self._key = n.find('key') + value = n.find('value') or '' + self._type = n.find('type') or 'raw' + self._hide = n.find('hide') or '' + self._tab_label = n.find('tab') or block.get_param_tab_labels()[0] + if self._tab_label not in block.get_param_tab_labels(): + block.get_param_tab_labels().append(self._tab_label) + # Build the param + Element.__init__(self, block) + # Create the Option objects from the n data + self._options = list() + self._evaluated = None + for option in map(lambda o: Option(param=self, n=o), n.findall('option')): + key = option.get_key() + # Test against repeated keys + if key in self.get_option_keys(): + raise Exception('Key "{}" already exists in options'.format(key)) + # Store the option + self.get_options().append(option) + # Test the enum options + if self.is_enum(): + # Test against options with identical keys + if len(set(self.get_option_keys())) != len(self.get_options()): + raise Exception('Options keys "{}" are not unique.'.format(self.get_option_keys())) + # Test against inconsistent keys in options + opt_keys = self.get_options()[0].get_opt_keys() + for option in self.get_options(): + if set(opt_keys) != set(option.get_opt_keys()): + raise Exception('Opt keys "{}" are not identical across all options.'.format(opt_keys)) + # If a value is specified, it must be in the options keys + if value or value in self.get_option_keys(): + self._value = value + else: + self._value = self.get_option_keys()[0] + if self.get_value() not in self.get_option_keys(): + raise Exception('The value "{}" is not in the possible values of "{}".'.format(self.get_value(), self.get_option_keys())) + else: + self._value = value or '' + self._default = value + self._init = False + self._hostage_cells = list() + self.template_arg = TemplateArg(self) + + def get_types(self): + return ( + 'raw', 'enum', + 'complex', 'real', 'float', 'int', + 'complex_vector', 'real_vector', 'float_vector', 'int_vector', + 'hex', 'string', 'bool', + 'file_open', 'file_save', '_multiline', '_multiline_python_external', + 'id', 'stream_id', + 'grid_pos', 'notebook', 'gui_hint', + 'import', + ) + + def __repr__(self): + """ + Get the repr (nice string format) for this param. + + Returns: + the string representation + """ + ################################################## + # Truncate helper method + ################################################## + def _truncate(string, style=0): + max_len = max(27 - len(self.get_name()), 3) + if len(string) > max_len: + if style < 0: # Front truncate + string = '...' + string[3-max_len:] + elif style == 0: # Center truncate + string = string[:max_len/2 - 3] + '...' + string[-max_len/2:] + elif style > 0: # Rear truncate + string = string[:max_len-3] + '...' + return string + + ################################################## + # Simple conditions + ################################################## + if not self.is_valid(): + return _truncate(self.get_value()) + if self.get_value() in self.get_option_keys(): + return self.get_option(self.get_value()).get_name() + + ################################################## + # Split up formatting by type + ################################################## + # Default center truncate + truncate = 0 + e = self.get_evaluated() + t = self.get_type() + if isinstance(e, bool): + return str(e) + elif isinstance(e, COMPLEX_TYPES): + dt_str = num_to_str(e) + elif isinstance(e, VECTOR_TYPES): + # Vector types + if len(e) > 8: + # Large vectors use code + dt_str = self.get_value() + truncate = 1 + else: + # Small vectors use eval + dt_str = ', '.join(map(num_to_str, e)) + elif t in ('file_open', 'file_save'): + dt_str = self.get_value() + truncate = -1 + else: + # Other types + dt_str = str(e) + + # Done + return _truncate(dt_str, truncate) + + def __repr2__(self): + """ + Get the repr (nice string format) for this param. + + Returns: + the string representation + """ + if self.is_enum(): + return self.get_option(self.get_value()).get_name() + return self.get_value() + + def __str__(self): + return 'Param - {}({})'.format(self.get_name(), self.get_key()) + + def get_color(self): + """ + Get the color that represents this param's type. + + Returns: + a hex color code. + """ + try: + return { + # Number types + 'complex': Constants.COMPLEX_COLOR_SPEC, + 'real': Constants.FLOAT_COLOR_SPEC, + 'float': Constants.FLOAT_COLOR_SPEC, + 'int': Constants.INT_COLOR_SPEC, + # Vector types + 'complex_vector': Constants.COMPLEX_VECTOR_COLOR_SPEC, + 'real_vector': Constants.FLOAT_VECTOR_COLOR_SPEC, + 'float_vector': Constants.FLOAT_VECTOR_COLOR_SPEC, + 'int_vector': Constants.INT_VECTOR_COLOR_SPEC, + # Special + 'bool': Constants.INT_COLOR_SPEC, + 'hex': Constants.INT_COLOR_SPEC, + 'string': Constants.BYTE_VECTOR_COLOR_SPEC, + 'id': Constants.ID_COLOR_SPEC, + 'stream_id': Constants.ID_COLOR_SPEC, + 'grid_pos': Constants.INT_VECTOR_COLOR_SPEC, + 'notebook': Constants.INT_VECTOR_COLOR_SPEC, + 'raw': Constants.WILDCARD_COLOR_SPEC, + }[self.get_type()] + except: + return '#FFFFFF' + + def get_hide(self): + """ + Get the hide value from the base class. + Hide the ID parameter for most blocks. Exceptions below. + If the parameter controls a port type, vlen, or nports, return part. + If the parameter is an empty grid position, return part. + These parameters are redundant to display in the flow graph view. + + Returns: + hide the hide property string + """ + hide = self.get_parent().resolve_dependencies(self._hide).strip() + if hide: + return hide + # Hide ID in non variable blocks + if self.get_key() == 'id' and not _show_id_matcher.match(self.get_parent().get_key()): + return 'part' + # Hide port controllers for type and nports + if self.get_key() in ' '.join(map(lambda p: ' '.join([p._type, p._nports]), + self.get_parent().get_ports())): + return 'part' + # Hide port controllers for vlen, when == 1 + if self.get_key() in ' '.join(map( + lambda p: p._vlen, self.get_parent().get_ports()) + ): + try: + if int(self.get_evaluated()) == 1: + return 'part' + except: + pass + # Hide empty grid positions + if self.get_key() in ('grid_pos', 'notebook') and not self.get_value(): + return 'part' + return hide + + def validate(self): + """ + Validate the param. + The value must be evaluated and type must a possible type. + """ + Element.validate(self) + if self.get_type() not in self.get_types(): + self.add_error_message('Type "{}" is not a possible type.'.format(self.get_type())) + + self._evaluated = None + try: + self._evaluated = self.evaluate() + except Exception, e: + self.add_error_message(str(e)) + + def get_evaluated(self): + return self._evaluated + + def evaluate(self): + """ + Evaluate the value. + + Returns: + evaluated type + """ + self._init = True + self._lisitify_flag = False + self._stringify_flag = False + self._hostage_cells = list() + t = self.get_type() + v = self.get_value() + + ######################### + # Enum Type + ######################### + if self.is_enum(): + return v + + ######################### + # Numeric Types + ######################### + elif t in ('raw', 'complex', 'real', 'float', 'int', 'hex', 'bool'): + # Raise exception if python cannot evaluate this value + try: + e = self.get_parent().get_parent().evaluate(v) + except Exception, e: + raise Exception('Value "{}" cannot be evaluated:\n{}'.format(v, e)) + # Raise an exception if the data is invalid + if t == 'raw': + return e + elif t == 'complex': + if not isinstance(e, COMPLEX_TYPES): + raise Exception('Expression "{}" is invalid for type complex.'.format(str(e))) + return e + elif t == 'real' or t == 'float': + if not isinstance(e, REAL_TYPES): + raise Exception('Expression "{}" is invalid for type float.'.format(str(e))) + return e + elif t == 'int': + if not isinstance(e, INT_TYPES): + raise Exception('Expression "{}" is invalid for type integer.'.format(str(e))) + return e + elif t == 'hex': + return hex(e) + elif t == 'bool': + if not isinstance(e, bool): + raise Exception('Expression "{}" is invalid for type bool.'.format(str(e))) + return e + else: + raise TypeError('Type "{}" not handled'.format(t)) + ######################### + # Numeric Vector Types + ######################### + elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'): + if not v: + # Turn a blank string into an empty list, so it will eval + v = '()' + # Raise exception if python cannot evaluate this value + try: + e = self.get_parent().get_parent().evaluate(v) + except Exception, e: + raise Exception('Value "{}" cannot be evaluated:\n{}'.format(v, e)) + # Raise an exception if the data is invalid + if t == 'complex_vector': + if not isinstance(e, VECTOR_TYPES): + self._lisitify_flag = True + e = [e] + if not all([isinstance(ei, COMPLEX_TYPES) for ei in e]): + raise Exception('Expression "{}" is invalid for type complex vector.'.format(str(e))) + return e + elif t == 'real_vector' or t == 'float_vector': + if not isinstance(e, VECTOR_TYPES): + self._lisitify_flag = True + e = [e] + if not all([isinstance(ei, REAL_TYPES) for ei in e]): + raise Exception('Expression "{}" is invalid for type float vector.'.format(str(e))) + return e + elif t == 'int_vector': + if not isinstance(e, VECTOR_TYPES): + self._lisitify_flag = True + e = [e] + if not all([isinstance(ei, INT_TYPES) for ei in e]): + raise Exception('Expression "{}" is invalid for type integer vector.'.format(str(e))) + return e + ######################### + # String Types + ######################### + elif t in ('string', 'file_open', 'file_save', '_multiline', '_multiline_python_external'): + # Do not check if file/directory exists, that is a runtime issue + try: + e = self.get_parent().get_parent().evaluate(v) + if not isinstance(e, str): + raise Exception() + except: + self._stringify_flag = True + e = str(v) + if t == '_multiline_python_external': + ast.parse(e) # Raises SyntaxError + return e + ######################### + # Unique ID Type + ######################### + elif t == 'id': + # Can python use this as a variable? + if not _check_id_matcher.match(v): + raise Exception('ID "{}" must begin with a letter and may contain letters, numbers, and underscores.'.format(v)) + ids = [param.get_value() for param in self.get_all_params(t)] + + # Id should only appear once, or zero times if block is disabled + if ids.count(v) > 1: + raise Exception('ID "{}" is not unique.'.format(v)) + if v in ID_BLACKLIST: + raise Exception('ID "{}" is blacklisted.'.format(v)) + return v + + ######################### + # Stream ID Type + ######################### + elif t == 'stream_id': + # Get a list of all stream ids used in the virtual sinks + ids = [param.get_value() for param in filter( + lambda p: p.get_parent().is_virtual_sink(), + self.get_all_params(t), + )] + # Check that the virtual sink's stream id is unique + if self.get_parent().is_virtual_sink(): + # Id should only appear once, or zero times if block is disabled + if ids.count(v) > 1: + raise Exception('Stream ID "{}" is not unique.'.format(v)) + # Check that the virtual source's steam id is found + if self.get_parent().is_virtual_source(): + if v not in ids: + raise Exception('Stream ID "{}" is not found.'.format(v)) + return v + + ######################### + # 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('@') + 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) + ######################### + # Grid Position Type + ######################### + elif t == 'grid_pos': + if not v: + # Allow for empty grid pos + return '' + e = self.get_parent().get_parent().evaluate(v) + if not isinstance(e, (list, tuple)) or len(e) != 4 or not all([isinstance(ei, int) for ei in e]): + raise Exception('A grid position must be a list of 4 integers.') + row, col, row_span, col_span = e + # Check row, col + if row < 0 or col < 0: + raise Exception('Row and column must be non-negative.') + # Check row span, col span + if row_span <= 0 or col_span <= 0: + raise Exception('Row and column span must be greater than zero.') + # Get hostage cell parent + try: + my_parent = self.get_parent().get_param('notebook').evaluate() + except: + my_parent = '' + # 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))) + # 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: + raise Exception('Another graphical element is using parent "{}", cell "{}".'.format(str(parent), str(cell))) + return e + ######################### + # Notebook Page Type + ######################### + elif t == 'notebook': + if not v: + # Allow for empty notebook + return '' + + # Get a list of all notebooks + notebook_blocks = filter(lambda b: b.get_key() == 'notebook', self.get_parent().get_parent().get_enabled_blocks()) + # Check for notebook param syntax + try: + notebook_id, page_index = map(str.strip, v.split(',')) + except: + raise Exception('Bad notebook page format.') + # Check that the notebook id is valid + try: + notebook_block = filter(lambda b: b.get_id() == notebook_id, notebook_blocks)[0] + except: + raise Exception('Notebook id "{}" is not an existing notebook id.'.format(notebook_id)) + + # Check that page index exists + if int(page_index) not in range(len(notebook_block.get_param('labels').evaluate())): + raise Exception('Page index "{}" is not a valid index number.'.format(page_index)) + return notebook_id, page_index + + ######################### + # Import Type + ######################### + elif t == 'import': + # New namespace + n = dict() + try: + exec v in n + except ImportError: + raise Exception('Import "{}" failed.'.format(v)) + except Exception: + raise Exception('Bad import syntax: "{}".'.format(v)) + return filter(lambda k: str(k) != '__builtins__', n.keys()) + + ######################### + else: + raise TypeError('Type "{}" not handled'.format(t)) + + def to_code(self): + """ + Convert the value to code. + For string and list types, check the init flag, call evaluate(). + This ensures that evaluate() was called to set the xxxify_flags. + + Returns: + a string representing the code + """ + v = self.get_value() + t = self.get_type() + # String types + if t in ('string', 'file_open', 'file_save', '_multiline', '_multiline_python_external'): + if not self._init: + self.evaluate() + if self._stringify_flag: + return '"%s"' % v.replace('"', '\"') + else: + return v + # Vector types + elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'): + if not self._init: + self.evaluate() + if self._lisitify_flag: + return '(%s, )' % v + else: + return '(%s)' % v + else: + return v + + def get_all_params(self, type): + """ + Get all the params from the flowgraph that have the given type. + + Args: + type: the specified type + + Returns: + a list of params + """ + return sum([filter(lambda p: p.get_type() == type, block.get_params()) for block in self.get_parent().get_parent().get_enabled_blocks()], []) + + def is_enum(self): + return self._type == 'enum' + + def get_value(self): + value = self._value + if self.is_enum() and value not in self.get_option_keys(): + value = self.get_option_keys()[0] + self.set_value(value) + return value + + def set_value(self, value): + # Must be a string + self._value = str(value) + + def set_default(self, value): + if self._default == self._value: + self.set_value(value) + self._default = str(value) + + def get_type(self): + return self.get_parent().resolve_dependencies(self._type) + + def get_tab_label(self): + return self._tab_label + + def get_name(self): + return self.get_parent().resolve_dependencies(self._name).strip() + + def get_key(self): + return self._key + + ############################################## + # Access Options + ############################################## + def get_option_keys(self): + return _get_keys(self.get_options()) + + def get_option(self, key): + return _get_elem(self.get_options(), key) + + def get_options(self): + return self._options + + ############################################## + # Access Opts + ############################################## + def get_opt_keys(self): + return self.get_option(self.get_value()).get_opt_keys() + + def get_opt(self, key): + return self.get_option(self.get_value()).get_opt(key) + + def get_opts(self): + return self.get_option(self.get_value()).get_opts() + + ############################################## + # Import/Export Methods + ############################################## + def export_data(self): + """ + Export this param's key/value. + + Returns: + a nested data odict + """ + n = odict() + n['key'] = self.get_key() + n['value'] = self.get_value() + return n diff --git a/grc/base/ParseXML.py b/grc/core/ParseXML.py index e05fc1428d..c9f6541ee7 100644 --- a/grc/base/ParseXML.py +++ b/grc/core/ParseXML.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2015 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -18,7 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ from lxml import etree -from . import odict + +from .utils import odict xml_failures = {} etree.set_default_parser(etree.XMLParser(remove_comments=True)) @@ -42,7 +43,7 @@ def validate_dtd(xml_file, dtd_file=None): dtd_file: the optional dtd file @throws Exception validation fails """ - # perform parsing, use dtd validation if dtd file is not specified + # Perform parsing, use dtd validation if dtd file is not specified parser = etree.XMLParser(dtd_validation=not dtd_file) try: xml = etree.parse(xml_file, parser=parser) @@ -51,7 +52,7 @@ def validate_dtd(xml_file, dtd_file=None): if parser.error_log: raise XMLSyntaxError(parser.error_log) - # perform dtd validation if the dtd file is specified + # Perform dtd validation if the dtd file is specified if not dtd_file: return try: @@ -100,9 +101,11 @@ def _from_file(xml): nested_data = odict() for elem in xml: key, value = _from_file(elem).items()[0] - if nested_data.has_key(key): nested_data[key].append(value) - else: nested_data[key] = [value] - # delistify if the length of values is 1 + if key in nested_data: + nested_data[key].append(value) + else: + nested_data[key] = [value] + # Delistify if the length of values is 1 for key, values in nested_data.iteritems(): if len(values) == 1: nested_data[key] = values[0] @@ -120,7 +123,8 @@ def to_file(nested_data, xml_file): """ xml_data = "" instructions = nested_data.pop('_instructions', None) - if instructions: # create the processing instruction from the array + # Create the processing instruction from the array + if instructions: xml_data += etree.tostring(etree.ProcessingInstruction( 'grc', ' '.join( "{0}='{1}'".format(*item) for item in instructions.iteritems()) @@ -143,7 +147,7 @@ def _to_file(nested_data): """ nodes = list() for key, values in nested_data.iteritems(): - # listify the values if not a list + # Listify the values if not a list if not isinstance(values, (list, set, tuple)): values = [values] for value in values: diff --git a/grc/core/Platform.py b/grc/core/Platform.py new file mode 100644 index 0000000000..4c1e6f471a --- /dev/null +++ b/grc/core/Platform.py @@ -0,0 +1,319 @@ +""" +Copyright 2008-2016 Free Software Foundation, Inc. +This file is part of GNU Radio + +GNU Radio Companion is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +GNU Radio Companion is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +""" + +import os +import sys + +from . import ParseXML, Messages, Constants + +from .Config import Config +from .Element import Element +from .generator import Generator +from .FlowGraph import FlowGraph +from .Connection import Connection +from .Block import Block +from .Port import Port +from .Param import Param + +from .utils import odict, extract_docs + + +class Platform(Element): + + Config = Config + Generator = Generator + FlowGraph = FlowGraph + Connection = Connection + Block = Block + Port = Port + Param = Param + + is_platform = True + + def __init__(self, *args, **kwargs): + """ Make a platform for GNU Radio """ + Element.__init__(self) + + self.config = self.Config(*args, **kwargs) + + self.block_docstrings = {} + self.block_docstrings_loaded_callback = lambda: None # dummy to be replaced by BlockTreeWindow + + self._docstring_extractor = extract_docs.SubprocessLoader( + callback_query_result=self._save_docstring_extraction_result, + callback_finished=lambda: self.block_docstrings_loaded_callback() + ) + + self._block_dtd = Constants.BLOCK_DTD + self._default_flow_graph = Constants.DEFAULT_FLOW_GRAPH + + # Create a dummy flow graph for the blocks + self._flow_graph = Element(self) + self._flow_graph.connections = [] + + self.blocks = None + self._blocks_n = None + self._category_trees_n = None + self.domains = {} + self.connection_templates = {} + + self._auto_hier_block_generate_chain = set() + + self.load_blocks() + + def __str__(self): + return 'Platform - {}({})'.format(self.config.key, self.config.name) + + @staticmethod + def find_file_in_paths(filename, paths, cwd): + """Checks the provided paths relative to cwd for a certain filename""" + if not os.path.isdir(cwd): + cwd = os.path.dirname(cwd) + if isinstance(paths, str): + paths = (p for p in paths.split(':') if p) + + for path in paths: + path = os.path.expanduser(path) + if not os.path.isabs(path): + path = os.path.normpath(os.path.join(cwd, path)) + file_path = os.path.join(path, filename) + if os.path.exists(os.path.normpath(file_path)): + return file_path + + def load_and_generate_flow_graph(self, file_path): + """Loads a flow graph from file and generates it""" + Messages.set_indent(len(self._auto_hier_block_generate_chain)) + Messages.send('>>> Loading: %r\n' % file_path) + if file_path in self._auto_hier_block_generate_chain: + Messages.send(' >>> Warning: cyclic hier_block dependency\n') + return False + self._auto_hier_block_generate_chain.add(file_path) + try: + flow_graph = self.get_new_flow_graph() + flow_graph.grc_file_path = file_path + # Other, nested higiter_blocks might be auto-loaded here + flow_graph.import_data(self.parse_flow_graph(file_path)) + flow_graph.rewrite() + flow_graph.validate() + if not flow_graph.is_valid(): + raise Exception('Flowgraph invalid') + except Exception as e: + Messages.send('>>> Load Error: {}: {}\n'.format(file_path, str(e))) + return False + finally: + self._auto_hier_block_generate_chain.discard(file_path) + Messages.set_indent(len(self._auto_hier_block_generate_chain)) + + try: + Messages.send('>>> Generating: {}\n'.format(file_path)) + generator = self.Generator(flow_graph, file_path) + generator.write() + except Exception as e: + Messages.send('>>> Generate Error: {}: {}\n'.format(file_path, str(e))) + return False + + self.load_block_xml(generator.get_file_path_xml()) + return True + + def load_blocks(self): + """load the blocks and block tree from the search paths""" + self._docstring_extractor.start() + # Reset + self.blocks = odict() + self._blocks_n = odict() + self._category_trees_n = list() + self.domains.clear() + self.connection_templates.clear() + ParseXML.xml_failures.clear() + # Try to parse and load blocks + for xml_file in self.iter_xml_files(): + try: + if xml_file.endswith("block_tree.xml"): + self.load_category_tree_xml(xml_file) + elif xml_file.endswith('domain.xml'): + self.load_domain_xml(xml_file) + else: + self.load_block_xml(xml_file) + except ParseXML.XMLSyntaxError as e: + # print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s' % (e, xml_file) + pass + except Exception as e: + print >> sys.stderr, 'Warning: XML parsing failed:\n\t%r\n\tIgnoring: %s' % (e, xml_file) + + self._docstring_extractor.finish() + # self._docstring_extractor.wait() + + def iter_xml_files(self): + """Iterator for block descriptions and category trees""" + for block_path in self.config.block_paths: + if os.path.isfile(block_path): + yield block_path + elif os.path.isdir(block_path): + for dirpath, dirnames, filenames in os.walk(block_path): + for filename in sorted(filter(lambda f: f.endswith('.xml'), filenames)): + yield os.path.join(dirpath, filename) + + def load_block_xml(self, xml_file): + """Load block description from xml file""" + # Validate and import + ParseXML.validate_dtd(xml_file, self._block_dtd) + n = ParseXML.from_file(xml_file).find('block') + n['block_wrapper_path'] = xml_file # inject block wrapper path + # Get block instance and add it to the list of blocks + block = self.Block(self._flow_graph, n) + key = block.get_key() + if key in self.blocks: + print >> sys.stderr, 'Warning: Block with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file) + else: # Store the block + self.blocks[key] = block + self._blocks_n[key] = n + + self._docstring_extractor.query( + block.get_key(), + block.get_imports(raw=True), + block.get_make(raw=True) + ) + + def load_category_tree_xml(self, xml_file): + """Validate and parse category tree file and add it to list""" + ParseXML.validate_dtd(xml_file, Constants.BLOCK_TREE_DTD) + n = ParseXML.from_file(xml_file).find('cat') + self._category_trees_n.append(n) + + def load_domain_xml(self, xml_file): + """Load a domain properties and connection templates from XML""" + ParseXML.validate_dtd(xml_file, Constants.DOMAIN_DTD) + n = ParseXML.from_file(xml_file).find('domain') + + key = n.find('key') + if not key: + print >> sys.stderr, 'Warning: Domain with emtpy key.\n\tIgnoring: {}'.format(xml_file) + return + if key in self.domains: # test against repeated keys + print >> sys.stderr, 'Warning: Domain with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file) + return + + #to_bool = lambda s, d: d if s is None else s.lower() not in ('false', 'off', '0', '') + def to_bool(s, d): + if s is not None: + return s.lower() not in ('false', 'off', '0', '') + return d + + color = n.find('color') or '' + try: + import gtk # ugly but handy + gtk.gdk.color_parse(color) + except (ValueError, ImportError): + if color: # no color is okay, default set in GUI + print >> sys.stderr, 'Warning: Can\'t parse color code "{}" for domain "{}" '.format(color, key) + color = None + + self.domains[key] = dict( + name=n.find('name') or key, + multiple_sinks=to_bool(n.find('multiple_sinks'), True), + multiple_sources=to_bool(n.find('multiple_sources'), False), + color=color + ) + for connection_n in n.findall('connection'): + key = (connection_n.find('source_domain'), connection_n.find('sink_domain')) + if not all(key): + print >> sys.stderr, 'Warning: Empty domain key(s) in connection template.\n\t{}'.format(xml_file) + elif key in self.connection_templates: + print >> sys.stderr, 'Warning: Connection template "{}" already exists.\n\t{}'.format(key, xml_file) + else: + self.connection_templates[key] = connection_n.find('make') or '' + + def load_block_tree(self, block_tree): + """ + Load a block tree with categories and blocks. + Step 1: Load all blocks from the xml specification. + Step 2: Load blocks with builtin category specifications. + + Args: + block_tree: the block tree object + """ + # Recursive function to load categories and blocks + def load_category(cat_n, parent=None): + # Add this category + parent = (parent or []) + [cat_n.find('name')] + block_tree.add_block(parent) + # Recursive call to load sub categories + map(lambda c: load_category(c, parent), cat_n.findall('cat')) + # Add blocks in this category + for block_key in cat_n.findall('block'): + if block_key not in self.blocks: + print >> sys.stderr, 'Warning: Block key "{}" not found when loading category tree.'.format(block_key) + continue + block = self.blocks[block_key] + # If it exists, the block's category shall not be overridden by the xml tree + if not block.get_category(): + block.set_category(parent) + + # Recursively load the category trees and update the categories for each block + for category_tree_n in self._category_trees_n: + load_category(category_tree_n) + + # Add blocks to block tree + for block in self.blocks.itervalues(): + # Blocks with empty categories are hidden + if not block.get_category(): + continue + block_tree.add_block(block.get_category(), block) + + def _save_docstring_extraction_result(self, key, docstrings): + docs = {} + for match, docstring in docstrings.iteritems(): + if not docstring or match.endswith('_sptr'): + continue + docstring = docstring.replace('\n\n', '\n').strip() + docs[match] = docstring + self.block_docstrings[key] = docs + + ############################################## + # Access + ############################################## + + def parse_flow_graph(self, flow_graph_file): + """ + Parse a saved flow graph file. + Ensure that the file exists, and passes the dtd check. + + Args: + flow_graph_file: the flow graph file + + Returns: + nested data + @throws exception if the validation fails + """ + flow_graph_file = flow_graph_file or self._default_flow_graph + open(flow_graph_file, 'r') # Test open + ParseXML.validate_dtd(flow_graph_file, Constants.FLOW_GRAPH_DTD) + return ParseXML.from_file(flow_graph_file) + + def get_new_flow_graph(self): + return self.FlowGraph(platform=self) + + def get_blocks(self): + return self.blocks.values() + + def get_new_block(self, flow_graph, key): + return self.Block(flow_graph, n=self._blocks_n[key]) + + def get_colors(self): + return [(name, color) for name, key, sizeof, color in Constants.CORE_TYPES] diff --git a/grc/core/Port.py b/grc/core/Port.py new file mode 100644 index 0000000000..6a8f484082 --- /dev/null +++ b/grc/core/Port.py @@ -0,0 +1,404 @@ +""" +Copyright 2008-2015 Free Software Foundation, Inc. +This file is part of GNU Radio + +GNU Radio Companion is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +GNU Radio Companion is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +""" + +from .Constants import DEFAULT_DOMAIN, GR_STREAM_DOMAIN, GR_MESSAGE_DOMAIN +from .Element import Element + +from . import Constants + + +def _get_source_from_virtual_sink_port(vsp): + """ + Resolve the source port that is connected to the given virtual sink port. + Use the get source from virtual source to recursively resolve subsequent ports. + """ + try: + return _get_source_from_virtual_source_port( + vsp.get_enabled_connections()[0].get_source()) + except: + raise Exception('Could not resolve source for virtual sink port {}'.format(vsp)) + + +def _get_source_from_virtual_source_port(vsp, traversed=[]): + """ + Recursively resolve source ports over the virtual connections. + Keep track of traversed sources to avoid recursive loops. + """ + if not vsp.get_parent().is_virtual_source(): + return vsp + if vsp in traversed: + raise Exception('Loop found when resolving virtual source {}'.format(vsp)) + try: + return _get_source_from_virtual_source_port( + _get_source_from_virtual_sink_port( + filter( # Get all virtual sinks with a matching stream id + lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(), + filter( # Get all enabled blocks that are also virtual sinks + lambda b: b.is_virtual_sink(), + vsp.get_parent().get_parent().get_enabled_blocks(), + ), + )[0].get_sinks()[0] + ), traversed + [vsp], + ) + except: + raise Exception('Could not resolve source for virtual source port {}'.format(vsp)) + + +def _get_sink_from_virtual_source_port(vsp): + """ + Resolve the sink port that is connected to the given virtual source port. + Use the get sink from virtual sink to recursively resolve subsequent ports. + """ + try: + # Could have many connections, but use first + return _get_sink_from_virtual_sink_port( + vsp.get_enabled_connections()[0].get_sink()) + except: + raise Exception('Could not resolve source for virtual source port {}'.format(vsp)) + + +def _get_sink_from_virtual_sink_port(vsp, traversed=[]): + """ + Recursively resolve sink ports over the virtual connections. + Keep track of traversed sinks to avoid recursive loops. + """ + if not vsp.get_parent().is_virtual_sink(): + return vsp + if vsp in traversed: + raise Exception('Loop found when resolving virtual sink {}'.format(vsp)) + try: + return _get_sink_from_virtual_sink_port( + _get_sink_from_virtual_source_port( + filter( # Get all virtual source with a matching stream id + lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(), + filter( # Get all enabled blocks that are also virtual sinks + lambda b: b.is_virtual_source(), + vsp.get_parent().get_parent().get_enabled_blocks(), + ), + )[0].get_sources()[0] + ), traversed + [vsp], + ) + except: + raise Exception('Could not resolve source for virtual sink port {}'.format(vsp)) + + +class Port(Element): + + is_port = True + + def __init__(self, block, n, dir): + """ + Make a new port from nested data. + + Args: + block: the parent element + n: the nested odict + dir: the direction + """ + self._n = n + if n['type'] == 'message': + n['domain'] = GR_MESSAGE_DOMAIN + if 'domain' not in n: + n['domain'] = DEFAULT_DOMAIN + elif n['domain'] == GR_MESSAGE_DOMAIN: + n['key'] = n['name'] + n['type'] = 'message' # For port color + if n['type'] == 'msg': + n['key'] = 'msg' + if not n.find('key'): + n['key'] = str(next(block.port_counters[dir == 'source'])) + + # Build the port + Element.__init__(self, block) + # Grab the data + self._name = n['name'] + self._key = n['key'] + self._type = n['type'] or '' + self._domain = n['domain'] + self._hide = n.find('hide') or '' + self._dir = dir + self._hide_evaluated = False # Updated on rewrite() + + self._nports = n.find('nports') or '' + self._vlen = n.find('vlen') or '' + self._optional = bool(n.find('optional')) + self._clones = [] # References to cloned ports (for nports > 1) + + def __str__(self): + if self.is_source: + return 'Source - {}({})'.format(self.get_name(), self.get_key()) + if self.is_sink: + return 'Sink - {}({})'.format(self.get_name(), self.get_key()) + + def get_types(self): + return Constants.TYPE_TO_SIZEOF.keys() + + def is_type_empty(self): + return not self._n['type'] + + def validate(self): + Element.validate(self) + if self.get_type() not in self.get_types(): + self.add_error_message('Type "{}" is not a possible type.'.format(self.get_type())) + platform = self.get_parent().get_parent().get_parent() + if self.get_domain() not in platform.domains: + self.add_error_message('Domain key "{}" is not registered.'.format(self.get_domain())) + if not self.get_enabled_connections() and not self.get_optional(): + self.add_error_message('Port is not connected.') + # Message port logic + if self.get_type() == 'msg': + if self.get_nports(): + self.add_error_message('A port of type "msg" cannot have "nports" set.') + if self.get_vlen() != 1: + self.add_error_message('A port of type "msg" must have a "vlen" of 1.') + + def rewrite(self): + """ + Handle the port cloning for virtual blocks. + """ + if self.is_type_empty(): + try: + # Clone type and vlen + source = self.resolve_empty_type() + self._type = str(source.get_type()) + self._vlen = str(source.get_vlen()) + except: + # Reset type and vlen + self._type = '' + self._vlen = '' + + Element.rewrite(self) + hide = self.get_parent().resolve_dependencies(self._hide).strip().lower() + self._hide_evaluated = False if hide in ('false', 'off', '0') else bool(hide) + + # Update domain if was deduced from (dynamic) port type + type_ = self.get_type() + if self._domain == GR_STREAM_DOMAIN and type_ == "message": + self._domain = GR_MESSAGE_DOMAIN + self._key = self._name + if self._domain == GR_MESSAGE_DOMAIN and type_ != "message": + self._domain = GR_STREAM_DOMAIN + self._key = '0' # Is rectified in rewrite() + + def resolve_virtual_source(self): + if self.get_parent().is_virtual_sink(): + return _get_source_from_virtual_sink_port(self) + if self.get_parent().is_virtual_source(): + return _get_source_from_virtual_source_port(self) + + def resolve_empty_type(self): + if self.is_sink: + try: + src = _get_source_from_virtual_sink_port(self) + if not src.is_type_empty(): + return src + except: + pass + sink = _get_sink_from_virtual_sink_port(self) + if not sink.is_type_empty(): + return sink + if self.is_source: + try: + src = _get_source_from_virtual_source_port(self) + if not src.is_type_empty(): + return src + except: + pass + sink = _get_sink_from_virtual_source_port(self) + if not sink.is_type_empty(): + return sink + + def get_vlen(self): + """ + Get the vector length. + If the evaluation of vlen cannot be cast to an integer, return 1. + + Returns: + the vector length or 1 + """ + vlen = self.get_parent().resolve_dependencies(self._vlen) + try: + return int(self.get_parent().get_parent().evaluate(vlen)) + except: + return 1 + + def get_nports(self): + """ + Get the number of ports. + If already blank, return a blank + If the evaluation of nports cannot be cast to a positive integer, return 1. + + Returns: + the number of ports or 1 + """ + if self._nports == '': + return '' + + nports = self.get_parent().resolve_dependencies(self._nports) + try: + return max(1, int(self.get_parent().get_parent().evaluate(nports))) + except: + return 1 + + def get_optional(self): + return bool(self._optional) + + def get_color(self): + """ + Get the color that represents this port's type. + Codes differ for ports where the vec length is 1 or greater than 1. + + Returns: + a hex color code. + """ + try: + color = Constants.TYPE_TO_COLOR[self.get_type()] + vlen = self.get_vlen() + if vlen == 1: + return color + color_val = int(color[1:], 16) + r = (color_val >> 16) & 0xff + g = (color_val >> 8) & 0xff + b = (color_val >> 0) & 0xff + dark = (0, 0, 30, 50, 70)[min(4, vlen)] + r = max(r-dark, 0) + g = max(g-dark, 0) + b = max(b-dark, 0) + # TODO: Change this to .format() + return '#%.2x%.2x%.2x' % (r, g, b) + except: + return '#FFFFFF' + + def get_clones(self): + """ + Get the clones of this master port (nports > 1) + + Returns: + a list of ports + """ + return self._clones + + def add_clone(self): + """ + Create a clone of this (master) port and store a reference in self._clones. + + The new port name (and key for message ports) will have index 1... appended. + If this is the first clone, this (master) port will get a 0 appended to its name (and key) + + Returns: + the cloned port + """ + # Add index to master port name if there are no clones yet + if not self._clones: + self._name = self._n['name'] + '0' + # Also update key for none stream ports + if not self._key.isdigit(): + self._key = self._name + + # Prepare a copy of the odict for the clone + n = self._n.copy() + # Remove nports from the key so the copy cannot be a duplicator + if 'nports' in n: + n.pop('nports') + n['name'] = self._n['name'] + str(len(self._clones) + 1) + # Dummy value 99999 will be fixed later + n['key'] = '99999' if self._key.isdigit() else n['name'] + + # Clone + port = self.__class__(self.get_parent(), n, self._dir) + self._clones.append(port) + return port + + def remove_clone(self, port): + """ + Remove a cloned port (from the list of clones only) + Remove the index 0 of the master port name (and key9 if there are no more clones left + """ + self._clones.remove(port) + # Remove index from master port name if there are no more clones + if not self._clones: + self._name = self._n['name'] + # Also update key for none stream ports + if not self._key.isdigit(): + self._key = self._name + + def get_name(self): + number = '' + if self.get_type() == 'bus': + busses = filter(lambda a: a._dir == self._dir, self.get_parent().get_ports_gui()) + number = str(busses.index(self)) + '#' + str(len(self.get_associated_ports())) + return self._name + number + + def get_key(self): + return self._key + + @property + def is_sink(self): + return self._dir == 'sink' + + @property + def is_source(self): + return self._dir == 'source' + + def get_type(self): + return self.get_parent().resolve_dependencies(self._type) + + def get_domain(self): + return self._domain + + def get_hide(self): + return self._hide_evaluated + + def get_connections(self): + """ + Get all connections that use this port. + + Returns: + a list of connection objects + """ + connections = self.get_parent().get_parent().connections + connections = filter(lambda c: c.get_source() is self or c.get_sink() is self, connections) + return connections + + def get_enabled_connections(self): + """ + Get all enabled connections that use this port. + + Returns: + a list of connection objects + """ + return filter(lambda c: c.get_enabled(), self.get_connections()) + + def get_associated_ports(self): + if not self.get_type() == 'bus': + return [self] + else: + if self.is_source: + get_ports = self.get_parent().get_sources + bus_structure = self.get_parent().current_bus_structure['source'] + else: + get_ports = self.get_parent().get_sinks + bus_structure = self.get_parent().current_bus_structure['sink'] + + ports = [i for i in get_ports() if not i.get_type() == 'bus'] + if bus_structure: + busses = [i for i in get_ports() if i.get_type() == 'bus'] + bus_index = busses.index(self) + ports = filter(lambda a: ports.index(a) in bus_structure[bus_index], ports) + return ports diff --git a/grc/python/__init__.py b/grc/core/__init__.py index 8b13789179..8b13789179 100644 --- a/grc/python/__init__.py +++ b/grc/core/__init__.py diff --git a/grc/python/block.dtd b/grc/core/block.dtd index 145f4d8610..145f4d8610 100644 --- a/grc/python/block.dtd +++ b/grc/core/block.dtd diff --git a/grc/base/block_tree.dtd b/grc/core/block_tree.dtd index 9e23576477..9e23576477 100644 --- a/grc/base/block_tree.dtd +++ b/grc/core/block_tree.dtd diff --git a/grc/python/default_flow_graph.grc b/grc/core/default_flow_graph.grc index 059509d34b..059509d34b 100644 --- a/grc/python/default_flow_graph.grc +++ b/grc/core/default_flow_graph.grc diff --git a/grc/base/domain.dtd b/grc/core/domain.dtd index b5b0b8bf39..b5b0b8bf39 100644 --- a/grc/base/domain.dtd +++ b/grc/core/domain.dtd diff --git a/grc/base/flow_graph.dtd b/grc/core/flow_graph.dtd index bdfe1dc059..bdfe1dc059 100644 --- a/grc/base/flow_graph.dtd +++ b/grc/core/flow_graph.dtd diff --git a/grc/python/CMakeLists.txt b/grc/core/generator/CMakeLists.txt index 3f9e273146..4bdd59a7a2 100644 --- a/grc/python/CMakeLists.txt +++ b/grc/core/generator/CMakeLists.txt @@ -17,28 +17,16 @@ # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. -######################################################################## -GR_PYTHON_INSTALL(FILES - expr_utils.py - extract_docs.py - epy_block_io.py - Block.py - Connection.py - Constants.py - FlowGraph.py - Generator.py - Param.py - Platform.py - Port.py - __init__.py - DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/python +file(GLOB py_files "*.py") + +GR_PYTHON_INSTALL( + FILES ${py_files} + DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core/generator COMPONENT "grc" ) install(FILES - block.dtd - default_flow_graph.grc flow_graph.tmpl - DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/python + DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core/generator COMPONENT "grc" ) diff --git a/grc/core/generator/FlowGraphProxy.py b/grc/core/generator/FlowGraphProxy.py new file mode 100644 index 0000000000..3723005576 --- /dev/null +++ b/grc/core/generator/FlowGraphProxy.py @@ -0,0 +1,126 @@ +# Copyright 2016 Free Software Foundation, Inc. +# This file is part of GNU Radio +# +# GNU Radio Companion is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + +class FlowGraphProxy(object): + + def __init__(self, fg): + self._fg = fg + + def __getattr__(self, item): + return getattr(self._fg, item) + + def get_hier_block_stream_io(self, direction): + """ + Get a list of stream io signatures for this flow graph. + + Args: + direction: a string of 'in' or 'out' + + Returns: + a list of dicts with: type, label, vlen, size, optional + """ + return filter(lambda p: p['type'] != "message", self.get_hier_block_io(direction)) + + def get_hier_block_message_io(self, direction): + """ + Get a list of message io signatures for this flow graph. + + Args: + direction: a string of 'in' or 'out' + + Returns: + a list of dicts with: type, label, vlen, size, optional + """ + return filter(lambda p: p['type'] == "message", self.get_hier_block_io(direction)) + + def get_hier_block_io(self, direction): + """ + Get a list of io ports for this flow graph. + + Args: + direction: a string of 'in' or 'out' + + Returns: + a list of dicts with: type, label, vlen, size, optional + """ + pads = self.get_pad_sources() if direction in ('sink', 'in') else \ + self.get_pad_sinks() if direction in ('source', 'out') else [] + ports = [] + for pad in pads: + master = { + 'label': str(pad.get_param('label').get_evaluated()), + 'type': str(pad.get_param('type').get_evaluated()), + 'vlen': str(pad.get_param('vlen').get_value()), + 'size': pad.get_param('type').get_opt('size'), + 'optional': bool(pad.get_param('optional').get_evaluated()), + } + num_ports = pad.get_param('num_streams').get_evaluated() + if num_ports > 1: + for i in xrange(num_ports): + clone = master.copy() + clone['label'] += str(i) + ports.append(clone) + else: + ports.append(master) + return ports + + def get_pad_sources(self): + """ + Get a list of pad source blocks sorted by id order. + + Returns: + a list of pad source blocks in this flow graph + """ + pads = filter(lambda b: b.get_key() == 'pad_source', self.get_enabled_blocks()) + return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id())) + + def get_pad_sinks(self): + """ + Get a list of pad sink blocks sorted by id order. + + Returns: + a list of pad sink blocks in this flow graph + """ + pads = filter(lambda b: b.get_key() == 'pad_sink', self.get_enabled_blocks()) + return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id())) + + def get_pad_port_global_key(self, port): + """ + Get the key for a port of a pad source/sink to use in connect() + This takes into account that pad blocks may have multiple ports + + Returns: + the key (str) + """ + key_offset = 0 + pads = self.get_pad_sources() if port.is_source else self.get_pad_sinks() + for pad in pads: + # using the block param 'type' instead of the port domain here + # to emphasize that hier block generation is domain agnostic + is_message_pad = pad.get_param('type').get_evaluated() == "message" + if port.get_parent() == pad: + if is_message_pad: + key = pad.get_param('label').get_value() + else: + key = str(key_offset + int(port.get_key())) + return key + else: + # assuming we have either only sources or sinks + if not is_message_pad: + key_offset += len(pad.get_ports()) + return -1
\ No newline at end of file diff --git a/grc/python/Generator.py b/grc/core/generator/Generator.py index 56e3a6e78f..91671072d6 100644 --- a/grc/python/Generator.py +++ b/grc/core/generator/Generator.py @@ -1,41 +1,37 @@ -""" -Copyright 2008-2011 Free Software Foundation, Inc. -This file is part of GNU Radio +# Copyright 2008-2016 Free Software Foundation, Inc. +# This file is part of GNU Radio +# +# GNU Radio Companion is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" +import codecs import os -import sys -import subprocess import tempfile -import shlex -import codecs -import re # for shlex_quote -from distutils.spawn import find_executable from Cheetah.Template import Template -from .. gui import Messages -from .. base import ParseXML -from .. base import odict -from .. base.Constants import BLOCK_FLAG_NEED_QT_GUI +from .FlowGraphProxy import FlowGraphProxy +from .. import ParseXML, Messages +from ..Constants import ( + TOP_BLOCK_FILE_MODE, BLOCK_FLAG_NEED_QT_GUI, + HIER_BLOCK_FILE_MODE, BLOCK_DTD +) +from ..utils import expr_utils, odict -from . Constants import TOP_BLOCK_FILE_MODE, FLOW_GRAPH_TEMPLATE, \ - XTERM_EXECUTABLE, HIER_BLOCK_FILE_MODE, HIER_BLOCKS_LIB_DIR, BLOCK_DTD -from . import expr_utils +DATA_DIR = os.path.dirname(__file__) +FLOW_GRAPH_TEMPLATE = os.path.join(DATA_DIR, 'flow_graph.tmpl') class Generator(object): @@ -50,19 +46,16 @@ class Generator(object): flow_graph: the flow graph object file_path: the path to the grc file """ - self._generate_options = flow_graph.get_option('generate_options') - if self._generate_options == 'hb': + self.generate_options = flow_graph.get_option('generate_options') + if self.generate_options == 'hb': generator_cls = HierBlockGenerator - elif self._generate_options == 'hb_qt_gui': + elif self.generate_options == 'hb_qt_gui': generator_cls = QtHierBlockGenerator else: generator_cls = TopBlockGenerator self._generator = generator_cls(flow_graph, file_path) - def get_generate_options(self): - return self._generate_options - def __getattr__(self, item): """get all other attrib from actual generator object""" return getattr(self._generator, item) @@ -78,23 +71,23 @@ class TopBlockGenerator(object): flow_graph: the flow graph object file_path: the path to write the file to """ - self._flow_graph = flow_graph + self._flow_graph = FlowGraphProxy(flow_graph) self._generate_options = self._flow_graph.get_option('generate_options') self._mode = TOP_BLOCK_FILE_MODE dirname = self._dirname = os.path.dirname(file_path) - # handle the case where the directory is read-only - # in this case, use the system's temp directory + # Handle the case where the directory is read-only + # In this case, use the system's temp directory if not os.access(dirname, os.W_OK): dirname = tempfile.gettempdir() filename = self._flow_graph.get_option('id') + '.py' - self._file_path = os.path.join(dirname, filename) + self.file_path = os.path.join(dirname, filename) def get_file_path(self): - return self._file_path + return self.file_path def write(self): """generate output and write it to files""" - # do throttle warning + # Do throttle warning throttling_blocks = filter(lambda b: b.throtteling(), self._flow_graph.get_enabled_blocks()) if not throttling_blocks and not self._generate_options.startswith('hb'): Messages.send_warning("This flow graph may not have flow control: " @@ -109,48 +102,16 @@ class TopBlockGenerator(object): "e.g. a hardware source or sink. " "This is usually undesired. Consider " "removing the throttle block.") - # generate + # Generate for filename, data in self._build_python_code_from_template(): with codecs.open(filename, 'w', encoding='utf-8') as fp: fp.write(data) - if filename == self.get_file_path(): + if filename == self.file_path: try: os.chmod(filename, self._mode) except: pass - def get_popen(self): - """ - Execute this python flow graph. - - Returns: - a popen object - """ - run_command = self._flow_graph.get_option('run_command') - try: - run_command = run_command.format( - python=shlex_quote(sys.executable), - filename=shlex_quote(self.get_file_path())) - run_command_args = shlex.split(run_command) - except Exception as e: - raise ValueError("Can't parse run command {!r}: {}".format(run_command, e)) - - # when in no gui mode on linux, use a graphical terminal (looks nice) - xterm_executable = find_executable(XTERM_EXECUTABLE) - if self._generate_options == 'no_gui' and xterm_executable: - run_command_args = [xterm_executable, '-e', run_command] - - # this does not reproduce a shell executable command string, if a graphical - # terminal is used. Passing run_command though shlex_quote would do it but - # it looks really ugly and confusing in the console panel. - Messages.send_start_exec(' '.join(run_command_args)) - - return subprocess.Popen( - args=run_command_args, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - shell=False, universal_newlines=True - ) - def _build_python_code_from_template(self): """ Convert the flow graph to python code. @@ -167,21 +128,21 @@ class TopBlockGenerator(object): parameters = fg.get_parameters() monitors = fg.get_monitors() - # list of blocks not including variables and imports and parameters and disabled + # List of blocks not including variables and imports and parameters and disabled def _get_block_sort_text(block): code = block.get_make().replace(block.get_id(), ' ') try: - code += block.get_param('notebook').get_value() # older gui markup w/ wxgui + code += block.get_param('notebook').get_value() # Older gui markup w/ wxgui except: pass try: - code += block.get_param('gui_hint').get_value() # newer gui markup w/ qtgui + code += block.get_param('gui_hint').get_value() # Newer gui markup w/ qtgui except: pass return code blocks = expr_utils.sort_objects( - filter(lambda b: b.get_enabled() and not b.get_bypassed(), fg.iter_blocks()), + filter(lambda b: b.get_enabled() and not b.get_bypassed(), fg.blocks), lambda b: b.get_id(), _get_block_sort_text ) # List of regular blocks (all blocks minus the special ones) @@ -198,7 +159,8 @@ class TopBlockGenerator(object): output.append((file_path, src)) # Filter out virtual sink connections - cf = lambda c: not (c.is_bus() or c.is_msg() or c.get_sink().get_parent().is_virtual_sink()) + def cf(c): + return not (c.is_bus() or c.is_msg() or c.get_sink().get_parent().is_virtual_sink()) connections = filter(cf, fg.get_enabled_connections()) # Get the virtual blocks and resolve their connections @@ -220,8 +182,7 @@ class TopBlockGenerator(object): for block in bypassed_blocks: # Get the upstream connection (off of the sink ports) # Use *connections* not get_connections() - get_source_connection = lambda c: c.get_sink() == block.get_sinks()[0] - source_connection = filter(get_source_connection, connections) + source_connection = filter(lambda c: c.get_sink() == block.get_sinks()[0], connections) # The source connection should never have more than one element. assert (len(source_connection) == 1) @@ -229,8 +190,7 @@ class TopBlockGenerator(object): source_port = source_connection[0].get_source() # Loop through all the downstream connections - get_sink_connections = lambda c: c.get_source() == block.get_sources()[0] - for sink in filter(get_sink_connections, connections): + for sink in filter(lambda c: c.get_source() == block.get_sources()[0], connections): if not sink.get_enabled(): # Ignore disabled connections continue @@ -248,23 +208,23 @@ class TopBlockGenerator(object): c.get_source().get_parent().get_id(), c.get_sink().get_parent().get_id() )) - connection_templates = fg.get_parent().get_connection_templates() + connection_templates = fg.get_parent().connection_templates msgs = filter(lambda c: c.is_msg(), fg.get_enabled_connections()) - # list of variable names + # List of variable names var_ids = [var.get_id() for var in parameters + variables] - # prepend self. + # Prepend self. replace_dict = dict([(var_id, 'self.%s' % var_id) for var_id in var_ids]) - # list of callbacks + # List of callbacks callbacks = [ expr_utils.expr_replace(cb, replace_dict) for cb in sum([block.get_callbacks() for block in fg.get_enabled_blocks()], []) - ] - # map var id to callbacks + ] + # Map var id to callbacks var_id2cbs = dict([ (var_id, filter(lambda c: expr_utils.get_variable_dependencies(c, [var_id]), callbacks)) for var_id in var_ids ]) - # load the namespace + # Load the namespace namespace = { 'title': title, 'imports': imports, @@ -279,9 +239,9 @@ class TopBlockGenerator(object): 'generate_options': self._generate_options, 'var_id2cbs': var_id2cbs, } - # build the template + # Build the template t = Template(open(FLOW_GRAPH_TEMPLATE, 'r').read(), namespace) - output.append((self.get_file_path(), str(t))) + output.append((self.file_path, str(t))) return output @@ -297,10 +257,15 @@ class HierBlockGenerator(TopBlockGenerator): file_path: where to write the py file (the xml goes into HIER_BLOCK_LIB_DIR) """ TopBlockGenerator.__init__(self, flow_graph, file_path) + platform = flow_graph.get_parent() + + hier_block_lib_dir = platform.config.hier_block_lib_dir + if not os.path.exists(hier_block_lib_dir): + os.mkdir(hier_block_lib_dir) + self._mode = HIER_BLOCK_FILE_MODE - self._file_path = os.path.join(HIER_BLOCKS_LIB_DIR, - self._flow_graph.get_option('id') + '.py') - self._file_path_xml = self._file_path + '.xml' + self.file_path = os.path.join(hier_block_lib_dir, self._flow_graph.get_option('id') + '.py') + self._file_path_xml = self.file_path + '.xml' def get_file_path_xml(self): return self._file_path_xml @@ -322,7 +287,7 @@ class HierBlockGenerator(TopBlockGenerator): Returns: a xml node tree """ - # extract info from the flow graph + # Extract info from the flow graph block_key = self._flow_graph.get_option('id') parameters = self._flow_graph.get_parameters() @@ -331,7 +296,7 @@ class HierBlockGenerator(TopBlockGenerator): return "$"+name return name - # build the nested data + # Build the nested data block_n = odict() block_n['name'] = self._flow_graph.get_option('title') or \ self._flow_graph.get_option('id').replace('_', ' ').title() @@ -339,7 +304,7 @@ class HierBlockGenerator(TopBlockGenerator): block_n['category'] = self._flow_graph.get_option('category') block_n['import'] = "from {0} import {0} # grc-generated hier_block".format( self._flow_graph.get_option('id')) - # make data + # Make data if parameters: block_n['make'] = '{cls}(\n {kwargs},\n)'.format( cls=block_key, @@ -349,7 +314,7 @@ class HierBlockGenerator(TopBlockGenerator): ) else: block_n['make'] = '{cls}()'.format(cls=block_key) - # callback data + # Callback data block_n['callback'] = [ 'set_{key}(${key})'.format(key=param.get_id()) for param in parameters ] @@ -364,13 +329,13 @@ class HierBlockGenerator(TopBlockGenerator): param_n['type'] = 'raw' block_n['param'].append(param_n) - # bus stuff + # Bus stuff if self._flow_graph.get_bussink(): block_n['bus_sink'] = '1' if self._flow_graph.get_bussrc(): block_n['bus_source'] = '1' - # sink/source ports + # Sink/source ports for direction in ('sink', 'source'): block_n[direction] = list() for port in self._flow_graph.get_hier_block_io(direction): @@ -383,7 +348,7 @@ class HierBlockGenerator(TopBlockGenerator): port_n['optional'] = '1' block_n[direction].append(port_n) - # more bus stuff + # More bus stuff bus_struct_sink = self._flow_graph.get_bus_structure_sink() if bus_struct_sink: block_n['bus_structure_sink'] = bus_struct_sink[0].get_param('struct').get_value() @@ -391,11 +356,11 @@ class HierBlockGenerator(TopBlockGenerator): if bus_struct_src: block_n['bus_structure_source'] = bus_struct_src[0].get_param('struct').get_value() - # documentation + # Documentation block_n['doc'] = "\n".join(field for field in ( self._flow_graph.get_option('author'), self._flow_graph.get_option('description'), - self.get_file_path() + self.file_path ) if field) block_n['grc_source'] = str(self._flow_graph.grc_file_path) @@ -427,21 +392,3 @@ class QtHierBlockGenerator(HierBlockGenerator): "\n${gui_hint()($win)}" ) return n - - -########################################################### -# back-port from python3 -########################################################### -_find_unsafe = re.compile(r'[^\w@%+=:,./-]').search - - -def shlex_quote(s): - """Return a shell-escaped version of the string *s*.""" - if not s: - return "''" - if _find_unsafe(s) is None: - return s - - # use single quotes, and put single quotes into double quotes - # the string $'b is then quoted as '$'"'"'b' - return "'" + s.replace("'", "'\"'\"'") + "'" diff --git a/grc/core/generator/__init__.py b/grc/core/generator/__init__.py new file mode 100644 index 0000000000..f44b94a85d --- /dev/null +++ b/grc/core/generator/__init__.py @@ -0,0 +1,18 @@ +# Copyright 2008-2015 Free Software Foundation, Inc. +# This file is part of GNU Radio +# +# GNU Radio Companion is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +from Generator import Generator diff --git a/grc/python/flow_graph.tmpl b/grc/core/generator/flow_graph.tmpl index bd8025b676..ecdb89390e 100644 --- a/grc/python/flow_graph.tmpl +++ b/grc/core/generator/flow_graph.tmpl @@ -274,8 +274,8 @@ gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))]) self.settings = Qt.QSettings("GNU Radio", "$class_name") self.settings.setValue("geometry", self.saveGeometry()) event.accept() - #if $flow_graph.get_option('qt_qss_theme') + def setStyleSheetFromFile(self, filename): try: if not os.path.exists(filename): @@ -336,7 +336,12 @@ $short_id#slurp def argument_parser(): - parser = OptionParser(option_class=eng_option, usage="%prog: [options]") + #set $desc_args = 'usage="%prog: [options]", option_class=eng_option' + #if $flow_graph.get_option('description') + #set $desc_args += ', description=description' + description = $repr($flow_graph.get_option('description')) + #end if + parser = OptionParser($desc_args) #for $param in $parameters #set $type = $param.get_param('type').get_value() #if $type diff --git a/grc/core/utils/CMakeLists.txt b/grc/core/utils/CMakeLists.txt new file mode 100644 index 0000000000..2528fbc43c --- /dev/null +++ b/grc/core/utils/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright 2015 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. + +file(GLOB py_files "*.py") + +GR_PYTHON_INSTALL( + FILES ${py_files} + DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core/utils + COMPONENT "grc" +) diff --git a/grc/core/utils/__init__.py b/grc/core/utils/__init__.py new file mode 100644 index 0000000000..6b23da2723 --- /dev/null +++ b/grc/core/utils/__init__.py @@ -0,0 +1,22 @@ +# Copyright 2008-2015 Free Software Foundation, Inc. +# This file is part of GNU Radio +# +# GNU Radio Companion is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +import expr_utils +import epy_block_io +import extract_docs + +from odict import odict diff --git a/grc/core/utils/complexity.py b/grc/core/utils/complexity.py new file mode 100644 index 0000000000..baa8040db4 --- /dev/null +++ b/grc/core/utils/complexity.py @@ -0,0 +1,49 @@ + +def calculate_flowgraph_complexity(flowgraph): + """ Determines the complexity of a flowgraph """ + dbal = 0 + for block in flowgraph.blocks: + # Skip options block + if block.get_key() == 'options': + continue + + # Don't worry about optional sinks? + sink_list = filter(lambda c: not c.get_optional(), block.get_sinks()) + source_list = filter(lambda c: not c.get_optional(), block.get_sources()) + sinks = float(len(sink_list)) + sources = float(len(source_list)) + base = max(min(sinks, sources), 1) + + # Port ratio multiplier + if min(sinks, sources) > 0: + multi = sinks / sources + multi = (1 / multi) if multi > 1 else multi + else: + multi = 1 + + # Connection ratio multiplier + sink_multi = max(float(sum(map(lambda c: len(c.get_connections()), sink_list)) / max(sinks, 1.0)), 1.0) + source_multi = max(float(sum(map(lambda c: len(c.get_connections()), source_list)) / max(sources, 1.0)), 1.0) + dbal = dbal + (base * multi * sink_multi * source_multi) + + blocks = float(len(flowgraph.blocks)) + connections = float(len(flowgraph.connections)) + elements = blocks + connections + disabled_connections = len(filter(lambda c: not c.get_enabled(), flowgraph.connections)) + variables = elements - blocks - connections + enabled = float(len(flowgraph.get_enabled_blocks())) + + # Disabled multiplier + if enabled > 0: + disabled_multi = 1 / (max(1 - ((blocks - enabled) / max(blocks, 1)), 0.05)) + else: + disabled_multi = 1 + + # Connection multiplier (How many connections ) + if (connections - disabled_connections) > 0: + conn_multi = 1 / (max(1 - (disabled_connections / max(connections, 1)), 0.05)) + else: + conn_multi = 1 + + final = round(max((dbal - 1) * disabled_multi * conn_multi * connections, 0.0) / 1000000, 6) + return final diff --git a/grc/python/epy_block_io.py b/grc/core/utils/epy_block_io.py index e089908a01..df3a4bbc3e 100644 --- a/grc/python/epy_block_io.py +++ b/grc/core/utils/epy_block_io.py @@ -2,9 +2,6 @@ import inspect import collections -from gnuradio import gr -import pmt - TYPE_MAP = { 'complex64': 'complex', 'complex': 'complex', @@ -31,21 +28,27 @@ def _ports(sigs, msgs): return ports -def _blk_class(source_code): +def _find_block_class(source_code, cls): ns = {} try: exec source_code in ns except Exception as e: raise ValueError("Can't interpret source code: " + str(e)) for var in ns.itervalues(): - if inspect.isclass(var)and issubclass(var, gr.gateway.gateway_block): + if inspect.isclass(var) and issubclass(var, cls): return var raise ValueError('No python block class found in code') def extract(cls): + try: + from gnuradio import gr + import pmt + except ImportError: + raise EnvironmentError("Can't import GNU Radio") + if not inspect.isclass(cls): - cls = _blk_class(cls) + cls = _find_block_class(cls, gr.gateway.gateway_block) spec = inspect.getargspec(cls.__init__) defaults = map(repr, spec.defaults or ()) diff --git a/grc/python/expr_utils.py b/grc/core/utils/expr_utils.py index 9e0b2a4a0a..66911757d6 100644 --- a/grc/python/expr_utils.py +++ b/grc/core/utils/expr_utils.py @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import string VAR_CHARS = string.letters + string.digits + '_' + class graph(object): """ Simple graph structure held in a dictionary. @@ -30,13 +31,16 @@ class graph(object): def __str__(self): return str(self._graph) def add_node(self, node_key): - if self._graph.has_key(node_key): return + if node_key in self._graph: + return self._graph[node_key] = set() def remove_node(self, node_key): - if not self._graph.has_key(node_key): return + if node_key not in self._graph: + return for edges in self._graph.values(): - if node_key in edges: edges.remove(node_key) + if node_key in edges: + edges.remove(node_key) self._graph.pop(node_key) def add_edge(self, src_node_key, dest_node_key): @@ -45,9 +49,12 @@ class graph(object): def remove_edge(self, src_node_key, dest_node_key): self._graph[src_node_key].remove(dest_node_key) - def get_nodes(self): return self._graph.keys() + def get_nodes(self): + return self._graph.keys() + + def get_edges(self, node_key): + return self._graph[node_key] - def get_edges(self, node_key): return self._graph[node_key] def expr_split(expr): """ @@ -66,7 +73,8 @@ def expr_split(expr): quote = '' for char in expr: if quote or char in VAR_CHARS: - if char == quote: quote = '' + if char == quote: + quote = '' tok += char elif char in ("'", '"'): toks.append(tok) @@ -79,6 +87,7 @@ def expr_split(expr): toks.append(tok) return filter(lambda t: t, toks) + def expr_replace(expr, replace_dict): """ Search for vars in the expression and add the prepend. @@ -96,6 +105,7 @@ def expr_replace(expr, replace_dict): expr_splits[i] = replace_dict[es] return ''.join(expr_splits) + def get_variable_dependencies(expr, vars): """ Return a set of variables used in this expression. @@ -110,6 +120,7 @@ def get_variable_dependencies(expr, vars): expr_toks = expr_split(expr) return set(filter(lambda v: v in expr_toks, vars)) + def get_graph(exprs): """ Get a graph representing the variable dependencies @@ -121,14 +132,17 @@ def get_graph(exprs): a graph of variable deps """ vars = exprs.keys() - #get dependencies for each expression, load into graph + # Get dependencies for each expression, load into graph var_graph = graph() - for var in vars: var_graph.add_node(var) + for var in vars: + var_graph.add_node(var) for var, expr in exprs.iteritems(): for dep in get_variable_dependencies(expr, vars): - if dep != var: var_graph.add_edge(dep, var) + if dep != var: + var_graph.add_edge(dep, var) return var_graph + def sort_variables(exprs): """ Get a list of variables in order of dependencies. @@ -142,17 +156,20 @@ def sort_variables(exprs): """ var_graph = get_graph(exprs) sorted_vars = list() - #determine dependency order + # Determine dependency order while var_graph.get_nodes(): - #get a list of nodes with no edges + # Get a list of nodes with no edges indep_vars = filter(lambda var: not var_graph.get_edges(var), var_graph.get_nodes()) - if not indep_vars: raise Exception('circular dependency caught in sort_variables') - #add the indep vars to the end of the list + if not indep_vars: + raise Exception('circular dependency caught in sort_variables') + # Add the indep vars to the end of the list sorted_vars.extend(sorted(indep_vars)) - #remove each edge-less node from the graph - for var in indep_vars: var_graph.remove_node(var) + # Remove each edge-less node from the graph + for var in indep_vars: + var_graph.remove_node(var) return reversed(sorted_vars) + def sort_objects(objects, get_id, get_expr): """ Sort a list of objects according to their expressions. @@ -166,12 +183,14 @@ def sort_objects(objects, get_id, get_expr): a list of sorted objects """ id2obj = dict([(get_id(obj), obj) for obj in objects]) - #map obj id to expression code + # Map obj id to expression code id2expr = dict([(get_id(obj), get_expr(obj)) for obj in objects]) - #sort according to dependency + # Sort according to dependency sorted_ids = sort_variables(id2expr) - #return list of sorted objects + # Return list of sorted objects return [id2obj[id] for id in sorted_ids] + if __name__ == '__main__': - for i in sort_variables({'x':'1', 'y':'x+1', 'a':'x+y', 'b':'y+1', 'c':'a+b+x+y'}): print i + for i in sort_variables({'x': '1', 'y': 'x+1', 'a': 'x+y', 'b': 'y+1', 'c': 'a+b+x+y'}): + print i diff --git a/grc/python/extract_docs.py b/grc/core/utils/extract_docs.py index d8dc4f4e8f..a6e0bc971e 100644 --- a/grc/python/extract_docs.py +++ b/grc/core/utils/extract_docs.py @@ -1,5 +1,5 @@ """ -Copyright 2008-2011 Free Software Foundation, Inc. +Copyright 2008-2015 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -32,8 +32,8 @@ import itertools ############################################################################### def docstring_guess_from_key(key): - """Extract the documentation from the python __doc__ strings - + """ + Extract the documentation from the python __doc__ strings By guessing module and constructor names from key Args: @@ -65,12 +65,10 @@ def docstring_guess_from_key(key): else: return doc_strings - pattern = re.compile( - '^' + init_name.replace('_', '_*').replace('x', r'\w') + r'\w*$' - ) + pattern = re.compile('^' + init_name.replace('_', '_*').replace('x', r'\w') + r'\w*$') for match in filter(pattern.match, dir(module)): try: - doc_strings[match] = getattr(module, match).__doc__.strip() + doc_strings[match] = getattr(module, match).__doc__ except AttributeError: continue @@ -78,8 +76,8 @@ def docstring_guess_from_key(key): def docstring_from_make(key, imports, make): - """Extract the documentation from the python __doc__ strings - + """ + Extract the documentation from the python __doc__ strings By importing it and checking a truncated make Args: @@ -95,12 +93,10 @@ def docstring_from_make(key, imports, make): blk_cls = make.partition('(')[0].strip() if '$' in blk_cls: raise ValueError('Not an identifier') - ns = dict() for _import in imports: exec(_import.strip(), ns) blk = eval(blk_cls, ns) - doc_strings = {key: blk.__doc__} except (ImportError, AttributeError, SyntaxError, ValueError): @@ -114,10 +110,11 @@ def docstring_from_make(key, imports, make): ############################################################################### class SubprocessLoader(object): - """Start and manage docstring extraction process - + """ + Start and manage docstring extraction process Manages subprocess and handles RPC. """ + BOOTSTRAP = "import runpy; runpy.run_path({!r}, run_name='__worker__')" AUTH_CODE = random.random() # sort out unwanted output of worker process RESTART = 5 # number of worker restarts before giving up @@ -134,7 +131,7 @@ class SubprocessLoader(object): self._last_cmd = None def start(self): - """Start the worker process handler thread""" + """ Start the worker process handler thread """ if self._thread is not None: return self._shutdown.clear() @@ -143,7 +140,7 @@ class SubprocessLoader(object): thread.start() def run_worker(self): - """Read docstring back from worker stdout and execute callback.""" + """ Read docstring back from worker stdout and execute callback. """ for _ in range(self.RESTART): if self._shutdown.is_set(): break @@ -173,7 +170,7 @@ class SubprocessLoader(object): self.callback_finished() def _handle_worker(self): - """Send commands and responses back from worker.""" + """ Send commands and responses back from worker. """ assert '1' == self._worker.stdout.read(1) for cmd, args in iter(self._queue.get, self.DONE): self._last_cmd = cmd, args @@ -182,13 +179,13 @@ class SubprocessLoader(object): self._handle_response(cmd, args) def _send(self, cmd, args): - """send a command to worker's stdin""" + """ Send a command to worker's stdin """ fd = self._worker.stdin json.dump((self.AUTH_CODE, cmd, args), fd) fd.write('\n'.encode()) def _receive(self): - """receive response from worker's stdout""" + """ Receive response from worker's stdout """ for line in iter(self._worker.stdout.readline, ''): try: key, cmd, args = json.loads(line, encoding='utf-8') @@ -201,7 +198,7 @@ class SubprocessLoader(object): raise IOError("Can't read worker response") def _handle_response(self, cmd, args): - """Handle response from worker, call the callback""" + """ Handle response from worker, call the callback """ if cmd == 'result': key, docs = args self.callback_query_result(key, docs) @@ -211,7 +208,7 @@ class SubprocessLoader(object): print >> sys.stderr, "Unknown response:", cmd, args def query(self, key, imports=None, make=None): - """request docstring extraction for a certain key""" + """ Request docstring extraction for a certain key """ if self._thread is None: self.start() if imports and make: @@ -220,16 +217,16 @@ class SubprocessLoader(object): self._queue.put(('query_key_only', (key,))) def finish(self): - """signal end of requests""" + """ Signal end of requests """ self._queue.put(self.DONE) def wait(self): - """Wait for the handler thread to die""" + """ Wait for the handler thread to die """ if self._thread: self._thread.join() def terminate(self): - """Terminate the worker and wait""" + """ Terminate the worker and wait """ self._shutdown.set() try: self._worker.terminate() @@ -243,8 +240,8 @@ class SubprocessLoader(object): ############################################################################### def worker_main(): - """Main entry point for the docstring extraction process. - + """ + Main entry point for the docstring extraction process. Manages RPC with main process through. Runs a docstring extraction for each key it read on stdin. """ diff --git a/grc/base/odict.py b/grc/core/utils/odict.py index 70ab67d053..20970e947c 100644 --- a/grc/base/odict.py +++ b/grc/core/utils/odict.py @@ -1,5 +1,5 @@ """ -Copyright 2008-2011 Free Software Foundation, Inc. +Copyright 2008-2015 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from UserDict import DictMixin + class odict(DictMixin): def __init__(self, d={}): @@ -57,7 +58,8 @@ class odict(DictMixin): val: the value for the new entry """ index = (pos_key is None) and len(self._keys) or self._keys.index(pos_key) - if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key)) + if key in self._keys: + raise KeyError('Cannot insert, key "{}" already exists'.format(str(key))) self._keys.insert(index+1, key) self._data[key] = val @@ -72,7 +74,8 @@ class odict(DictMixin): val: the value for the new entry """ index = (pos_key is not None) and self._keys.index(pos_key) or 0 - if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key)) + if key in self._keys: + raise KeyError('Cannot insert, key "{}" already exists'.format(str(key))) self._keys.insert(index, key) self._data[key] = val @@ -86,7 +89,8 @@ class odict(DictMixin): Returns: the value or None """ - if self.has_key(key): return self[key] + if key in self: + return self[key] return None def findall(self, key): @@ -100,6 +104,8 @@ class odict(DictMixin): a list of values or empty list """ obj = self.find(key) - if obj is None: obj = list() - if isinstance(obj, list): return obj + if obj is None: + obj = list() + if isinstance(obj, list): + return obj return [obj] diff --git a/grc/cpp/README b/grc/cpp/README deleted file mode 100644 index 3eccc5dbf7..0000000000 --- a/grc/cpp/README +++ /dev/null @@ -1,5 +0,0 @@ -GRC could be used to generate c++ based flowgraphs: - -* A few base and gui classes would be overridden. -* Block info could be extracted from the doxygen xml. -* New flowgraph templates would be designed. diff --git a/grc/examples/simple/variable_config.grc b/grc/examples/simple/variable_config.grc deleted file mode 100644 index 0b60abc813..0000000000 --- a/grc/examples/simple/variable_config.grc +++ /dev/null @@ -1,561 +0,0 @@ -<?xml version='1.0' encoding='ASCII'?> -<flow_graph> - <timestamp>Sat Jul 12 16:15:51 2014</timestamp> - <block> - <key>options</key> - <param> - <key>id</key> - <value>variable_config_demo</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>title</key> - <value>Variable Config Block Demonstration</value> - </param> - <param> - <key>author</key> - <value>Example</value> - </param> - <param> - <key>description</key> - <value>Save/Load freq from a config file.</value> - </param> - <param> - <key>window_size</key> - <value>1280, 1024</value> - </param> - <param> - <key>generate_options</key> - <value>qt_gui</value> - </param> - <param> - <key>category</key> - <value>Custom</value> - </param> - <param> - <key>run_options</key> - <value>prompt</value> - </param> - <param> - <key>run</key> - <value>True</value> - </param> - <param> - <key>max_nouts</key> - <value>0</value> - </param> - <param> - <key>realtime_scheduling</key> - <value></value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(-1, 2)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable</key> - <param> - <key>id</key> - <value>samp_rate</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>value</key> - <value>32000</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(-1, 125)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>analog_sig_source_x</key> - <param> - <key>id</key> - <value>analog_sig_source_x_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>complex</value> - </param> - <param> - <key>samp_rate</key> - <value>samp_rate</value> - </param> - <param> - <key>waveform</key> - <value>analog.GR_COS_WAVE</value> - </param> - <param> - <key>freq</key> - <value>freq</value> - </param> - <param> - <key>amp</key> - <value>1</value> - </param> - <param> - <key>offset</key> - <value>0</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>affinity</key> - <value></value> - </param> - <param> - <key>minoutbuf</key> - <value>0</value> - </param> - <param> - <key>maxoutbuf</key> - <value>0</value> - </param> - <param> - <key>_coordinate</key> - <value>(173, 201)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>blocks_throttle</key> - <param> - <key>id</key> - <value>blocks_throttle_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>complex</value> - </param> - <param> - <key>samples_per_second</key> - <value>samp_rate</value> - </param> - <param> - <key>vlen</key> - <value>1</value> - </param> - <param> - <key>ignoretag</key> - <value>True</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>affinity</key> - <value></value> - </param> - <param> - <key>minoutbuf</key> - <value>0</value> - </param> - <param> - <key>maxoutbuf</key> - <value>0</value> - </param> - <param> - <key>_coordinate</key> - <value>(392, 233)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>qtgui_freq_sink_x</key> - <param> - <key>id</key> - <value>qtgui_freq_sink_x_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>complex</value> - </param> - <param> - <key>name</key> - <value>QT GUI Plot</value> - </param> - <param> - <key>fftsize</key> - <value>1024</value> - </param> - <param> - <key>wintype</key> - <value>firdes.WIN_BLACKMAN_hARRIS</value> - </param> - <param> - <key>fc</key> - <value>0</value> - </param> - <param> - <key>bw</key> - <value>samp_rate</value> - </param> - <param> - <key>autoscale</key> - <value>False</value> - </param> - <param> - <key>average</key> - <value>1.0</value> - </param> - <param> - <key>ymin</key> - <value>-140</value> - </param> - <param> - <key>ymax</key> - <value>10</value> - </param> - <param> - <key>nconnections</key> - <value>1</value> - </param> - <param> - <key>update_time</key> - <value>0.10</value> - </param> - <param> - <key>gui_hint</key> - <value></value> - </param> - <param> - <key>label1</key> - <value></value> - </param> - <param> - <key>width1</key> - <value>1</value> - </param> - <param> - <key>color1</key> - <value>"blue"</value> - </param> - <param> - <key>alpha1</key> - <value>1.0</value> - </param> - <param> - <key>label2</key> - <value></value> - </param> - <param> - <key>width2</key> - <value>1</value> - </param> - <param> - <key>color2</key> - <value>"red"</value> - </param> - <param> - <key>alpha2</key> - <value>1.0</value> - </param> - <param> - <key>label3</key> - <value></value> - </param> - <param> - <key>width3</key> - <value>1</value> - </param> - <param> - <key>color3</key> - <value>"green"</value> - </param> - <param> - <key>alpha3</key> - <value>1.0</value> - </param> - <param> - <key>label4</key> - <value></value> - </param> - <param> - <key>width4</key> - <value>1</value> - </param> - <param> - <key>color4</key> - <value>"black"</value> - </param> - <param> - <key>alpha4</key> - <value>1.0</value> - </param> - <param> - <key>label5</key> - <value></value> - </param> - <param> - <key>width5</key> - <value>1</value> - </param> - <param> - <key>color5</key> - <value>"cyan"</value> - </param> - <param> - <key>alpha5</key> - <value>1.0</value> - </param> - <param> - <key>label6</key> - <value></value> - </param> - <param> - <key>width6</key> - <value>1</value> - </param> - <param> - <key>color6</key> - <value>"magenta"</value> - </param> - <param> - <key>alpha6</key> - <value>1.0</value> - </param> - <param> - <key>label7</key> - <value></value> - </param> - <param> - <key>width7</key> - <value>1</value> - </param> - <param> - <key>color7</key> - <value>"yellow"</value> - </param> - <param> - <key>alpha7</key> - <value>1.0</value> - </param> - <param> - <key>label8</key> - <value></value> - </param> - <param> - <key>width8</key> - <value>1</value> - </param> - <param> - <key>color8</key> - <value>"dark red"</value> - </param> - <param> - <key>alpha8</key> - <value>1.0</value> - </param> - <param> - <key>label9</key> - <value></value> - </param> - <param> - <key>width9</key> - <value>1</value> - </param> - <param> - <key>color9</key> - <value>"dark green"</value> - </param> - <param> - <key>alpha9</key> - <value>1.0</value> - </param> - <param> - <key>label10</key> - <value></value> - </param> - <param> - <key>width10</key> - <value>1</value> - </param> - <param> - <key>color10</key> - <value>"dark blue"</value> - </param> - <param> - <key>alpha10</key> - <value>1.0</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>affinity</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(643, 221)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable_qtgui_range</key> - <param> - <key>id</key> - <value>freq</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>label</key> - <value>Frequency (Hz)</value> - </param> - <param> - <key>value</key> - <value>1e3</value> - </param> - <param> - <key>start</key> - <value>-samp_rate/2</value> - </param> - <param> - <key>stop</key> - <value>samp_rate/2</value> - </param> - <param> - <key>step</key> - <value>1</value> - </param> - <param> - <key>widget</key> - <value>counter_slider</value> - </param> - <param> - <key>orient</key> - <value>Qt.Horizontal</value> - </param> - <param> - <key>min_len</key> - <value>200</value> - </param> - <param> - <key>gui_hint</key> - <value></value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(339, 9)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable_config</key> - <param> - <key>id</key> - <value>freq_init</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>value</key> - <value>1000</value> - </param> - <param> - <key>type</key> - <value>real</value> - </param> - <param> - <key>config_file</key> - <value>/home/mbant/.gnuradio/config.conf</value> - </param> - <param> - <key>section</key> - <value>main</value> - </param> - <param> - <key>option</key> - <value>freq</value> - </param> - <param> - <key>writeback</key> - <value>freq</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(168, 0)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <connection> - <source_block_id>analog_sig_source_x_0</source_block_id> - <sink_block_id>blocks_throttle_0</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> - </connection> - <connection> - <source_block_id>blocks_throttle_0</source_block_id> - <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> - </connection> -</flow_graph> diff --git a/grc/examples/xmlrpc/readme.txt b/grc/examples/xmlrpc/readme.txt deleted file mode 100644 index 056ad1e823..0000000000 --- a/grc/examples/xmlrpc/readme.txt +++ /dev/null @@ -1,18 +0,0 @@ -################################################## -# XMLRPC example -################################################## - -XMLRPC allows software to make remote function calls over http. -In the case of GRC, one can use XMLRPC to modify variables in a running flow graph. -See http://www.xmlrpc.com/ - ---- Server Example --- -Place an "XMLRPC Server" block inside of any flow graph. -The server will provide set functions for every variable in the flow graph. -If a variable is called "freq", the server will provide a function set_freq(new_freq). -Run the server example and experiment with the example client script. - --- Client Example -- -The "XMLRPC Client" block will give a variable control over one remove function. -In the example client, there is one client block and gui control per variable. -This technique can be used to remotely control a flow graph, perhaps running on a non-gui machine. diff --git a/grc/examples/xmlrpc/xmlrpc_client.grc b/grc/examples/xmlrpc/xmlrpc_client.grc deleted file mode 100644 index 45d8af2824..0000000000 --- a/grc/examples/xmlrpc/xmlrpc_client.grc +++ /dev/null @@ -1,428 +0,0 @@ -<?xml version='1.0' encoding='ASCII'?> -<flow_graph> - <timestamp>Sat Jul 12 17:10:55 2014</timestamp> - <block> - <key>options</key> - <param> - <key>id</key> - <value>client_block</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>title</key> - <value>XMLRPC Client</value> - </param> - <param> - <key>author</key> - <value>Example</value> - </param> - <param> - <key>description</key> - <value>example flow graph</value> - </param> - <param> - <key>window_size</key> - <value>1280, 1024</value> - </param> - <param> - <key>generate_options</key> - <value>qt_gui</value> - </param> - <param> - <key>category</key> - <value>Custom</value> - </param> - <param> - <key>run_options</key> - <value>prompt</value> - </param> - <param> - <key>run</key> - <value>True</value> - </param> - <param> - <key>max_nouts</key> - <value>0</value> - </param> - <param> - <key>realtime_scheduling</key> - <value></value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(-2, 0)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable</key> - <param> - <key>id</key> - <value>samp_rate</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>value</key> - <value>32000</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(13, 172)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>xmlrpc_client</key> - <param> - <key>id</key> - <value>xmlrpc_client</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>addr</key> - <value>localhost</value> - </param> - <param> - <key>port</key> - <value>1234</value> - </param> - <param> - <key>callback</key> - <value>set_freq</value> - </param> - <param> - <key>variable</key> - <value>freq</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(177, 0)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>xmlrpc_client</key> - <param> - <key>id</key> - <value>xmlrpc_client0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>addr</key> - <value>localhost</value> - </param> - <param> - <key>port</key> - <value>1234</value> - </param> - <param> - <key>callback</key> - <value>set_ampl</value> - </param> - <param> - <key>variable</key> - <value>ampl</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(308, 0)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>xmlrpc_client</key> - <param> - <key>id</key> - <value>xmlrpc_client1</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>addr</key> - <value>localhost</value> - </param> - <param> - <key>port</key> - <value>1234</value> - </param> - <param> - <key>callback</key> - <value>set_offset</value> - </param> - <param> - <key>variable</key> - <value>offset*ampl</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(440, 4)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable_qtgui_range</key> - <param> - <key>id</key> - <value>freq</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>label</key> - <value>Frequency (Hz)</value> - </param> - <param> - <key>value</key> - <value>1000</value> - </param> - <param> - <key>start</key> - <value>0</value> - </param> - <param> - <key>stop</key> - <value>5e3</value> - </param> - <param> - <key>step</key> - <value>1</value> - </param> - <param> - <key>widget</key> - <value>counter_slider</value> - </param> - <param> - <key>orient</key> - <value>Qt.Horizontal</value> - </param> - <param> - <key>min_len</key> - <value>200</value> - </param> - <param> - <key>gui_hint</key> - <value>0,0,1,2</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(209, 165)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable_qtgui_range</key> - <param> - <key>id</key> - <value>ampl</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>label</key> - <value>Amplitude</value> - </param> - <param> - <key>value</key> - <value>1</value> - </param> - <param> - <key>start</key> - <value>0</value> - </param> - <param> - <key>stop</key> - <value>2</value> - </param> - <param> - <key>step</key> - <value>.1</value> - </param> - <param> - <key>widget</key> - <value>counter_slider</value> - </param> - <param> - <key>orient</key> - <value>Qt.Horizontal</value> - </param> - <param> - <key>min_len</key> - <value>200</value> - </param> - <param> - <key>gui_hint</key> - <value>1,0,1,2</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(367, 158)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable_qtgui_chooser</key> - <param> - <key>id</key> - <value>offset</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>label</key> - <value>Offset</value> - </param> - <param> - <key>type</key> - <value>int</value> - </param> - <param> - <key>num_opts</key> - <value>3</value> - </param> - <param> - <key>value</key> - <value>0</value> - </param> - <param> - <key>options</key> - <value>[0, 1, 2]</value> - </param> - <param> - <key>labels</key> - <value>[]</value> - </param> - <param> - <key>option0</key> - <value>-1</value> - </param> - <param> - <key>label0</key> - <value>neg</value> - </param> - <param> - <key>option1</key> - <value>0</value> - </param> - <param> - <key>label1</key> - <value>zero</value> - </param> - <param> - <key>option2</key> - <value>1</value> - </param> - <param> - <key>label2</key> - <value>pos</value> - </param> - <param> - <key>option3</key> - <value>3</value> - </param> - <param> - <key>label3</key> - <value></value> - </param> - <param> - <key>option4</key> - <value>4</value> - </param> - <param> - <key>label4</key> - <value></value> - </param> - <param> - <key>widget</key> - <value>combo_box</value> - </param> - <param> - <key>orient</key> - <value>Qt.QVBoxLayout</value> - </param> - <param> - <key>gui_hint</key> - <value>2,0,1,2</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(531, 145)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> -</flow_graph> diff --git a/grc/examples/xmlrpc/xmlrpc_client_script.py b/grc/examples/xmlrpc/xmlrpc_client_script.py deleted file mode 100644 index e96c4cbf83..0000000000 --- a/grc/examples/xmlrpc/xmlrpc_client_script.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python - -import time -import random -import xmlrpclib - -#create server object -s = xmlrpclib.Server("http://localhost:1234") - -#randomly change parameters of the sinusoid -for i in range(10): - #generate random values - new_freq = random.uniform(0, 5000) - new_ampl = random.uniform(0, 2) - new_offset = random.uniform(-1, 1) - #set new values - time.sleep(1) - s.set_freq(new_freq) - time.sleep(1) - s.set_ampl(new_ampl) - time.sleep(1) - s.set_offset(new_offset) - diff --git a/grc/examples/xmlrpc/xmlrpc_server.grc b/grc/examples/xmlrpc/xmlrpc_server.grc deleted file mode 100644 index d210b2694e..0000000000 --- a/grc/examples/xmlrpc/xmlrpc_server.grc +++ /dev/null @@ -1,908 +0,0 @@ -<?xml version='1.0' encoding='ASCII'?> -<flow_graph> - <timestamp>Sat Jul 12 17:11:40 2014</timestamp> - <block> - <key>options</key> - <param> - <key>id</key> - <value>server_block</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>title</key> - <value>XMLRPC Server</value> - </param> - <param> - <key>author</key> - <value>Example</value> - </param> - <param> - <key>description</key> - <value>example flow graph</value> - </param> - <param> - <key>window_size</key> - <value>1280, 1024</value> - </param> - <param> - <key>generate_options</key> - <value>qt_gui</value> - </param> - <param> - <key>category</key> - <value>Custom</value> - </param> - <param> - <key>run_options</key> - <value>prompt</value> - </param> - <param> - <key>run</key> - <value>True</value> - </param> - <param> - <key>max_nouts</key> - <value>0</value> - </param> - <param> - <key>realtime_scheduling</key> - <value></value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(0, -1)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable</key> - <param> - <key>id</key> - <value>ampl</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>value</key> - <value>1</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(4, 291)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable</key> - <param> - <key>id</key> - <value>freq</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>value</key> - <value>1000</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(2, 213)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable</key> - <param> - <key>id</key> - <value>samp_rate</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>value</key> - <value>32000</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(2, 136)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable</key> - <param> - <key>id</key> - <value>offset</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>value</key> - <value>0</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(3, 366)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>analog_sig_source_x</key> - <param> - <key>id</key> - <value>analog_sig_source_x_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>float</value> - </param> - <param> - <key>samp_rate</key> - <value>samp_rate</value> - </param> - <param> - <key>waveform</key> - <value>analog.GR_COS_WAVE</value> - </param> - <param> - <key>freq</key> - <value>freq</value> - </param> - <param> - <key>amp</key> - <value>ampl</value> - </param> - <param> - <key>offset</key> - <value>offset</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>affinity</key> - <value></value> - </param> - <param> - <key>minoutbuf</key> - <value>0</value> - </param> - <param> - <key>maxoutbuf</key> - <value>0</value> - </param> - <param> - <key>_coordinate</key> - <value>(175, 0)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>blocks_throttle</key> - <param> - <key>id</key> - <value>blocks_throttle</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>float</value> - </param> - <param> - <key>samples_per_second</key> - <value>samp_rate</value> - </param> - <param> - <key>vlen</key> - <value>1</value> - </param> - <param> - <key>ignoretag</key> - <value>True</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>affinity</key> - <value></value> - </param> - <param> - <key>minoutbuf</key> - <value>0</value> - </param> - <param> - <key>maxoutbuf</key> - <value>0</value> - </param> - <param> - <key>_coordinate</key> - <value>(399, 35)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>xmlrpc_server</key> - <param> - <key>id</key> - <value>xmlrpc_server</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>addr</key> - <value>localhost</value> - </param> - <param> - <key>port</key> - <value>1234</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(129, 137)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>qtgui_time_sink_x</key> - <param> - <key>id</key> - <value>qtgui_time_sink_x_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>float</value> - </param> - <param> - <key>name</key> - <value>Scope Plot</value> - </param> - <param> - <key>size</key> - <value>1024</value> - </param> - <param> - <key>srate</key> - <value>samp_rate</value> - </param> - <param> - <key>autoscale</key> - <value>False</value> - </param> - <param> - <key>ymin</key> - <value>-1</value> - </param> - <param> - <key>ymax</key> - <value>1</value> - </param> - <param> - <key>nconnections</key> - <value>1</value> - </param> - <param> - <key>update_time</key> - <value>0.10</value> - </param> - <param> - <key>entags</key> - <value>True</value> - </param> - <param> - <key>gui_hint</key> - <value>0, 0, 2, 4</value> - </param> - <param> - <key>tr_mode</key> - <value>qtgui.TRIG_MODE_FREE</value> - </param> - <param> - <key>tr_slope</key> - <value>qtgui.TRIG_SLOPE_POS</value> - </param> - <param> - <key>tr_level</key> - <value>0.0</value> - </param> - <param> - <key>tr_delay</key> - <value>0</value> - </param> - <param> - <key>tr_chan</key> - <value>0</value> - </param> - <param> - <key>tr_tag</key> - <value>""</value> - </param> - <param> - <key>label1</key> - <value></value> - </param> - <param> - <key>width1</key> - <value>1</value> - </param> - <param> - <key>color1</key> - <value>"blue"</value> - </param> - <param> - <key>style1</key> - <value>1</value> - </param> - <param> - <key>marker1</key> - <value>-1</value> - </param> - <param> - <key>alpha1</key> - <value>1.0</value> - </param> - <param> - <key>label2</key> - <value></value> - </param> - <param> - <key>width2</key> - <value>1</value> - </param> - <param> - <key>color2</key> - <value>"red"</value> - </param> - <param> - <key>style2</key> - <value>1</value> - </param> - <param> - <key>marker2</key> - <value>-1</value> - </param> - <param> - <key>alpha2</key> - <value>1.0</value> - </param> - <param> - <key>label3</key> - <value></value> - </param> - <param> - <key>width3</key> - <value>1</value> - </param> - <param> - <key>color3</key> - <value>"green"</value> - </param> - <param> - <key>style3</key> - <value>1</value> - </param> - <param> - <key>marker3</key> - <value>-1</value> - </param> - <param> - <key>alpha3</key> - <value>1.0</value> - </param> - <param> - <key>label4</key> - <value></value> - </param> - <param> - <key>width4</key> - <value>1</value> - </param> - <param> - <key>color4</key> - <value>"black"</value> - </param> - <param> - <key>style4</key> - <value>1</value> - </param> - <param> - <key>marker4</key> - <value>-1</value> - </param> - <param> - <key>alpha4</key> - <value>1.0</value> - </param> - <param> - <key>label5</key> - <value></value> - </param> - <param> - <key>width5</key> - <value>1</value> - </param> - <param> - <key>color5</key> - <value>"cyan"</value> - </param> - <param> - <key>style5</key> - <value>1</value> - </param> - <param> - <key>marker5</key> - <value>-1</value> - </param> - <param> - <key>alpha5</key> - <value>1.0</value> - </param> - <param> - <key>label6</key> - <value></value> - </param> - <param> - <key>width6</key> - <value>1</value> - </param> - <param> - <key>color6</key> - <value>"magenta"</value> - </param> - <param> - <key>style6</key> - <value>1</value> - </param> - <param> - <key>marker6</key> - <value>-1</value> - </param> - <param> - <key>alpha6</key> - <value>1.0</value> - </param> - <param> - <key>label7</key> - <value></value> - </param> - <param> - <key>width7</key> - <value>1</value> - </param> - <param> - <key>color7</key> - <value>"yellow"</value> - </param> - <param> - <key>style7</key> - <value>1</value> - </param> - <param> - <key>marker7</key> - <value>-1</value> - </param> - <param> - <key>alpha7</key> - <value>1.0</value> - </param> - <param> - <key>label8</key> - <value></value> - </param> - <param> - <key>width8</key> - <value>1</value> - </param> - <param> - <key>color8</key> - <value>"dark red"</value> - </param> - <param> - <key>style8</key> - <value>1</value> - </param> - <param> - <key>marker8</key> - <value>-1</value> - </param> - <param> - <key>alpha8</key> - <value>1.0</value> - </param> - <param> - <key>label9</key> - <value></value> - </param> - <param> - <key>width9</key> - <value>1</value> - </param> - <param> - <key>color9</key> - <value>"dark green"</value> - </param> - <param> - <key>style9</key> - <value>1</value> - </param> - <param> - <key>marker9</key> - <value>-1</value> - </param> - <param> - <key>alpha9</key> - <value>1.0</value> - </param> - <param> - <key>label10</key> - <value></value> - </param> - <param> - <key>width10</key> - <value>1</value> - </param> - <param> - <key>color10</key> - <value>"blue"</value> - </param> - <param> - <key>style10</key> - <value>1</value> - </param> - <param> - <key>marker10</key> - <value>-1</value> - </param> - <param> - <key>alpha10</key> - <value>1.0</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>affinity</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(644, 13)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>qtgui_freq_sink_x</key> - <param> - <key>id</key> - <value>qtgui_freq_sink_x_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>float</value> - </param> - <param> - <key>name</key> - <value>Spectrum Plot</value> - </param> - <param> - <key>fftsize</key> - <value>1024</value> - </param> - <param> - <key>wintype</key> - <value>firdes.WIN_BLACKMAN_hARRIS</value> - </param> - <param> - <key>fc</key> - <value>0</value> - </param> - <param> - <key>bw</key> - <value>samp_rate</value> - </param> - <param> - <key>autoscale</key> - <value>False</value> - </param> - <param> - <key>average</key> - <value>1.0</value> - </param> - <param> - <key>ymin</key> - <value>-140</value> - </param> - <param> - <key>ymax</key> - <value>10</value> - </param> - <param> - <key>nconnections</key> - <value>1</value> - </param> - <param> - <key>update_time</key> - <value>0.10</value> - </param> - <param> - <key>gui_hint</key> - <value>2, 0, 2, 4</value> - </param> - <param> - <key>label1</key> - <value></value> - </param> - <param> - <key>width1</key> - <value>1</value> - </param> - <param> - <key>color1</key> - <value>"blue"</value> - </param> - <param> - <key>alpha1</key> - <value>1.0</value> - </param> - <param> - <key>label2</key> - <value></value> - </param> - <param> - <key>width2</key> - <value>1</value> - </param> - <param> - <key>color2</key> - <value>"red"</value> - </param> - <param> - <key>alpha2</key> - <value>1.0</value> - </param> - <param> - <key>label3</key> - <value></value> - </param> - <param> - <key>width3</key> - <value>1</value> - </param> - <param> - <key>color3</key> - <value>"green"</value> - </param> - <param> - <key>alpha3</key> - <value>1.0</value> - </param> - <param> - <key>label4</key> - <value></value> - </param> - <param> - <key>width4</key> - <value>1</value> - </param> - <param> - <key>color4</key> - <value>"black"</value> - </param> - <param> - <key>alpha4</key> - <value>1.0</value> - </param> - <param> - <key>label5</key> - <value></value> - </param> - <param> - <key>width5</key> - <value>1</value> - </param> - <param> - <key>color5</key> - <value>"cyan"</value> - </param> - <param> - <key>alpha5</key> - <value>1.0</value> - </param> - <param> - <key>label6</key> - <value></value> - </param> - <param> - <key>width6</key> - <value>1</value> - </param> - <param> - <key>color6</key> - <value>"magenta"</value> - </param> - <param> - <key>alpha6</key> - <value>1.0</value> - </param> - <param> - <key>label7</key> - <value></value> - </param> - <param> - <key>width7</key> - <value>1</value> - </param> - <param> - <key>color7</key> - <value>"yellow"</value> - </param> - <param> - <key>alpha7</key> - <value>1.0</value> - </param> - <param> - <key>label8</key> - <value></value> - </param> - <param> - <key>width8</key> - <value>1</value> - </param> - <param> - <key>color8</key> - <value>"dark red"</value> - </param> - <param> - <key>alpha8</key> - <value>1.0</value> - </param> - <param> - <key>label9</key> - <value></value> - </param> - <param> - <key>width9</key> - <value>1</value> - </param> - <param> - <key>color9</key> - <value>"dark green"</value> - </param> - <param> - <key>alpha9</key> - <value>1.0</value> - </param> - <param> - <key>label10</key> - <value></value> - </param> - <param> - <key>width10</key> - <value>1</value> - </param> - <param> - <key>color10</key> - <value>"dark blue"</value> - </param> - <param> - <key>alpha10</key> - <value>1.0</value> - </param> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>affinity</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(644, 126)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <connection> - <source_block_id>analog_sig_source_x_0</source_block_id> - <sink_block_id>blocks_throttle</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> - </connection> - <connection> - <source_block_id>blocks_throttle</source_block_id> - <sink_block_id>qtgui_time_sink_x_0</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> - </connection> - <connection> - <source_block_id>blocks_throttle</source_block_id> - <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> - </connection> -</flow_graph> diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 7766a0a853..077786d4b4 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -17,26 +17,21 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -import os -import subprocess -from threading import Thread -import pygtk -pygtk.require('2.0') -import gtk import gobject +import gtk +import os +import subprocess -from .. base import ParseXML, Constants -from .. python.Constants import XTERM_EXECUTABLE - -from . import Dialogs, Messages, Preferences, Actions -from .ParserErrorsDialog import ParserErrorsDialog -from .MainWindow import MainWindow -from .PropsDialog import PropsDialog +from . import Dialogs, Preferences, Actions, Executor, Constants from .FileDialogs import (OpenFlowGraphFileDialog, SaveFlowGraphFileDialog, - SaveReportsFileDialog, SaveImageFileDialog, + SaveReportsFileDialog, SaveScreenShotDialog, OpenQSSFileDialog) -from .Constants import DEFAULT_CANVAS_SIZE, IMAGE_FILE_EXTENSION, GR_PREFIX +from .MainWindow import MainWindow +from .ParserErrorsDialog import ParserErrorsDialog +from .PropsDialog import PropsDialog + +from ..core import ParseXML, Messages gobject.threads_init() @@ -74,8 +69,6 @@ class ActionHandler: #initialize self.init_file_paths = file_paths Actions.APPLICATION_INITIALIZE() - #enter the mainloop - gtk.main() def _handle_key_press(self, widget, event): """ @@ -143,6 +136,7 @@ class ActionHandler: Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB, Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY, Actions.FLOW_GRAPH_OPEN_QSS_THEME, + Actions.SELECT_ALL, ): action.set_sensitive(True) if hasattr(action, 'load_from_preferences'): @@ -162,6 +156,8 @@ class ActionHandler: pass #do nothing, update routines below elif action == Actions.NOTHING_SELECT: self.get_flow_graph().unselect() + elif action == Actions.SELECT_ALL: + self.get_flow_graph().select_all() ################################################## # Enable/Disable ################################################## @@ -230,7 +226,7 @@ class ActionHandler: if y < y_min: y_min = y - for connection in block.get_connections(): + for connection in block.connections: # Get id of connected blocks source_id = connection.get_source().get_parent().get_id() @@ -373,7 +369,8 @@ class ActionHandler: # Window stuff ################################################## elif action == Actions.ABOUT_WINDOW_DISPLAY: - Dialogs.AboutDialog(self.get_flow_graph().get_parent()) + platform = self.get_flow_graph().get_parent() + Dialogs.AboutDialog(platform.config) elif action == Actions.HELP_WINDOW_DISPLAY: Dialogs.HelpDialog() elif action == Actions.TYPES_WINDOW_DISPLAY: @@ -489,12 +486,13 @@ class ActionHandler: self.main_window.menu_bar.refresh_submenus() elif action == Actions.FLOW_GRAPH_OPEN_QSS_THEME: - file_paths = OpenQSSFileDialog(GR_PREFIX + '/share/gnuradio/themes/').run() + file_paths = OpenQSSFileDialog(self.platform.config.install_prefix + + '/share/gnuradio/themes/').run() if file_paths: try: - from gnuradio import gr - gr.prefs().set_string("qtgui", "qss", file_paths[0]) - gr.prefs().save() + prefs = self.platform.config.prefs + prefs.set_string("qtgui", "qss", file_paths[0]) + prefs.save() except Exception as e: Messages.send("Failed to save QSS preference: " + str(e)) elif action == Actions.FLOW_GRAPH_CLOSE: @@ -521,10 +519,10 @@ class ActionHandler: self.main_window.tool_bar.refresh_submenus() self.main_window.menu_bar.refresh_submenus() elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE: - file_path = SaveImageFileDialog(self.get_page().get_file_path()).run() + file_path, background_transparent = SaveScreenShotDialog(self.get_page().get_file_path()).run() if file_path is not None: - pixbuf = self.get_flow_graph().get_drawing_area().get_pixbuf() - pixbuf.save(file_path, IMAGE_FILE_EXTENSION[1:]) + pixbuf = self.get_flow_graph().get_drawing_area().get_screenshot(background_transparent) + pixbuf.save(file_path, Constants.IMAGE_FILE_EXTENSION[1:]) ################################################## # Gen/Exec/Stop ################################################## @@ -542,12 +540,13 @@ class ActionHandler: elif action == Actions.FLOW_GRAPH_EXEC: if not self.get_page().get_proc(): Actions.FLOW_GRAPH_GEN() - if Preferences.xterm_missing() != XTERM_EXECUTABLE: - if not os.path.exists(XTERM_EXECUTABLE): - Dialogs.MissingXTermDialog(XTERM_EXECUTABLE) - Preferences.xterm_missing(XTERM_EXECUTABLE) + xterm = self.platform.config.xterm_executable + if Preferences.xterm_missing() != xterm: + if not os.path.exists(xterm): + Dialogs.MissingXTermDialog(xterm) + Preferences.xterm_missing(xterm) if self.get_page().get_saved() and self.get_page().get_file_path(): - ExecFlowGraphThread(self) + Executor.ExecFlowGraphThread(self) elif action == Actions.FLOW_GRAPH_KILL: if self.get_page().get_proc(): try: @@ -560,7 +559,8 @@ class ActionHandler: self.platform.load_blocks() self.main_window.btwin.clear() self.platform.load_block_tree(self.main_window.btwin) - Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(bool(ParseXML.xml_failures)) + Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(bool( + ParseXML.xml_failures)) Messages.send_xml_errors_if_any(ParseXML.xml_failures) # Force a redraw of the graph, by getting the current state and re-importing it self.main_window.update_pages() @@ -635,7 +635,7 @@ class ActionHandler: self.main_window.update() try: #set the size of the flow graph area (if changed) new_size = (self.get_flow_graph().get_option('window_size') or - DEFAULT_CANVAS_SIZE) + self.platform.config.default_canvas_size) if self.get_flow_graph().get_size() != tuple(new_size): self.get_flow_graph().set_size(*new_size) except: pass @@ -653,48 +653,3 @@ class ActionHandler: Actions.FLOW_GRAPH_GEN.set_sensitive(sensitive) Actions.FLOW_GRAPH_EXEC.set_sensitive(sensitive) Actions.FLOW_GRAPH_KILL.set_sensitive(self.get_page().get_proc() is not None) - -class ExecFlowGraphThread(Thread): - """Execute the flow graph as a new process and wait on it to finish.""" - - def __init__ (self, action_handler): - """ - ExecFlowGraphThread constructor. - - Args: - action_handler: an instance of an ActionHandler - """ - Thread.__init__(self) - self.update_exec_stop = action_handler.update_exec_stop - self.flow_graph = action_handler.get_flow_graph() - #store page and dont use main window calls in run - self.page = action_handler.get_page() - #get the popen - try: - self.p = self.page.get_generator().get_popen() - self.page.set_proc(self.p) - #update - self.update_exec_stop() - self.start() - except Exception, e: - Messages.send_verbose_exec(str(e)) - Messages.send_end_exec() - - def run(self): - """ - Wait on the executing process by reading from its stdout. - Use gobject.idle_add when calling functions that modify gtk objects. - """ - #handle completion - r = "\n" - while r: - gobject.idle_add(Messages.send_verbose_exec, r) - r = os.read(self.p.stdout.fileno(), 1024) - self.p.poll() - gobject.idle_add(self.done) - - def done(self): - """Perform end of execution tasks.""" - Messages.send_end_exec(self.p.returncode) - self.page.set_proc(None) - self.update_exec_stop() diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index 9b32b3e601..354e536a82 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -226,6 +226,12 @@ FLOW_GRAPH_REDO = Action( keypresses=(gtk.keysyms.y, gtk.gdk.CONTROL_MASK), ) NOTHING_SELECT = Action() +SELECT_ALL = Action( + label='Select _All', + tooltip='Select all blocks and connections in the flow graph', + stock_id=gtk.STOCK_SELECT_ALL, + keypresses=(gtk.keysyms.a, gtk.gdk.CONTROL_MASK), +) ELEMENT_SELECT = Action() ELEMENT_CREATE = Action() ELEMENT_DELETE = Action( @@ -386,7 +392,7 @@ FLOW_GRAPH_KILL = Action( keypresses=(gtk.keysyms.F7, NO_MODS_MASK), ) FLOW_GRAPH_SCREEN_CAPTURE = Action( - label='Sc_reen Capture', + label='Screen Ca_pture', tooltip='Create a screen capture of the flow graph', stock_id=gtk.STOCK_PRINT, keypresses=(gtk.keysyms.Print, NO_MODS_MASK), diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index 19f041f508..259aa6ed8b 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -82,6 +82,7 @@ MENU_BAR_LIST = ( Actions.BLOCK_COPY, Actions.BLOCK_PASTE, Actions.ELEMENT_DELETE, + Actions.SELECT_ALL, None, Actions.BLOCK_ROTATE_CCW, Actions.BLOCK_ROTATE_CW, diff --git a/grc/gui/Block.py b/grc/gui/Block.py index 67b80695fa..95135310b8 100644 --- a/grc/gui/Block.py +++ b/grc/gui/Block.py @@ -17,22 +17,24 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from Element import Element -import Utils -import Colors -from .. base import odict -from .. python.Param import num_to_str -from Constants import BORDER_PROXIMITY_SENSITIVITY -from Constants import ( - BLOCK_LABEL_PADDING, PORT_SPACING, PORT_SEPARATION, LABEL_SEPARATION, - PORT_BORDER_SEPARATION, POSSIBLE_ROTATIONS, BLOCK_FONT, PARAM_FONT -) -import Actions import pygtk pygtk.require('2.0') import gtk import pango +from . import Actions, Colors, Utils + +from .Constants import ( + BLOCK_LABEL_PADDING, PORT_SPACING, PORT_SEPARATION, LABEL_SEPARATION, + PORT_BORDER_SEPARATION, POSSIBLE_ROTATIONS, BLOCK_FONT, PARAM_FONT, + BORDER_PROXIMITY_SENSITIVITY +) +from . Element import Element +from ..core.Param import num_to_str +from ..core.utils import odict +from ..core.utils.complexity import calculate_flowgraph_complexity +from ..core.Block import Block as _Block + BLOCK_MARKUP_TMPL="""\ #set $foreground = $block.is_valid() and 'black' or 'red' <span foreground="$foreground" font_desc="$font"><b>$encode($block.get_name())</b></span>""" @@ -52,15 +54,16 @@ COMMENT_COMPLEXITY_MARKUP_TMPL="""\ """ - -class Block(Element): +class Block(Element, _Block): """The graphical signal block.""" - def __init__(self): + def __init__(self, flow_graph, n): """ Block contructor. Add graphics related params to the block. """ + _Block.__init__(self, flow_graph, n) + self.W = 0 self.H = 0 #add the position param @@ -135,10 +138,10 @@ class Block(Element): delta_coor: requested delta coordinate (dX, dY) to move Returns: - The delta coordinate possible to move while keeping the block on the canvas + The delta coordinate possible to move while keeping the block on the canvas or the input (dX, dY) on failure """ - dX, dY = delta_coor + dX, dY = delta_coor try: fgW, fgH = self.get_parent().get_size() @@ -147,7 +150,7 @@ class Block(Element): sW, sH = self.W, self.H else: sW, sH = self.H, self.W - + if x + dX < 0: dX = -x elif dX + x + sW >= fgW: @@ -159,7 +162,7 @@ class Block(Element): except: pass - return ( dX, dY ) + return ( dX, dY ) def get_rotation(self): """ @@ -193,7 +196,7 @@ class Block(Element): def create_labels(self): """Create the labels for the signal block.""" Element.create_labels(self) - self._bg_color = self.is_dummy_block() and Colors.MISSING_BLOCK_BACKGROUND_COLOR or \ + self._bg_color = self.is_dummy_block and Colors.MISSING_BLOCK_BACKGROUND_COLOR or \ self.get_bypassed() and Colors.BLOCK_BYPASSED_COLOR or \ self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR @@ -204,7 +207,7 @@ class Block(Element): layout.set_markup(Utils.parse_template(BLOCK_MARKUP_TMPL, block=self, font=BLOCK_FONT)) self.label_width, self.label_height = layout.get_pixel_size() #display the params - if self.is_dummy_block(): + if self.is_dummy_block: markups = [ '<span foreground="black" font_desc="{font}"><b>key: </b>{key}</span>'.format(font=PARAM_FONT, key=self._key) ] @@ -271,7 +274,8 @@ class Block(Element): # Show the flowgraph complexity on the top block if enabled if Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY.get_active() and self.get_key() == "options": - complexity = "Complexity: {}bal".format(num_to_str(self.get_parent().get_complexity())) + complexity = calculate_flowgraph_complexity(self.get_parent()) + complexity = "Complexity: {}bal".format(num_to_str(complexity)) layout = gtk.DrawingArea().create_pango_layout('') layout.set_markup(Utils.parse_template(COMMENT_COMPLEXITY_MARKUP_TMPL, @@ -311,7 +315,7 @@ class Block(Element): Element.draw( self, gc, window, bg_color=self._bg_color, border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or - self.is_dummy_block() and Colors.MISSING_BLOCK_BORDER_COLOR or Colors.BORDER_COLOR, + self.is_dummy_block and Colors.MISSING_BLOCK_BORDER_COLOR or Colors.BORDER_COLOR, ) #draw label image if self.is_horizontal(): diff --git a/grc/gui/BlockTreeWindow.py b/grc/gui/BlockTreeWindow.py index 6b3ebf7807..4279e8c61d 100644 --- a/grc/gui/BlockTreeWindow.py +++ b/grc/gui/BlockTreeWindow.py @@ -30,12 +30,27 @@ KEY_INDEX = 1 DOC_INDEX = 2 DOC_MARKUP_TMPL = """\ -#if $doc -#if len($doc) > 1000 -#set $doc = $doc[:1000] + '...' +#set $docs = [] +#if $doc.get('') + #set $docs += $doc.pop('').splitlines() + [''] #end if -$encode($doc)#slurp -#else +#for b, d in $doc.iteritems() + #set $docs += ['--- {0} ---'.format(b)] + d.splitlines() + [''] +#end for +#set $len_out = 0 +#for $n, $line in $enumerate($docs[:-1]) +#if $n + +#end if +$encode($line)#slurp +#set $len_out += $len($line) +#if $n > 10 or $len_out > 500 + +...#slurp +#break +#end if +#end for +#if $len_out == 0 undocumented#slurp #end if""" @@ -129,8 +144,10 @@ class BlockTreeWindow(gtk.VBox): category: the category list or path string block: the block object or None """ - if treestore is None: treestore = self.treestore - if categories is None: categories = self._categories + if treestore is None: + treestore = self.treestore + if categories is None: + categories = self._categories if isinstance(category, (str, unicode)): category = category.split('/') category = tuple(filter(lambda x: x, category)) # tuple is hashable @@ -138,17 +155,18 @@ class BlockTreeWindow(gtk.VBox): for i, cat_name in enumerate(category): sub_category = category[:i+1] if sub_category not in categories: - iter = treestore.insert_before(categories[sub_category[:-1]], None) - treestore.set_value(iter, NAME_INDEX, '[ %s ]'%cat_name) - treestore.set_value(iter, KEY_INDEX, '') - treestore.set_value(iter, DOC_INDEX, Utils.parse_template(CAT_MARKUP_TMPL, cat=cat_name)) - categories[sub_category] = iter + iter_ = treestore.insert_before(categories[sub_category[:-1]], None) + treestore.set_value(iter_, NAME_INDEX, cat_name) + treestore.set_value(iter_, KEY_INDEX, '') + treestore.set_value(iter_, DOC_INDEX, Utils.parse_template(CAT_MARKUP_TMPL, cat=cat_name)) + categories[sub_category] = iter_ # add block - if block is None: return - iter = treestore.insert_before(categories[category], None) - treestore.set_value(iter, NAME_INDEX, block.get_name()) - treestore.set_value(iter, KEY_INDEX, block.get_key()) - treestore.set_value(iter, DOC_INDEX, Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc())) + if block is None: + return + iter_ = treestore.insert_before(categories[category], None) + treestore.set_value(iter_, NAME_INDEX, block.get_name()) + treestore.set_value(iter_, KEY_INDEX, block.get_key()) + treestore.set_value(iter_, DOC_INDEX, Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc())) def update_docs(self): """Update the documentation column of every block""" @@ -157,7 +175,7 @@ class BlockTreeWindow(gtk.VBox): if model.iter_has_child(iter_): return # category node, no doc string key = model.get_value(iter_, KEY_INDEX) - block = self.platform.get_block(key) + block = self.platform.blocks[key] doc = Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc()) model.set_value(iter_, DOC_INDEX, doc) @@ -210,8 +228,8 @@ class BlockTreeWindow(gtk.VBox): self.treeview.set_model(self.treestore) self.treeview.collapse_all() else: - blocks = self.get_flow_graph().get_parent().get_blocks() - matching_blocks = filter(lambda b: key in b.get_key().lower() or key in b.get_name().lower(), blocks) + matching_blocks = filter(lambda b: key in b.get_key().lower() or key in b.get_name().lower(), + self.platform.blocks.values()) self.treestore_search.clear() self._categories_search = {tuple(): None} diff --git a/grc/gui/CMakeLists.txt b/grc/gui/CMakeLists.txt index 99140df7c4..aa9592b351 100644 --- a/grc/gui/CMakeLists.txt +++ b/grc/gui/CMakeLists.txt @@ -17,34 +17,10 @@ # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. -######################################################################## -GR_PYTHON_INSTALL(FILES - external_editor.py - Block.py - Colors.py - Constants.py - Connection.py - Element.py - FlowGraph.py - Param.py - Platform.py - Port.py - Utils.py - ActionHandler.py - Actions.py - Bars.py - BlockTreeWindow.py - Dialogs.py - DrawingArea.py - FileDialogs.py - MainWindow.py - Messages.py - NotebookPage.py - ParserErrorsDialog.py - PropsDialog.py - Preferences.py - StateCache.py - __init__.py +file(GLOB py_files "*.py") + +GR_PYTHON_INSTALL( + FILES ${py_files} DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/gui COMPONENT "grc" ) diff --git a/grc/gui/Colors.py b/grc/gui/Colors.py index 52c95e8edf..050b363cdd 100644 --- a/grc/gui/Colors.py +++ b/grc/gui/Colors.py @@ -33,8 +33,9 @@ try: PARAM_ENTRY_TEXT_COLOR = get_color('black') ENTRYENUM_CUSTOM_COLOR = get_color('#EEEEEE') #flow graph color constants - FLOWGRAPH_BACKGROUND_COLOR = get_color('#FFF9FF') + FLOWGRAPH_BACKGROUND_COLOR = get_color('#FFFFFF') COMMENT_BACKGROUND_COLOR = get_color('#F3F3F3') + FLOWGRAPH_EDGE_COLOR = COMMENT_BACKGROUND_COLOR #block color constants BLOCK_ENABLED_COLOR = get_color('#F1ECFF') BLOCK_DISABLED_COLOR = get_color('#CCCCCC') diff --git a/grc/gui/Config.py b/grc/gui/Config.py new file mode 100644 index 0000000000..9b0c5d4afe --- /dev/null +++ b/grc/gui/Config.py @@ -0,0 +1,74 @@ +""" +Copyright 2016 Free Software Foundation, Inc. +This file is part of GNU Radio + +GNU Radio Companion is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +GNU Radio Companion is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +""" + +import sys +import os +from ..core.Config import Config as _Config +from . import Constants + + +class Config(_Config): + + name = 'GNU Radio Companion' + + gui_prefs_file = os.environ.get( + 'GRC_PREFS_PATH', os.path.expanduser('~/.gnuradio/grc.conf')) + + def __init__(self, install_prefix, *args, **kwargs): + _Config.__init__(self, *args, **kwargs) + self.install_prefix = install_prefix + Constants.update_font_size(self.font_size) + + @property + def editor(self): + return self.prefs.get_string('grc', 'editor', '') + + @editor.setter + def editor(self, value): + self.prefs.get_string('grc', 'editor', value) + self.prefs.save() + + @property + def xterm_executable(self): + return self.prefs.get_string('grc', 'xterm_executable', 'xterm') + + @property + def default_canvas_size(self): + try: # ugly, but matches current code style + raw = self.prefs.get_string('grc', 'canvas_default_size', '1280, 1024') + value = tuple(int(x.strip('() ')) for x in raw.split(',')) + if len(value) != 2 or not all(300 < x < 4096 for x in value): + raise Exception() + return value + except: + print >> sys.stderr, "Error: invalid 'canvas_default_size' setting." + return Constants.DEFAULT_CANVAS_SIZE_DEFAULT + + @property + def font_size(self): + try: # ugly, but matches current code style + font_size = self.prefs.get_long('grc', 'canvas_font_size', + Constants.DEFAULT_FONT_SIZE) + if font_size <= 0: + raise Exception() + except: + font_size = Constants.DEFAULT_FONT_SIZE + print >> sys.stderr, "Error: invalid 'canvas_font_size' setting." + + return font_size diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py index badf8e8a82..50361c19d0 100644 --- a/grc/gui/Connection.py +++ b/grc/gui/Connection.py @@ -17,15 +17,18 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -import Utils -from Element import Element +import gtk + import Colors +import Utils from Constants import CONNECTOR_ARROW_BASE, CONNECTOR_ARROW_HEIGHT -import gtk +from Element import Element + +from ..core.Constants import GR_MESSAGE_DOMAIN +from ..core.Connection import Connection as _Connection -from .. base.Constants import GR_MESSAGE_DOMAIN -class Connection(Element): +class Connection(Element, _Connection): """ A graphical connection for ports. The connection has 2 parts, the arrow and the wire. @@ -35,8 +38,9 @@ class Connection(Element): The arrow coloring exposes the enabled and valid states. """ - def __init__(self): + def __init__(self, **kwargs): Element.__init__(self) + _Connection.__init__(self, **kwargs) # can't use Colors.CONNECTION_ENABLED_COLOR here, might not be defined (grcc) self._bg_color = self._arrow_color = self._color = None @@ -88,7 +92,7 @@ class Connection(Element): if not source_domain == sink_domain == GR_MESSAGE_DOMAIN \ else gtk.gdk.LINE_ON_OFF_DASH get_domain_color = lambda d: Colors.get_color(( - self.get_parent().get_parent().get_domain(d) or {} + self.get_parent().get_parent().domains.get(d, {}) ).get('color') or Colors.DEFAULT_DOMAIN_COLOR_CODE) self._color = get_domain_color(source_domain) self._bg_color = get_domain_color(sink_domain) diff --git a/grc/gui/Constants.py b/grc/gui/Constants.py index 741c6fda95..e267c6ca02 100644 --- a/grc/gui/Constants.py +++ b/grc/gui/Constants.py @@ -17,18 +17,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -import os -import sys - -import pygtk -pygtk.require('2.0') import gtk -from gnuradio import gr +from ..core.Constants import * -prefs = gr.prefs() -GR_PREFIX = gr.prefix() -EDITOR = prefs.get_string('grc', 'editor', '') # default path for the open/save dialogs DEFAULT_FILE_PATH = os.getcwd() @@ -50,28 +42,12 @@ MIN_DIALOG_HEIGHT = 500 DEFAULT_BLOCKS_WINDOW_WIDTH = 100 DEFAULT_REPORTS_WINDOW_WIDTH = 100 -try: # ugly, but matches current code style - raw = prefs.get_string('grc', 'canvas_default_size', '1280, 1024') - DEFAULT_CANVAS_SIZE = tuple(int(x.strip('() ')) for x in raw.split(',')) - if len(DEFAULT_CANVAS_SIZE) != 2 or not all(300 < x < 4096 for x in DEFAULT_CANVAS_SIZE): - raise Exception() -except: - DEFAULT_CANVAS_SIZE = 1280, 1024 - print >> sys.stderr, "Error: invalid 'canvas_default_size' setting." - -# flow-graph canvas fonts -try: # ugly, but matches current code style - FONT_SIZE = prefs.get_long('grc', 'canvas_font_size', 8) - if FONT_SIZE <= 0: - raise Exception() -except: - FONT_SIZE = 8 - print >> sys.stderr, "Error: invalid 'canvas_font_size' setting." -FONT_FAMILY = "Sans" -BLOCK_FONT = "%s %f" % (FONT_FAMILY, FONT_SIZE) -PORT_FONT = BLOCK_FONT -PARAM_FONT = "%s %f" % (FONT_FAMILY, FONT_SIZE - 0.5) +DEFAULT_CANVAS_SIZE_DEFAULT = 1280, 1024 +FONT_SIZE = DEFAULT_FONT_SIZE = 8 +FONT_FAMILY = "Sans" +BLOCK_FONT = PORT_FONT = "Sans 8" +PARAM_FONT = "Sans 7.5" # size of the state saving cache in the flow graph (undo/redo functionality) STATE_CACHE_SIZE = 42 @@ -90,8 +66,7 @@ CANVAS_GRID_SIZE = 8 # port constraint dimensions PORT_BORDER_SEPARATION = 8 PORT_SPACING = 2 * PORT_BORDER_SEPARATION -PORT_SEPARATION = PORT_SPACING + 2 * PORT_LABEL_PADDING + int(1.5 * FONT_SIZE) -PORT_SEPARATION += -PORT_SEPARATION % (2 * CANVAS_GRID_SIZE) # even multiple +PORT_SEPARATION = 32 PORT_MIN_WIDTH = 20 PORT_LABEL_HIDDEN_WIDTH = 10 @@ -120,3 +95,17 @@ SCROLL_DISTANCE = 15 # How close the mouse click can be to a line and register a connection select. LINE_SELECT_SENSITIVITY = 5 + + +def update_font_size(font_size): + global PORT_SEPARATION, BLOCK_FONT, PORT_FONT, PARAM_FONT, FONT_SIZE + + FONT_SIZE = font_size + BLOCK_FONT = "%s %f" % (FONT_FAMILY, font_size) + PORT_FONT = BLOCK_FONT + PARAM_FONT = "%s %f" % (FONT_FAMILY, font_size - 0.5) + + PORT_SEPARATION = PORT_SPACING + 2 * PORT_LABEL_PADDING + int(1.5 * font_size) + PORT_SEPARATION += -PORT_SEPARATION % (2 * CANVAS_GRID_SIZE) # even multiple + +update_font_size(DEFAULT_FONT_SIZE) diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py index f2941250a8..6cfdd50a34 100644 --- a/grc/gui/Dialogs.py +++ b/grc/gui/Dialogs.py @@ -17,15 +17,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -import pygtk -pygtk.require('2.0') import gtk import sys from distutils.spawn import find_executable - -from . import Utils, Actions, Constants, Messages +from . import Utils, Actions +from ..core import Messages class SimpleTextDisplay(gtk.TextView): @@ -177,14 +175,14 @@ def ErrorsDialog(flowgraph): MessageDialogHelper( class AboutDialog(gtk.AboutDialog): """A cute little about dialog.""" - def __init__(self, platform): + def __init__(self, config): """AboutDialog constructor.""" gtk.AboutDialog.__init__(self) - self.set_name(platform.get_name()) - self.set_version(platform.get_version()) - self.set_license(platform.get_license()) - self.set_copyright(platform.get_license().splitlines()[0]) - self.set_website(platform.get_website()) + self.set_name(config.name) + self.set_version(config.version) + self.set_license(config.license) + self.set_copyright(config.license.splitlines()[0]) + self.set_website(config.website) self.run() self.destroy() @@ -240,7 +238,7 @@ def MissingXTermDialog(xterm): ) -def ChooseEditorDialog(): +def ChooseEditorDialog(config): # Give the option to either choose an editor or use the default # Always return true/false so the caller knows it was successful buttons = ( @@ -266,10 +264,7 @@ def ChooseEditorDialog(): file_dialog.set_current_folder('/usr/bin') try: if file_dialog.run() == gtk.RESPONSE_OK: - file_path = file_dialog.get_filename() - Constants.prefs.set_string('grc', 'editor', file_path) - Constants.prefs.save() - Constants.EDITOR = file_path + config.editor = file_path = file_dialog.get_filename() file_dialog.destroy() return file_path finally: @@ -287,16 +282,12 @@ def ChooseEditorDialog(): if process is None: raise ValueError("Can't find default editor executable") # Save - Constants.prefs.set_string('grc', 'editor', process) - Constants.prefs.save() - Constants.EDITOR = process + config.editor = process return process except Exception: Messages.send('>>> Unable to load the default editor. Please choose an editor.\n') # Just reset of the constant and force the user to select an editor the next time - Constants.prefs.set_string('grc', 'editor', '') - Constants.prefs.save() - Constants.EDITOR = "" + config.editor = '' return Messages.send('>>> No editor selected.\n') diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py index 4412129809..6a1df27a8c 100644 --- a/grc/gui/DrawingArea.py +++ b/grc/gui/DrawingArea.py @@ -20,7 +20,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import pygtk pygtk.require('2.0') import gtk + from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT, DND_TARGETS +import Colors + class DrawingArea(gtk.DrawingArea): """ @@ -68,13 +71,21 @@ class DrawingArea(gtk.DrawingArea): self.set_flags(gtk.CAN_FOCUS) # self.set_can_focus(True) self.connect('focus-out-event', self._handle_focus_lost_event) - def new_pixmap(self, width, height): return gtk.gdk.Pixmap(self.window, width, height, -1) - def get_pixbuf(self): - width, height = self._pixmap.get_size() - pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8, width, height) - pixbuf.get_from_drawable(self._pixmap, self._pixmap.get_colormap(), 0, 0, 0, 0, width, height) + def new_pixmap(self, width, height): + return gtk.gdk.Pixmap(self.window, width, height, -1) + + def get_screenshot(self, transparent_bg=False): + pixmap = self._pixmap + W, H = pixmap.get_size() + pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8, W, H) + pixbuf.fill(0xFF + Colors.FLOWGRAPH_BACKGROUND_COLOR.pixel << 8) + pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, W-1, H-1) + if transparent_bg: + bgc = Colors.FLOWGRAPH_BACKGROUND_COLOR + pixbuf = pixbuf.add_alpha(True, bgc.red, bgc.green, bgc.blue) return pixbuf + ########################################################################## ## Handlers ########################################################################## @@ -149,6 +160,12 @@ class DrawingArea(gtk.DrawingArea): gc = self.window.new_gc() self._flow_graph.draw(gc, self._pixmap) self.window.draw_drawable(gc, self._pixmap, 0, 0, 0, 0, -1, -1) + # draw a light grey line on the bottom and right end of the canvas. + # this is useful when the theme uses the same panel bg color as the canvas + W, H = self._pixmap.get_size() + gc.set_foreground(Colors.FLOWGRAPH_EDGE_COLOR) + self.window.draw_line(gc, 0, H-1, W, H-1) + self.window.draw_line(gc, W-1, 0, W-1, H) def _handle_focus_lost_event(self, widget, event): # don't clear selection while context menu is active diff --git a/grc/gui/Element.py b/grc/gui/Element.py index 18fb321929..9385424772 100644 --- a/grc/gui/Element.py +++ b/grc/gui/Element.py @@ -132,14 +132,14 @@ class Element(object): """ self.coor = coor - def get_parent(self): - """ - Get the parent of this element. - - Returns: - the parent - """ - return self.parent + # def get_parent(self): + # """ + # Get the parent of this element. + # + # Returns: + # the parent + # """ + # return self.parent def set_highlighted(self, highlighted): """ diff --git a/grc/gui/Executor.py b/grc/gui/Executor.py new file mode 100644 index 0000000000..f75f514cdb --- /dev/null +++ b/grc/gui/Executor.py @@ -0,0 +1,123 @@ +# Copyright 2016 Free Software Foundation, Inc. +# This file is part of GNU Radio +# +# GNU Radio Companion is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +import gobject +import os +import threading +import shlex +import subprocess +import sys +import re +from distutils.spawn import find_executable + +from ..core import Messages + + +class ExecFlowGraphThread(threading.Thread): + """Execute the flow graph as a new process and wait on it to finish.""" + + def __init__(self, action_handler): + """ + ExecFlowGraphThread constructor. + + Args: + action_handler: an instance of an ActionHandler + """ + threading.Thread.__init__(self) + self.update_exec_stop = action_handler.update_exec_stop + self.flow_graph = action_handler.get_flow_graph() + self.xterm_executable = action_handler.platform.config.xterm_executable + #store page and dont use main window calls in run + self.page = action_handler.get_page() + #get the popen + try: + self.p = self._popen() + self.page.set_proc(self.p) + #update + self.update_exec_stop() + self.start() + except Exception, e: + Messages.send_verbose_exec(str(e)) + Messages.send_end_exec() + + def _popen(self): + """ + Execute this python flow graph. + """ + run_command = self.flow_graph.get_option('run_command') + generator = self.page.get_generator() + + try: + run_command = run_command.format( + python=shlex_quote(sys.executable), + filename=shlex_quote(generator.file_path)) + run_command_args = shlex.split(run_command) + except Exception as e: + raise ValueError("Can't parse run command {!r}: {}".format(run_command, e)) + + # When in no gui mode on linux, use a graphical terminal (looks nice) + xterm_executable = find_executable(self.xterm_executable) + if generator.generate_options == 'no_gui' and xterm_executable: + run_command_args = [xterm_executable, '-e', run_command] + + # this does not reproduce a shell executable command string, if a graphical + # terminal is used. Passing run_command though shlex_quote would do it but + # it looks really ugly and confusing in the console panel. + Messages.send_start_exec(' '.join(run_command_args)) + + return subprocess.Popen( + args=run_command_args, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + shell=False, universal_newlines=True + ) + + def run(self): + """ + Wait on the executing process by reading from its stdout. + Use gobject.idle_add when calling functions that modify gtk objects. + """ + #handle completion + r = "\n" + while r: + gobject.idle_add(Messages.send_verbose_exec, r) + r = os.read(self.p.stdout.fileno(), 1024) + self.p.poll() + gobject.idle_add(self.done) + + def done(self): + """Perform end of execution tasks.""" + Messages.send_end_exec(self.p.returncode) + self.page.set_proc(None) + self.update_exec_stop() + + +########################################################### +# back-port from python3 +########################################################### +_find_unsafe = re.compile(r'[^\w@%+=:,./-]').search + + +def shlex_quote(s): + """Return a shell-escaped version of the string *s*.""" + if not s: + return "''" + if _find_unsafe(s) is None: + return s + + # use single quotes, and put single quotes into double quotes + # the string $'b is then quoted as '$'"'"'b' + return "'" + s.replace("'", "'\"'\"'") + "'" diff --git a/grc/gui/FileDialogs.py b/grc/gui/FileDialogs.py index 730ac6fba0..4b5770ad21 100644 --- a/grc/gui/FileDialogs.py +++ b/grc/gui/FileDialogs.py @@ -210,3 +210,18 @@ class SaveFlowGraphFileDialog(FileDialog): type = SAVE_FLOW_GRAPH class OpenQSSFileDialog(FileDialog): type = OPEN_QSS_THEME class SaveReportsFileDialog(FileDialog): type = SAVE_REPORTS class SaveImageFileDialog(FileDialog): type = SAVE_IMAGE + + +class SaveScreenShotDialog(SaveImageFileDialog): + + def __init__(self, current_file_path=''): + SaveImageFileDialog.__init__(self, current_file_path) + self._button = button = gtk.CheckButton('_Background transparent') + self._button.set_active(Preferences.screen_shot_background_transparent()) + self.set_extra_widget(button) + + def run(self): + filename = SaveImageFileDialog.run(self) + bg_transparent = self._button.get_active() + Preferences.screen_shot_background_transparent(bg_transparent) + return filename, bg_transparent diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index 2053e86454..357f87c894 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -17,39 +17,43 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -import random import functools -from itertools import chain -from operator import methodcaller +import random from distutils.spawn import find_executable +from itertools import chain, count +from operator import methodcaller import gobject -from . import Actions, Colors, Constants, Utils, Messages, Bars, Dialogs -from . Element import Element -from . Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE -from . external_editor import ExternalEditor +from . import Actions, Colors, Constants, Utils, Bars, Dialogs +from .Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE +from .Element import Element +from .external_editor import ExternalEditor +from ..core.FlowGraph import FlowGraph as _Flowgraph +from ..core import Messages -class FlowGraph(Element): + +class FlowGraph(Element, _Flowgraph): """ FlowGraph is the data structure to store graphical signal blocks, graphical inputs and outputs, and the connections between inputs and outputs. """ - def __init__(self): + def __init__(self, **kwargs): """ FlowGraph constructor. Create a list for signal blocks and connections. Connect mouse handlers. """ Element.__init__(self) + _Flowgraph.__init__(self, **kwargs) #when is the flow graph selected? (used by keyboard event handler) self.is_selected = lambda: bool(self.get_selected_elements()) #important vars dealing with mouse event tracking self.element_moved = False self.mouse_pressed = False - self.unselect() + self._selected_elements = [] self.press_coor = (0, 0) #selected ports self._old_selected_port = None @@ -62,14 +66,31 @@ class FlowGraph(Element): self._external_updaters = {} + def _get_unique_id(self, base_id=''): + """ + Get a unique id starting with the base id. + + Args: + base_id: the id starts with this and appends a count + + Returns: + a unique id + """ + for index in count(): + block_id = '{}_{}'.format(base_id, index) + if block_id not in (b.get_id() for b in self.blocks): + break + return block_id + def install_external_editor(self, param): target = (param.get_parent().get_id(), param.get_key()) if target in self._external_updaters: editor = self._external_updaters[target] else: - editor = (find_executable(Constants.EDITOR) or - Dialogs.ChooseEditorDialog()) + config = self.get_parent().config + editor = (find_executable(config.editor) or + Dialogs.ChooseEditorDialog(config)) if not editor: return updater = functools.partial( @@ -86,9 +107,7 @@ class FlowGraph(Element): # Problem launching the editor. Need to select a new editor. Messages.send('>>> Error opening an external editor. Please select a different editor.\n') # Reset the editor to force the user to select a new one. - Constants.prefs.set_string('grc', 'editor', '') - Constants.prefs.save() - Constants.EDITOR = "" + self.get_parent().config.editor = '' def handle_external_editor_change(self, new_value, target): try: @@ -131,7 +150,7 @@ class FlowGraph(Element): int(random.uniform(.25, .75)*v_adj.page_size + v_adj.get_value()), ) #get the new block - block = self.get_new_block(key) + block = self.new_block(key) block.set_coordinate(coor) block.set_rotation(0) block.get_param('id').set_value(id) @@ -160,7 +179,7 @@ class FlowGraph(Element): #get connections between selected blocks connections = filter( lambda c: c.get_source().get_parent() in blocks and c.get_sink().get_parent() in blocks, - self.get_connections(), + self.connections, ) clipboard = ( (x_min, y_min), @@ -190,7 +209,7 @@ class FlowGraph(Element): for block_n in blocks_n: block_key = block_n.find('key') if block_key == 'options': continue - block = self.get_new_block(block_key) + block = self.new_block(block_key) if not block: continue # unknown block was pasted (e.g. dummy block) selected.add(block) @@ -206,7 +225,7 @@ class FlowGraph(Element): if param_key == 'id': old_id2block[param_value] = block #if the block id is not unique, get a new block id - if param_value in [blk.get_id() for blk in self.get_blocks()]: + if param_value in (blk.get_id() for blk in self.blocks): param_value = self._get_unique_id(param_value) #set value to key block.get_param(param_key).set_value(param_value) @@ -350,7 +369,7 @@ class FlowGraph(Element): # draw comments first if Actions.TOGGLE_SHOW_BLOCK_COMMENTS.get_active(): - for block in self.iter_blocks(): + for block in self.blocks: if block.get_enabled(): block.draw_comment(gc, window) #draw multi select rectangle @@ -368,8 +387,8 @@ class FlowGraph(Element): window.draw_rectangle(gc, False, x, y, w, h) #draw blocks on top of connections hide_disabled_blocks = Actions.TOGGLE_HIDE_DISABLED_BLOCKS.get_active() - blocks = sorted(self.iter_blocks(), key=methodcaller('get_enabled')) - for element in chain(self.iter_connections(), blocks): + blocks = sorted(self.blocks, key=methodcaller('get_enabled')) + for element in chain(self.connections, blocks): if hide_disabled_blocks and not element.get_enabled(): continue # skip hidden disabled blocks and connections element.draw(gc, window) @@ -432,6 +451,10 @@ class FlowGraph(Element): """ self._selected_elements = [] + def select_all(self): + """Select all blocks in the flow graph""" + self._selected_elements = list(self.get_elements()) + def what_is_selected(self, coor, coor_m=None): """ What is selected? @@ -456,13 +479,13 @@ class FlowGraph(Element): if not selected_element: continue # hidden disabled connections, blocks and their ports can not be selected if Actions.TOGGLE_HIDE_DISABLED_BLOCKS.get_active() and ( - selected_element.is_block() and not selected_element.get_enabled() or - selected_element.is_connection() and not selected_element.get_enabled() or - selected_element.is_port() and not selected_element.get_parent().get_enabled() + selected_element.is_block and not selected_element.get_enabled() or + selected_element.is_connection and not selected_element.get_enabled() or + selected_element.is_port and not selected_element.get_parent().get_enabled() ): continue #update the selected port information - if selected_element.is_port(): + if selected_element.is_port: if not coor_m: selected_port = selected_element selected_element = selected_element.get_parent() selected.add(selected_element) @@ -486,7 +509,8 @@ class FlowGraph(Element): """ selected = set() for selected_element in self.get_selected_elements(): - if selected_element.is_connection(): selected.add(selected_element) + if selected_element.is_connection: + selected.add(selected_element) return list(selected) def get_selected_blocks(self): @@ -498,7 +522,8 @@ class FlowGraph(Element): """ selected = set() for selected_element in self.get_selected_elements(): - if selected_element.is_block(): selected.add(selected_element) + if selected_element.is_block: + selected.add(selected_element) return list(selected) def get_selected_block(self): @@ -673,7 +698,7 @@ class FlowGraph(Element): adj.set_value(adj_val-SCROLL_DISTANCE) adj.emit('changed') #remove the connection if selected in drag event - if len(self.get_selected_elements()) == 1 and self.get_selected_element().is_connection(): + if len(self.get_selected_elements()) == 1 and self.get_selected_element().is_connection: Actions.ELEMENT_DELETE() #move the selected elements and record the new coordinate if not self.get_ctrl_mask(): diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py index a340bcc817..6da240d85b 100644 --- a/grc/gui/MainWindow.py +++ b/grc/gui/MainWindow.py @@ -17,21 +17,19 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from Constants import \ - NEW_FLOGRAPH_TITLE, DEFAULT_REPORTS_WINDOW_WIDTH -import Actions -import pygtk -pygtk.require('2.0') -import gtk -import Bars -from BlockTreeWindow import BlockTreeWindow -from Dialogs import TextDisplay, MessageDialogHelper -from NotebookPage import NotebookPage -import Preferences -import Messages -import Utils import os +import gtk + +from . import Bars, Actions, Preferences, Utils +from .BlockTreeWindow import BlockTreeWindow +from .Constants import \ + NEW_FLOGRAPH_TITLE, DEFAULT_REPORTS_WINDOW_WIDTH +from .Dialogs import TextDisplay, MessageDialogHelper +from .NotebookPage import NotebookPage + +from ..core import Messages + MAIN_WINDOW_TITLE_TMPL = """\ #if not $saved *#slurp @@ -71,11 +69,13 @@ class MainWindow(gtk.Window): Setup the menu, toolbar, flowgraph editor notebook, block selection window... """ self._platform = platform - gen_opts = platform.get_block('options').get_param('generate_options') + + gen_opts = platform.blocks['options'].get_param('generate_options') generate_mode_default = gen_opts.get_value() generate_modes = [ (o.get_key(), o.get_name(), o.get_key() == generate_mode_default) for o in gen_opts.get_options()] + # load preferences Preferences.load(platform) #setup window @@ -283,7 +283,7 @@ class MainWindow(gtk.Window): new_flowgraph_title=NEW_FLOGRAPH_TITLE, read_only=self.get_page().get_read_only(), saved=self.get_page().get_saved(), - platform_name=self._platform.get_name(), + platform_name=self._platform.config.name, ) ) #set tab titles diff --git a/grc/gui/NotebookPage.py b/grc/gui/NotebookPage.py index 4c112154af..6614649c89 100644 --- a/grc/gui/NotebookPage.py +++ b/grc/gui/NotebookPage.py @@ -102,10 +102,8 @@ class NotebookPage(gtk.HBox): Returns: generator """ - return self.get_flow_graph().get_parent().get_generator()( - self.get_flow_graph(), - self.get_file_path(), - ) + platform = self.get_flow_graph().get_parent() + return platform.Generator(self.get_flow_graph(), self.get_file_path()) def _handle_button(self, button): """ diff --git a/grc/gui/Param.py b/grc/gui/Param.py index 6884d6530a..bf0a59b96b 100644 --- a/grc/gui/Param.py +++ b/grc/gui/Param.py @@ -23,8 +23,10 @@ import pygtk pygtk.require('2.0') import gtk -from . import Colors, Utils, Constants, Dialogs -from . Element import Element +from . import Colors, Utils, Constants +from .Element import Element + +from ..core.Param import Param as _Param class InputParam(gtk.HBox): @@ -317,7 +319,9 @@ class FileParam(EntryParam): if self.param.get_key() == 'qt_qss_theme': dirname = os.path.dirname(dirname) # trim filename if not os.path.exists(dirname): - dirname = os.path.join(Constants.GR_PREFIX, '/share/gnuradio/themes') + platform = self.param.get_parent().get_parent().get_parent() + dirname = os.path.join(platform.config.install_prefix, + '/share/gnuradio/themes') if not os.path.exists(dirname): dirname = os.getcwd() # fix bad paths @@ -378,11 +382,12 @@ Error: #end if""" -class Param(Element): +class Param(Element, _Param): """The graphical parameter.""" - def __init__(self): + def __init__(self, **kwargs): Element.__init__(self) + _Param.__init__(self, **kwargs) def get_input(self, *args, **kwargs): """ diff --git a/grc/gui/Platform.py b/grc/gui/Platform.py index eda28a0e94..500df1cce4 100644 --- a/grc/gui/Platform.py +++ b/grc/gui/Platform.py @@ -17,12 +17,55 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from Element import Element +import os +import sys -class Platform(Element): - def __init__(self, prefs_file): +from ..core.Platform import Platform as _Platform + +from .Config import Config as _Config +from .Block import Block as _Block +from .Connection import Connection as _Connection +from .Element import Element +from .FlowGraph import FlowGraph as _FlowGraph +from .Param import Param as _Param +from .Port import Port as _Port + + +class Platform(Element, _Platform): + + def __init__(self, *args, **kwargs): Element.__init__(self) + _Platform.__init__(self, *args, **kwargs) + + # Ensure conf directories + gui_prefs_file = self.config.gui_prefs_file + if not os.path.exists(os.path.dirname(gui_prefs_file)): + os.mkdir(os.path.dirname(gui_prefs_file)) + + self._move_old_pref_file() + + def get_prefs_file(self): + return self.config.gui_prefs_file - self._prefs_file = prefs_file + def _move_old_pref_file(self): + gui_prefs_file = self.config.gui_prefs_file + old_gui_prefs_file = os.environ.get( + 'GRC_PREFS_PATH', os.path.expanduser('~/.grc')) + if gui_prefs_file == old_gui_prefs_file: + return # prefs file overridden with env var + if os.path.exists(old_gui_prefs_file) and not os.path.exists(gui_prefs_file): + try: + import shutil + shutil.move(old_gui_prefs_file, gui_prefs_file) + except Exception as e: + print >> sys.stderr, e - def get_prefs_file(self): return self._prefs_file + ############################################## + # Constructors + ############################################## + FlowGraph = _FlowGraph + Connection = _Connection + Block = _Block + Port = _Port + Param = _Param + Config = _Config diff --git a/grc/gui/Port.py b/grc/gui/Port.py index ae1a1d223f..6314b7ede8 100644 --- a/grc/gui/Port.py +++ b/grc/gui/Port.py @@ -17,32 +17,33 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from Element import Element -from Constants import ( - PORT_SEPARATION, PORT_SPACING, CONNECTOR_EXTENSION_MINIMAL, - CONNECTOR_EXTENSION_INCREMENT, CANVAS_GRID_SIZE, - PORT_LABEL_PADDING, PORT_MIN_WIDTH, PORT_LABEL_HIDDEN_WIDTH, PORT_FONT -) -from .. base.Constants import DEFAULT_DOMAIN, GR_MESSAGE_DOMAIN -import Utils -import Actions -import Colors import pygtk pygtk.require('2.0') import gtk +from . import Actions, Colors, Utils +from .Constants import ( + PORT_SEPARATION, PORT_SPACING, CONNECTOR_EXTENSION_MINIMAL, + CONNECTOR_EXTENSION_INCREMENT, PORT_LABEL_PADDING, PORT_MIN_WIDTH, PORT_LABEL_HIDDEN_WIDTH, PORT_FONT +) +from .Element import Element +from ..core.Constants import DEFAULT_DOMAIN, GR_MESSAGE_DOMAIN + +from ..core.Port import Port as _Port + PORT_MARKUP_TMPL="""\ <span foreground="black" font_desc="$font">$encode($port.get_name())</span>""" -class Port(Element): +class Port(_Port, Element): """The graphical port.""" - def __init__(self): + def __init__(self, block, n, dir): """ Port contructor. Create list of connector coordinates. """ + _Port.__init__(self, block, n, dir) Element.__init__(self) self.W = self.H = self.w = self.h = 0 self._connector_coordinate = (0, 0) @@ -63,7 +64,7 @@ class Port(Element): rotation = self.get_rotation() #get all sibling ports ports = self.get_parent().get_sources_gui() \ - if self.is_source() else self.get_parent().get_sinks_gui() + if self.is_source else self.get_parent().get_sinks_gui() ports = filter(lambda p: not p.get_hide(), ports) #get the max width self.W = max([port.W for port in ports] + [PORT_MIN_WIDTH]) @@ -81,27 +82,27 @@ class Port(Element): index = length-index-1 port_separation = PORT_SEPARATION \ - if not self.get_parent().has_busses[self.is_source()] \ + if not self.get_parent().has_busses[self.is_source] \ else max([port.H for port in ports]) + PORT_SPACING offset = (self.get_parent().H - (length-1)*port_separation - self.H)/2 #create areas and connector coordinates - if (self.is_sink() and rotation == 0) or (self.is_source() and rotation == 180): + if (self.is_sink and rotation == 0) or (self.is_source and rotation == 180): x = -W y = port_separation*index+offset self.add_area((x, y), (W, self.H)) self._connector_coordinate = (x-1, y+self.H/2) - elif (self.is_source() and rotation == 0) or (self.is_sink() and rotation == 180): + elif (self.is_source and rotation == 0) or (self.is_sink and rotation == 180): x = self.get_parent().W y = port_separation*index+offset self.add_area((x, y), (W, self.H)) self._connector_coordinate = (x+1+W, y+self.H/2) - elif (self.is_source() and rotation == 90) or (self.is_sink() and rotation == 270): + elif (self.is_source and rotation == 90) or (self.is_sink and rotation == 270): y = -W x = port_separation*index+offset self.add_area((x, y), (self.H, W)) self._connector_coordinate = (x+self.H/2, y-1) - elif (self.is_sink() and rotation == 90) or (self.is_source() and rotation == 270): + elif (self.is_sink and rotation == 90) or (self.is_source and rotation == 270): y = self.get_parent().W x = port_separation*index+offset self.add_area((x, y), (self.H, W)) @@ -144,7 +145,7 @@ class Port(Element): Element.draw( self, gc, window, bg_color=self._bg_color, border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or - self.get_parent().is_dummy_block() and Colors.MISSING_BLOCK_BORDER_COLOR or + self.get_parent().is_dummy_block and Colors.MISSING_BLOCK_BORDER_COLOR or Colors.BORDER_COLOR, ) if not self._areas_list or self._label_hidden(): @@ -176,8 +177,8 @@ class Port(Element): Returns: the direction in degrees """ - if self.is_source(): return self.get_rotation() - elif self.is_sink(): return (self.get_rotation() + 180)%360 + if self.is_source: return self.get_rotation() + elif self.is_sink: return (self.get_rotation() + 180)%360 def get_connector_length(self): """ diff --git a/grc/gui/Preferences.py b/grc/gui/Preferences.py index 3ebee24345..1a194fd8c5 100644 --- a/grc/gui/Preferences.py +++ b/grc/gui/Preferences.py @@ -35,7 +35,7 @@ _config_parser = ConfigParser.SafeConfigParser() def file_extension(): - return '.'+_platform.get_key() + return '.grc' def load(platform): @@ -150,3 +150,7 @@ def blocks_window_position(pos=None): def xterm_missing(cmd=None): return entry('xterm_missing', cmd, default='INVALID_XTERM_SETTING') + + +def screen_shot_background_transparent(transparent=None): + return entry('screen_shot_background_transparent', transparent, default=False) diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index bf7d31d391..7c66a77a54 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -97,7 +97,8 @@ class PropsDialog(gtk.Dialog): self._params_boxes.append((tab, label, vbox)) # Docs for the block - self._docs_text_display = SimpleTextDisplay() + self._docs_text_display = doc_view = SimpleTextDisplay() + doc_view.get_buffer().create_tag('b', weight=pango.WEIGHT_BOLD) self._docs_box = gtk.ScrolledWindow() self._docs_box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self._docs_box.add_with_viewport(self._docs_text_display) @@ -200,10 +201,43 @@ class PropsDialog(gtk.Dialog): messages = '\n\n'.join(self._block.get_error_messages()) self._error_messages_text_display.set_text(messages) # update the docs box - self._docs_text_display.set_text(self._block.get_doc()) + self._update_docs_page() # update the generated code self._update_generated_code_page() + def _update_docs_page(self): + """Show documentation from XML and try to display best matching docstring""" + buffer = self._docs_text_display.get_buffer() + buffer.delete(buffer.get_start_iter(), buffer.get_end_iter()) + pos = buffer.get_end_iter() + + docstrings = self._block.get_doc() + if not docstrings: + return + + # show documentation string from block xml + from_xml = docstrings.pop('', '') + for line in from_xml.splitlines(): + if line.lstrip() == line and line.endswith(':'): + buffer.insert_with_tags_by_name(pos, line + '\n', 'b') + else: + buffer.insert(pos, line + '\n') + if from_xml: + buffer.insert(pos, '\n') + + # if given the current parameters an exact match can be made + block_constructor = self._block.get_make().rsplit('.', 2)[-1] + block_class = block_constructor.partition('(')[0].strip() + if block_class in docstrings: + docstrings = {block_class: docstrings[block_class]} + + # show docstring(s) extracted from python sources + for cls_name, docstring in docstrings.iteritems(): + buffer.insert_with_tags_by_name(pos, cls_name + '\n', 'b') + buffer.insert(pos, docstring + '\n\n') + pos.backward_chars(2) + buffer.delete(pos, buffer.get_end_iter()) + def _update_generated_code_page(self): if not self._code_text_display: return # user disabled code preview diff --git a/grc/main.py b/grc/main.py new file mode 100755 index 0000000000..ae7a0ce115 --- /dev/null +++ b/grc/main.py @@ -0,0 +1,55 @@ +# Copyright 2009-2016 Free Software Foundation, Inc. +# This file is part of GNU Radio +# +# GNU Radio Companion is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +import optparse + +import gtk +from gnuradio import gr + +from .gui.Platform import Platform +from .gui.ActionHandler import ActionHandler + + +VERSION_AND_DISCLAIMER_TEMPLATE = """\ +GNU Radio Companion %s + +This program is part of GNU Radio +GRC comes with ABSOLUTELY NO WARRANTY. +This is free software, and you are welcome to redistribute it. +""" + + +def main(): + parser = optparse.OptionParser( + usage='usage: %prog [options] [saved flow graphs]', + version=VERSION_AND_DISCLAIMER_TEMPLATE % gr.version()) + options, args = parser.parse_args() + + try: + gtk.window_set_default_icon(gtk.IconTheme().load_icon('gnuradio-grc', 256, 0)) + except: + pass + + platform = Platform( + prefs_file=gr.prefs(), + version=gr.version(), + version_parts=(gr.major_version(), gr.api_version(), gr.minor_version()), + install_prefix=gr.prefix() + ) + ActionHandler(args, platform) + gtk.main() + diff --git a/grc/python/Block.py b/grc/python/Block.py deleted file mode 100644 index 782893fd8f..0000000000 --- a/grc/python/Block.py +++ /dev/null @@ -1,323 +0,0 @@ -""" -Copyright 2008-2011 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import itertools -import collections - -from .. base.Constants import BLOCK_FLAG_NEED_QT_GUI, BLOCK_FLAG_NEED_WX_GUI -from .. base.odict import odict - -from .. base.Block import Block as _Block -from .. gui.Block import Block as _GUIBlock - -from . FlowGraph import _variable_matcher -from . import epy_block_io - - -class Block(_Block, _GUIBlock): - - def __init__(self, flow_graph, n): - """ - Make a new block from nested data. - - Args: - flow: graph the parent element - n: the nested odict - - Returns: - block a new block - """ - #grab the data - self._doc = (n.find('doc') or '').strip('\n').replace('\\\n', '') - self._imports = map(lambda i: i.strip(), n.findall('import')) - self._make = n.find('make') - self._var_make = n.find('var_make') - self._checks = n.findall('check') - self._callbacks = n.findall('callback') - self._bus_structure_source = n.find('bus_structure_source') or '' - self._bus_structure_sink = n.find('bus_structure_sink') or '' - self.port_counters = [itertools.count(), itertools.count()] - #build the block - _Block.__init__( - self, - flow_graph=flow_graph, - n=n, - ) - _GUIBlock.__init__(self) - - self._epy_source_hash = -1 # for epy blocks - self._epy_reload_error = None - - def get_bus_structure(self, direction): - if direction == 'source': - bus_structure = self._bus_structure_source; - else: - bus_structure = self._bus_structure_sink; - - bus_structure = self.resolve_dependencies(bus_structure); - - if not bus_structure: return '' - try: - clean_bus_structure = self.get_parent().evaluate(bus_structure) - return clean_bus_structure - - except: return '' - - def validate(self): - """ - Validate this block. - Call the base class validate. - Evaluate the checks: each check must evaluate to True. - """ - _Block.validate(self) - #evaluate the checks - for check in self._checks: - check_res = self.resolve_dependencies(check) - try: - if not self.get_parent().evaluate(check_res): - self.add_error_message('Check "%s" failed.'%check) - except: self.add_error_message('Check "%s" did not evaluate.'%check) - # for variables check the value (only if var_value is used - if _variable_matcher.match(self.get_key()) and self._var_value != '$value': - value = self._var_value - try: - value = self.get_var_value() - self.get_parent().evaluate(value) - except Exception as err: - self.add_error_message('Value "%s" cannot be evaluated:\n%s' % (value, err)) - - # check if this is a GUI block and matches the selected generate option - current_generate_option = self.get_parent().get_option('generate_options') - - def check_generate_mode(label, flag, valid_options): - block_requires_mode = ( - flag in self.get_flags() or - self.get_name().upper().startswith(label) - ) - if block_requires_mode and current_generate_option not in valid_options: - self.add_error_message("Can't generate this block in mode " + - repr(current_generate_option)) - - check_generate_mode('WX GUI', BLOCK_FLAG_NEED_WX_GUI, ('wx_gui',)) - check_generate_mode('QT GUI', BLOCK_FLAG_NEED_QT_GUI, ('qt_gui', 'hb_qt_gui')) - if self._epy_reload_error: - self.get_param('_source_code').add_error_message(str(self._epy_reload_error)) - - def rewrite(self): - """ - Add and remove ports to adjust for the nports. - """ - _Block.rewrite(self) - # Check and run any custom rewrite function for this block - getattr(self, 'rewrite_' + self._key, lambda: None)() - - # adjust nports, disconnect hidden ports - for ports in (self.get_sources(), self.get_sinks()): - for i, master_port in enumerate(ports): - nports = master_port.get_nports() or 1 - num_ports = 1 + len(master_port.get_clones()) - if master_port.get_hide(): - for connection in master_port.get_connections(): - self.get_parent().remove_element(connection) - if not nports and num_ports == 1: # not a master port and no left-over clones - continue - # remove excess cloned ports - for port in master_port.get_clones()[nports-1:]: - # remove excess connections - for connection in port.get_connections(): - self.get_parent().remove_element(connection) - master_port.remove_clone(port) - ports.remove(port) - # add more cloned ports - for j in range(num_ports, nports): - port = master_port.add_clone() - ports.insert(ports.index(master_port) + j, port) - - self.back_ofthe_bus(ports) - # renumber non-message/-msg ports - domain_specific_port_index = collections.defaultdict(int) - for port in filter(lambda p: p.get_key().isdigit(), ports): - domain = port.get_domain() - port._key = str(domain_specific_port_index[domain]) - domain_specific_port_index[domain] += 1 - - def port_controller_modify(self, direction): - """ - Change the port controller. - - Args: - direction: +1 or -1 - - Returns: - true for change - """ - changed = False - #concat the nports string from the private nports settings of all ports - nports_str = ' '.join([port._nports for port in self.get_ports()]) - #modify all params whose keys appear in the nports string - for param in self.get_params(): - if param.is_enum() or param.get_key() not in nports_str: continue - #try to increment the port controller by direction - try: - value = param.get_evaluated() - value = value + direction - if 0 < value: - param.set_value(value) - changed = True - except: pass - return changed - - def get_doc(self): - platform = self.get_parent().get_parent() - extracted_docs = platform.block_docstrings.get(self._key, '') - return (self._doc + '\n\n' + extracted_docs).strip() - - def get_category(self): - return _Block.get_category(self) - - def get_imports(self, raw=False): - """ - Resolve all import statements. - Split each import statement at newlines. - Combine all import statments into a list. - Filter empty imports. - - Returns: - a list of import statements - """ - if raw: - return self._imports - return filter(lambda i: i, sum(map(lambda i: self.resolve_dependencies(i).split('\n'), self._imports), [])) - - def get_make(self, raw=False): - if raw: - return self._make - return self.resolve_dependencies(self._make) - - def get_var_make(self): - return self.resolve_dependencies(self._var_make) - - def get_var_value(self): - return self.resolve_dependencies(self._var_value) - - def get_callbacks(self): - """ - Get a list of function callbacks for this block. - - Returns: - a list of strings - """ - def make_callback(callback): - callback = self.resolve_dependencies(callback) - if 'self.' in callback: return callback - return 'self.%s.%s'%(self.get_id(), callback) - return map(make_callback, self._callbacks) - - def is_virtual_sink(self): - return self.get_key() == 'virtual_sink' - - def is_virtual_source(self): - return self.get_key() == 'virtual_source' - - ########################################################################### - # Custom rewrite functions - ########################################################################### - - def rewrite_epy_block(self): - flowgraph = self.get_parent() - platform = flowgraph.get_parent() - param_blk = self.get_param('_io_cache') - param_src = self.get_param('_source_code') - doc_end_tag = 'Block Documentation:' - - src = param_src.get_value() - src_hash = hash((self.get_id(), src)) - if src_hash == self._epy_source_hash: - return - - try: - blk_io = epy_block_io.extract(src) - - except Exception as e: - self._epy_reload_error = ValueError(str(e)) - try: # load last working block io - blk_io = epy_block_io.BlockIO(*eval(param_blk.get_value())) - except: - return - else: - self._epy_reload_error = None # clear previous errors - param_blk.set_value(repr(tuple(blk_io))) - - # print "Rewriting embedded python block {!r}".format(self.get_id()) - self._epy_source_hash = src_hash - self._name = blk_io.name or blk_io.cls - self._doc = self._doc.split(doc_end_tag)[0] + doc_end_tag + '\n' + blk_io.doc - self._imports[0] = 'import ' + self.get_id() - self._make = '{0}.{1}({2})'.format(self.get_id(), blk_io.cls, ', '.join( - '{0}=${0}'.format(key) for key, _ in blk_io.params)) - - params = {} - for param in list(self._params): - if hasattr(param, '__epy_param__'): - params[param.get_key()] = param - self._params.remove(param) - - for key, value in blk_io.params: - try: - param = params[key] - param.set_default(value) - except KeyError: # need to make a new param - name = key.replace('_', ' ').title() - n = odict(dict(name=name, key=key, type='raw', value=value)) - param = platform.Param(block=self, n=n) - setattr(param, '__epy_param__', True) - self._params.append(param) - - def update_ports(label, ports, port_specs, direction): - ports_to_remove = list(ports) - iter_ports = iter(ports) - ports_new = [] - port_current = next(iter_ports, None) - for key, port_type in port_specs: - reuse_port = ( - port_current is not None and - port_current.get_type() == port_type and - (key.isdigit() or port_current.get_key() == key) - ) - if reuse_port: - ports_to_remove.remove(port_current) - port, port_current = port_current, next(iter_ports, None) - else: - n = odict(dict(name=label + str(key), type=port_type, key=key)) - if port_type == 'message': - n['name'] = key - n['optional'] = '1' - port = platform.Port(block=self, n=n, dir=direction) - ports_new.append(port) - # replace old port list with new one - del ports[:] - ports.extend(ports_new) - # remove excess port connections - for port in ports_to_remove: - for connection in port.get_connections(): - flowgraph.remove_element(connection) - - update_ports('in', self.get_sinks(), blk_io.sinks, 'sink') - update_ports('out', self.get_sources(), blk_io.sources, 'source') - _Block.rewrite(self) diff --git a/grc/python/Connection.py b/grc/python/Connection.py deleted file mode 100644 index 822876a0ae..0000000000 --- a/grc/python/Connection.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Copyright 2008-2011 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import Constants -from .. base.Connection import Connection as _Connection -from .. gui.Connection import Connection as _GUIConnection - -class Connection(_Connection, _GUIConnection): - - def __init__(self, **kwargs): - _Connection.__init__(self, **kwargs) - _GUIConnection.__init__(self) - - def is_msg(self): - return self.get_source().get_type() == self.get_sink().get_type() == 'msg' - - def is_bus(self): - return self.get_source().get_type() == self.get_sink().get_type() == 'bus' - - def validate(self): - """ - Validate the connections. - The ports must match in io size. - """ - _Connection.validate(self) - source_size = Constants.TYPE_TO_SIZEOF[self.get_source().get_type()] * self.get_source().get_vlen() - sink_size = Constants.TYPE_TO_SIZEOF[self.get_sink().get_type()] * self.get_sink().get_vlen() - if source_size != sink_size: - self.add_error_message('Source IO size "%s" does not match sink IO size "%s".'%(source_size, sink_size)) diff --git a/grc/python/FlowGraph.py b/grc/python/FlowGraph.py deleted file mode 100644 index b2a1d27859..0000000000 --- a/grc/python/FlowGraph.py +++ /dev/null @@ -1,338 +0,0 @@ -""" -Copyright 2008-2011 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" -import re -import imp -from operator import methodcaller - -from . import expr_utils -from .. base.FlowGraph import FlowGraph as _FlowGraph -from .. gui.FlowGraph import FlowGraph as _GUIFlowGraph - -_variable_matcher = re.compile('^(variable\w*)$') -_parameter_matcher = re.compile('^(parameter)$') -_monitors_searcher = re.compile('(ctrlport_monitor)') -_bussink_searcher = re.compile('^(bus_sink)$') -_bussrc_searcher = re.compile('^(bus_source)$') -_bus_struct_sink_searcher = re.compile('^(bus_structure_sink)$') -_bus_struct_src_searcher = re.compile('^(bus_structure_source)$') - - -class FlowGraph(_FlowGraph, _GUIFlowGraph): - - def __init__(self, **kwargs): - self.grc_file_path = '' - _FlowGraph.__init__(self, **kwargs) - _GUIFlowGraph.__init__(self) - self.n = {} - self.n_hash = -1 - self._renew_eval_ns = True - self._eval_cache = {} - - def _eval(self, code, namespace, namespace_hash): - """ - Evaluate the code with the given namespace. - - Args: - code: a string with python code - namespace: a dict representing the namespace - namespace_hash: a unique hash for the namespace - - Returns: - the resultant object - """ - if not code: raise Exception, 'Cannot evaluate empty statement.' - my_hash = hash(code) ^ namespace_hash - #cache if does not exist - if not self._eval_cache.has_key(my_hash): - self._eval_cache[my_hash] = eval(code, namespace, namespace) - #return from cache - return self._eval_cache[my_hash] - - def get_hier_block_stream_io(self, direction): - """ - Get a list of stream io signatures for this flow graph. - - Args: - direction: a string of 'in' or 'out' - - Returns: - a list of dicts with: type, label, vlen, size, optional - """ - return filter(lambda p: p['type'] != "message", - self.get_hier_block_io(direction)) - - def get_hier_block_message_io(self, direction): - """ - Get a list of message io signatures for this flow graph. - - Args: - direction: a string of 'in' or 'out' - - Returns: - a list of dicts with: type, label, vlen, size, optional - """ - return filter(lambda p: p['type'] == "message", - self.get_hier_block_io(direction)) - - def get_hier_block_io(self, direction): - """ - Get a list of io ports for this flow graph. - - Args: - direction: a string of 'in' or 'out' - - Returns: - a list of dicts with: type, label, vlen, size, optional - """ - pads = self.get_pad_sources() if direction in ('sink', 'in') else \ - self.get_pad_sinks() if direction in ('source', 'out') else [] - ports = [] - for pad in pads: - master = { - 'label': str(pad.get_param('label').get_evaluated()), - 'type': str(pad.get_param('type').get_evaluated()), - 'vlen': str(pad.get_param('vlen').get_value()), - 'size': pad.get_param('type').get_opt('size'), - 'optional': bool(pad.get_param('optional').get_evaluated()), - } - num_ports = pad.get_param('num_streams').get_evaluated() - if num_ports > 1: - for i in xrange(num_ports): - clone = master.copy() - clone['label'] += str(i) - ports.append(clone) - else: - ports.append(master) - return ports - - def get_pad_sources(self): - """ - Get a list of pad source blocks sorted by id order. - - Returns: - a list of pad source blocks in this flow graph - """ - pads = filter(lambda b: b.get_key() == 'pad_source', self.get_enabled_blocks()) - return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id())) - - def get_pad_sinks(self): - """ - Get a list of pad sink blocks sorted by id order. - - Returns: - a list of pad sink blocks in this flow graph - """ - pads = filter(lambda b: b.get_key() == 'pad_sink', self.get_enabled_blocks()) - return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id())) - - def get_pad_port_global_key(self, port): - """ - Get the key for a port of a pad source/sink to use in connect() - This takes into account that pad blocks may have multiple ports - - Returns: - the key (str) - """ - key_offset = 0 - pads = self.get_pad_sources() if port.is_source() else self.get_pad_sinks() - for pad in pads: - # using the block param 'type' instead of the port domain here - # to emphasize that hier block generation is domain agnostic - is_message_pad = pad.get_param('type').get_evaluated() == "message" - if port.get_parent() == pad: - if is_message_pad: - key = pad.get_param('label').get_value() - else: - key = str(key_offset + int(port.get_key())) - return key - else: - # assuming we have either only sources or sinks - if not is_message_pad: - key_offset += len(pad.get_ports()) - return -1 - - def get_imports(self): - """ - Get a set of all import statments in this flow graph namespace. - - Returns: - a set of import statements - """ - imports = sum([block.get_imports() for block in self.get_enabled_blocks()], []) - imports = sorted(set(imports)) - return imports - - def get_variables(self): - """ - Get a list of all variables in this flow graph namespace. - Exclude paramterized variables. - - Returns: - a sorted list of variable blocks in order of dependency (indep -> dep) - """ - variables = filter(lambda b: _variable_matcher.match(b.get_key()), self.iter_enabled_blocks()) - return expr_utils.sort_objects(variables, methodcaller('get_id'), methodcaller('get_var_make')) - - def get_parameters(self): - """ - Get a list of all paramterized variables in this flow graph namespace. - - Returns: - a list of paramterized variables - """ - parameters = filter(lambda b: _parameter_matcher.match(b.get_key()), self.iter_enabled_blocks()) - return parameters - - def get_monitors(self): - """ - Get a list of all ControlPort monitors - """ - monitors = filter(lambda b: _monitors_searcher.search(b.get_key()), - self.iter_enabled_blocks()) - return monitors - - def get_python_modules(self): - """Iterate over custom code block ID and Source""" - for block in self.iter_enabled_blocks(): - if block.get_key() == 'epy_module': - yield block.get_id(), block.get_param('source_code').get_value() - - def get_bussink(self): - bussink = filter(lambda b: _bussink_searcher.search(b.get_key()), self.get_enabled_blocks()) - - for i in bussink: - for j in i.get_params(): - if j.get_name() == 'On/Off' and j.get_value() == 'on': - return True; - - return False - - def get_bussrc(self): - bussrc = filter(lambda b: _bussrc_searcher.search(b.get_key()), self.get_enabled_blocks()) - - for i in bussrc: - for j in i.get_params(): - if j.get_name() == 'On/Off' and j.get_value() == 'on': - return True; - - return False - - def get_bus_structure_sink(self): - bussink = filter(lambda b: _bus_struct_sink_searcher.search(b.get_key()), self.get_enabled_blocks()) - - return bussink - - def get_bus_structure_src(self): - bussrc = filter(lambda b: _bus_struct_src_searcher.search(b.get_key()), self.get_enabled_blocks()) - - return bussrc - - def rewrite(self): - """ - Flag the namespace to be renewed. - """ - def reconnect_bus_blocks(): - for block in self.get_blocks(): - - if 'bus' in map(lambda a: a.get_type(), block.get_sources_gui()): - - - for i in range(len(block.get_sources_gui())): - if len(block.get_sources_gui()[i].get_connections()) > 0: - source = block.get_sources_gui()[i] - sink = [] - - for j in range(len(source.get_connections())): - sink.append(source.get_connections()[j].get_sink()); - - - for elt in source.get_connections(): - self.remove_element(elt); - for j in sink: - self.connect(source, j); - self._renew_eval_ns = True - _FlowGraph.rewrite(self); - reconnect_bus_blocks(); - - def evaluate(self, expr): - """ - Evaluate the expression. - - Args: - expr: the string expression - @throw Exception bad expression - - Returns: - the evaluated data - """ - if self._renew_eval_ns: - self._renew_eval_ns = False - #reload namespace - n = dict() - #load imports - for code in self.get_imports(): - try: exec code in n - except: pass - - for id, code in self.get_python_modules(): - try: - module = imp.new_module(id) - exec code in module.__dict__ - n[id] = module - except: - pass - - #load parameters - np = dict() - for parameter in self.get_parameters(): - try: - e = eval(parameter.get_param('value').to_code(), n, n) - np[parameter.get_id()] = e - except: pass - n.update(np) #merge param namespace - #load variables - for variable in self.get_variables(): - try: - e = eval(variable.get_var_value(), n, n) - n[variable.get_id()] = e - except: pass - #make namespace public - self.n = n - self.n_hash = hash(str(n)) - #evaluate - e = self._eval(expr, self.n, self.n_hash) - return e - - def get_new_block(self, key): - """Try to auto-generate the block from file if missing""" - block = _FlowGraph.get_new_block(self, key) - if not block: - platform = self.get_parent() - # we're before the initial fg rewrite(), so no evaluated values! - # --> use raw value instead - path_param = self._options_block.get_param('hier_block_src_path') - file_path = platform.find_file_in_paths( - filename=key + '.' + platform.get_key(), - paths=path_param.get_value(), - cwd=self.grc_file_path - ) - if file_path: # grc file found. load and get block - platform.load_and_generate_flow_graph(file_path) - block = _FlowGraph.get_new_block(self, key) # can be None - return block diff --git a/grc/python/Param.py b/grc/python/Param.py deleted file mode 100644 index e60f613f00..0000000000 --- a/grc/python/Param.py +++ /dev/null @@ -1,433 +0,0 @@ -""" -Copyright 2008-2011 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import ast -import re - -from gnuradio import gr - -from .. base.Param import Param as _Param -from .. gui.Param import Param as _GUIParam - -import Constants -from Constants import VECTOR_TYPES, COMPLEX_TYPES, REAL_TYPES, INT_TYPES - -from gnuradio import eng_notation - -_check_id_matcher = re.compile('^[a-z|A-Z]\w*$') -_show_id_matcher = re.compile('^(variable\w*|parameter|options|notebook|epy_module)$') - - -#blacklist certain ids, its not complete, but should help -import __builtin__ -ID_BLACKLIST = ['self', 'options', 'gr', 'blks2', 'wxgui', 'wx', 'math', 'forms', 'firdes'] + \ - filter(lambda x: not x.startswith('_'), dir(gr.top_block())) + dir(__builtin__) - - -def num_to_str(num): - """ Display logic for numbers """ - if isinstance(num, COMPLEX_TYPES): - num = complex(num) #cast to python complex - if num == 0: return '0' #value is zero - elif num.imag == 0: return '%s'%eng_notation.num_to_str(num.real) #value is real - elif num.real == 0: return '%sj'%eng_notation.num_to_str(num.imag) #value is imaginary - elif num.imag < 0: return '%s-%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(abs(num.imag))) - else: return '%s+%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(num.imag)) - else: return str(num) - - -class Param(_Param, _GUIParam): - - def __init__(self, **kwargs): - _Param.__init__(self, **kwargs) - _GUIParam.__init__(self) - self._init = False - self._hostage_cells = list() - - def get_types(self): return ( - 'raw', 'enum', - 'complex', 'real', 'float', 'int', - 'complex_vector', 'real_vector', 'float_vector', 'int_vector', - 'hex', 'string', 'bool', - 'file_open', 'file_save', '_multiline', '_multiline_python_external', - 'id', 'stream_id', - 'grid_pos', 'notebook', 'gui_hint', - 'import', - ) - - def __repr__(self): - """ - Get the repr (nice string format) for this param. - - Returns: - the string representation - """ - ################################################## - # truncate helper method - ################################################## - def _truncate(string, style=0): - max_len = max(27 - len(self.get_name()), 3) - if len(string) > max_len: - if style < 0: #front truncate - string = '...' + string[3-max_len:] - elif style == 0: #center truncate - string = string[:max_len/2 -3] + '...' + string[-max_len/2:] - elif style > 0: #rear truncate - string = string[:max_len-3] + '...' - return string - ################################################## - # simple conditions - ################################################## - if not self.is_valid(): return _truncate(self.get_value()) - if self.get_value() in self.get_option_keys(): return self.get_option(self.get_value()).get_name() - - ################################################## - # split up formatting by type - ################################################## - truncate = 0 #default center truncate - e = self.get_evaluated() - t = self.get_type() - if isinstance(e, bool): return str(e) - elif isinstance(e, COMPLEX_TYPES): dt_str = num_to_str(e) - elif isinstance(e, VECTOR_TYPES): #vector types - if len(e) > 8: - dt_str = self.get_value() #large vectors use code - truncate = 1 - else: dt_str = ', '.join(map(num_to_str, e)) #small vectors use eval - elif t in ('file_open', 'file_save'): - dt_str = self.get_value() - truncate = -1 - else: dt_str = str(e) #other types - ################################################## - # done - ################################################## - return _truncate(dt_str, truncate) - - def get_color(self): - """ - Get the color that represents this param's type. - - Returns: - a hex color code. - """ - try: - return { - #number types - 'complex': Constants.COMPLEX_COLOR_SPEC, - 'real': Constants.FLOAT_COLOR_SPEC, - 'float': Constants.FLOAT_COLOR_SPEC, - 'int': Constants.INT_COLOR_SPEC, - #vector types - 'complex_vector': Constants.COMPLEX_VECTOR_COLOR_SPEC, - 'real_vector': Constants.FLOAT_VECTOR_COLOR_SPEC, - 'float_vector': Constants.FLOAT_VECTOR_COLOR_SPEC, - 'int_vector': Constants.INT_VECTOR_COLOR_SPEC, - #special - 'bool': Constants.INT_COLOR_SPEC, - 'hex': Constants.INT_COLOR_SPEC, - 'string': Constants.BYTE_VECTOR_COLOR_SPEC, - 'id': Constants.ID_COLOR_SPEC, - 'stream_id': Constants.ID_COLOR_SPEC, - 'grid_pos': Constants.INT_VECTOR_COLOR_SPEC, - 'notebook': Constants.INT_VECTOR_COLOR_SPEC, - 'raw': Constants.WILDCARD_COLOR_SPEC, - }[self.get_type()] - except: return _Param.get_color(self) - - def get_hide(self): - """ - Get the hide value from the base class. - Hide the ID parameter for most blocks. Exceptions below. - If the parameter controls a port type, vlen, or nports, return part. - If the parameter is an empty grid position, return part. - These parameters are redundant to display in the flow graph view. - - Returns: - hide the hide property string - """ - hide = _Param.get_hide(self) - if hide: return hide - #hide ID in non variable blocks - if self.get_key() == 'id' and not _show_id_matcher.match(self.get_parent().get_key()): return 'part' - #hide port controllers for type and nports - if self.get_key() in ' '.join(map( - lambda p: ' '.join([p._type, p._nports]), self.get_parent().get_ports()) - ): return 'part' - #hide port controllers for vlen, when == 1 - if self.get_key() in ' '.join(map( - lambda p: p._vlen, self.get_parent().get_ports()) - ): - try: - if int(self.get_evaluated()) == 1: return 'part' - except: pass - #hide empty grid positions - if self.get_key() in ('grid_pos', 'notebook') and not self.get_value(): return 'part' - return hide - - def validate(self): - """ - Validate the param. - A test evaluation is performed - """ - _Param.validate(self) #checks type - self._evaluated = None - try: self._evaluated = self.evaluate() - except Exception, e: self.add_error_message(str(e)) - - def get_evaluated(self): return self._evaluated - - def evaluate(self): - """ - Evaluate the value. - - Returns: - evaluated type - """ - self._init = True - self._lisitify_flag = False - self._stringify_flag = False - self._hostage_cells = list() - t = self.get_type() - v = self.get_value() - ######################### - # Enum Type - ######################### - if self.is_enum(): return v - ######################### - # Numeric Types - ######################### - elif t in ('raw', 'complex', 'real', 'float', 'int', 'hex', 'bool'): - #raise exception if python cannot evaluate this value - try: e = self.get_parent().get_parent().evaluate(v) - except Exception, e: raise Exception, 'Value "%s" cannot be evaluated:\n%s'%(v, e) - #raise an exception if the data is invalid - if t == 'raw': return e - elif t == 'complex': - if not isinstance(e, COMPLEX_TYPES): - raise Exception, 'Expression "%s" is invalid for type complex.'%str(e) - return e - elif t == 'real' or t == 'float': - if not isinstance(e, REAL_TYPES): - raise Exception, 'Expression "%s" is invalid for type float.'%str(e) - return e - elif t == 'int': - if not isinstance(e, INT_TYPES): - raise Exception, 'Expression "%s" is invalid for type integer.'%str(e) - return e - elif t == 'hex': return hex(e) - elif t == 'bool': - if not isinstance(e, bool): - raise Exception, 'Expression "%s" is invalid for type bool.'%str(e) - return e - else: raise TypeError, 'Type "%s" not handled'%t - ######################### - # Numeric Vector Types - ######################### - elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'): - if not v: v = '()' #turn a blank string into an empty list, so it will eval - #raise exception if python cannot evaluate this value - try: e = self.get_parent().get_parent().evaluate(v) - except Exception, e: raise Exception, 'Value "%s" cannot be evaluated:\n%s'%(v, e) - #raise an exception if the data is invalid - if t == 'complex_vector': - if not isinstance(e, VECTOR_TYPES): - self._lisitify_flag = True - e = [e] - if not all([isinstance(ei, COMPLEX_TYPES) for ei in e]): - raise Exception, 'Expression "%s" is invalid for type complex vector.'%str(e) - return e - elif t == 'real_vector' or t == 'float_vector': - if not isinstance(e, VECTOR_TYPES): - self._lisitify_flag = True - e = [e] - if not all([isinstance(ei, REAL_TYPES) for ei in e]): - raise Exception, 'Expression "%s" is invalid for type float vector.'%str(e) - return e - elif t == 'int_vector': - if not isinstance(e, VECTOR_TYPES): - self._lisitify_flag = True - e = [e] - if not all([isinstance(ei, INT_TYPES) for ei in e]): - raise Exception, 'Expression "%s" is invalid for type integer vector.'%str(e) - return e - ######################### - # String Types - ######################### - elif t in ('string', 'file_open', 'file_save', '_multiline', '_multiline_python_external'): - #do not check if file/directory exists, that is a runtime issue - try: - e = self.get_parent().get_parent().evaluate(v) - if not isinstance(e, str): - raise Exception() - except: - self._stringify_flag = True - e = str(v) - if t == '_multiline_python_external': - ast.parse(e) # raises SyntaxError - return e - ######################### - # Unique ID Type - ######################### - elif t == 'id': - #can python use this as a variable? - if not _check_id_matcher.match(v): - raise Exception, 'ID "%s" must begin with a letter and may contain letters, numbers, and underscores.'%v - ids = [param.get_value() for param in self.get_all_params(t)] - if ids.count(v) > 1: #id should only appear once, or zero times if block is disabled - raise Exception, 'ID "%s" is not unique.'%v - if v in ID_BLACKLIST: - raise Exception, 'ID "%s" is blacklisted.'%v - return v - ######################### - # Stream ID Type - ######################### - elif t == 'stream_id': - #get a list of all stream ids used in the virtual sinks - ids = [param.get_value() for param in filter( - lambda p: p.get_parent().is_virtual_sink(), - self.get_all_params(t), - )] - #check that the virtual sink's stream id is unique - if self.get_parent().is_virtual_sink(): - if ids.count(v) > 1: #id should only appear once, or zero times if block is disabled - raise Exception, 'Stream ID "%s" is not unique.'%v - #check that the virtual source's steam id is found - if self.get_parent().is_virtual_source(): - if v not in ids: - raise Exception, 'Stream ID "%s" is not found.'%v - return v - ######################### - # 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('@') - else: index = '?' - - 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 and 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) - ######################### - # Grid Position Type - ######################### - elif t == 'grid_pos': - if not v: return '' #allow for empty grid pos - e = self.get_parent().get_parent().evaluate(v) - if not isinstance(e, (list, tuple)) or len(e) != 4 or not all([isinstance(ei, int) for ei in e]): - raise Exception, 'A grid position must be a list of 4 integers.' - row, col, row_span, col_span = e - #check row, col - if row < 0 or col < 0: - raise Exception, 'Row and column must be non-negative.' - #check row span, col span - if row_span <= 0 or col_span <= 0: - raise Exception, 'Row and column span must be greater than zero.' - #get hostage cell parent - try: my_parent = self.get_parent().get_param('notebook').evaluate() - except: my_parent = '' - #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))) - #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: - raise Exception, 'Another graphical element is using parent "%s", cell "%s".'%(str(parent), str(cell)) - return e - ######################### - # Notebook Page Type - ######################### - elif t == 'notebook': - if not v: return '' #allow for empty notebook - #get a list of all notebooks - notebook_blocks = filter(lambda b: b.get_key() == 'notebook', self.get_parent().get_parent().get_enabled_blocks()) - #check for notebook param syntax - try: notebook_id, page_index = map(str.strip, v.split(',')) - except: raise Exception, 'Bad notebook page format.' - #check that the notebook id is valid - try: notebook_block = filter(lambda b: b.get_id() == notebook_id, notebook_blocks)[0] - except: raise Exception, 'Notebook id "%s" is not an existing notebook id.'%notebook_id - #check that page index exists - if int(page_index) not in range(len(notebook_block.get_param('labels').evaluate())): - raise Exception, 'Page index "%s" is not a valid index number.'%page_index - return notebook_id, page_index - ######################### - # Import Type - ######################### - elif t == 'import': - n = dict() #new namespace - try: exec v in n - except ImportError: raise Exception, 'Import "%s" failed.'%v - except Exception: raise Exception, 'Bad import syntax: "%s".'%v - return filter(lambda k: str(k) != '__builtins__', n.keys()) - ######################### - else: raise TypeError, 'Type "%s" not handled'%t - - def to_code(self): - """ - Convert the value to code. - For string and list types, check the init flag, call evaluate(). - This ensures that evaluate() was called to set the xxxify_flags. - - Returns: - a string representing the code - """ - v = self.get_value() - t = self.get_type() - if t in ('string', 'file_open', 'file_save', '_multiline', '_multiline_python_external'): # string types - if not self._init: self.evaluate() - if self._stringify_flag: return '"%s"'%v.replace('"', '\"') - else: return v - elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'): #vector types - if not self._init: self.evaluate() - if self._lisitify_flag: return '(%s, )'%v - else: return '(%s)'%v - else: return v - - def get_all_params(self, type): - """ - Get all the params from the flowgraph that have the given type. - - Args: - type: the specified type - - Returns: - a list of params - """ - return sum([filter(lambda p: p.get_type() == type, block.get_params()) for block in self.get_parent().get_parent().get_enabled_blocks()], []) diff --git a/grc/python/Platform.py b/grc/python/Platform.py deleted file mode 100644 index 2a0bbf9a9e..0000000000 --- a/grc/python/Platform.py +++ /dev/null @@ -1,174 +0,0 @@ -""" -Copyright 2008-2016 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import os -import sys - -from gnuradio import gr - -from .. base.Platform import Platform as _Platform -from .. gui.Platform import Platform as _GUIPlatform -from .. gui import Messages - -from . import extract_docs -from .FlowGraph import FlowGraph as _FlowGraph -from .Connection import Connection as _Connection -from .Block import Block as _Block -from .Port import Port as _Port -from .Param import Param as _Param -from .Generator import Generator -from .Constants import ( - HIER_BLOCKS_LIB_DIR, BLOCK_DTD, DEFAULT_FLOW_GRAPH, BLOCKS_DIRS, - PREFS_FILE, PREFS_FILE_OLD, CORE_TYPES -) - -COLORS = [(name, color) for name, key, sizeof, color in CORE_TYPES] - - -class Platform(_Platform, _GUIPlatform): - def __init__(self): - """ - Make a platform for gnuradio. - """ - # ensure hier and conf directories - if not os.path.exists(HIER_BLOCKS_LIB_DIR): - os.mkdir(HIER_BLOCKS_LIB_DIR) - if not os.path.exists(os.path.dirname(PREFS_FILE)): - os.mkdir(os.path.dirname(PREFS_FILE)) - - self.block_docstrings = block_docstrings = dict() - self.block_docstrings_loaded_callback = lambda: None - - def setter(key, docs): - block_docstrings[key] = '\n\n'.join( - '--- {0} ---\n{1}\n'.format(b, d.replace('\n\n', '\n')) - for b, d in docs.iteritems() if d is not None - ) - - self._docstring_extractor = extract_docs.SubprocessLoader( - callback_query_result=setter, - callback_finished=lambda: self.block_docstrings_loaded_callback() - ) - - # init - _Platform.__init__( - self, - name='GNU Radio Companion', - version=(gr.version(), gr.major_version(), gr.api_version(), gr.minor_version()), - key='grc', - license=__doc__.strip(), - website='http://gnuradio.org/', - block_paths=BLOCKS_DIRS, - block_dtd=BLOCK_DTD, - default_flow_graph=DEFAULT_FLOW_GRAPH, - generator=Generator, - colors=COLORS, - ) - self._move_old_pref_file() - _GUIPlatform.__init__( - self, - prefs_file=PREFS_FILE - ) - self._auto_hier_block_generate_chain = set() - - @staticmethod - def _move_old_pref_file(): - if PREFS_FILE == PREFS_FILE_OLD: - return # prefs file overridden with env var - if os.path.exists(PREFS_FILE_OLD) and not os.path.exists(PREFS_FILE): - try: - import shutil - shutil.move(PREFS_FILE_OLD, PREFS_FILE) - except Exception as e: - print >> sys.stderr, e - - def load_blocks(self): - self._docstring_extractor.start() - _Platform.load_blocks(self) - self._docstring_extractor.finish() - # self._docstring_extractor.wait() - - def load_block_xml(self, xml_file): - block = _Platform.load_block_xml(self, xml_file) - self._docstring_extractor.query( - block.get_key(), - block.get_imports(raw=True), - block.get_make(raw=True) - ) - return block - - @staticmethod - def find_file_in_paths(filename, paths, cwd): - """Checks the provided paths relative to cwd for a certain filename""" - if not os.path.isdir(cwd): - cwd = os.path.dirname(cwd) - if isinstance(paths, str): - paths = (p for p in paths.split(':') if p) - - for path in paths: - path = os.path.expanduser(path) - if not os.path.isabs(path): - path = os.path.normpath(os.path.join(cwd, path)) - file_path = os.path.join(path, filename) - if os.path.exists(os.path.normpath(file_path)): - return file_path - - def load_and_generate_flow_graph(self, file_path): - """Loads a flowgraph from file and generates it""" - Messages.set_indent(len(self._auto_hier_block_generate_chain)) - Messages.send('>>> Loading: %r\n' % file_path) - if file_path in self._auto_hier_block_generate_chain: - Messages.send(' >>> Warning: cyclic hier_block dependency\n') - return False - self._auto_hier_block_generate_chain.add(file_path) - try: - flow_graph = self.get_new_flow_graph() - flow_graph.grc_file_path = file_path - # other, nested higiter_blocks might be auto-loaded here - flow_graph.import_data(self.parse_flow_graph(file_path)) - flow_graph.rewrite() - flow_graph.validate() - if not flow_graph.is_valid(): - raise Exception('Flowgraph invalid') - except Exception as e: - Messages.send('>>> Load Error: %r: %s\n' % (file_path, str(e))) - return False - finally: - self._auto_hier_block_generate_chain.discard(file_path) - Messages.set_indent(len(self._auto_hier_block_generate_chain)) - - try: - Messages.send('>>> Generating: %r\n' % file_path) - generator = self.get_generator()(flow_graph, file_path) - generator.write() - except Exception as e: - Messages.send('>>> Generate Error: %r: %s\n' % (file_path, str(e))) - return False - - self.load_block_xml(generator.get_file_path_xml()) - return True - - ############################################## - # Constructors - ############################################## - FlowGraph = _FlowGraph - Connection = _Connection - Block = _Block - Port = _Port - Param = _Param diff --git a/grc/python/Port.py b/grc/python/Port.py deleted file mode 100644 index 249d7aed71..0000000000 --- a/grc/python/Port.py +++ /dev/null @@ -1,268 +0,0 @@ -""" -Copyright 2008-2012 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from .. base.Port import Port as _Port -from .. base.Constants import DEFAULT_DOMAIN, GR_MESSAGE_DOMAIN -from .. gui.Port import Port as _GUIPort -import Constants - - -def _get_source_from_virtual_sink_port(vsp): - """ - Resolve the source port that is connected to the given virtual sink port. - Use the get source from virtual source to recursively resolve subsequent ports. - """ - try: return _get_source_from_virtual_source_port( - vsp.get_enabled_connections()[0].get_source()) - except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp - -def _get_source_from_virtual_source_port(vsp, traversed=[]): - """ - Recursively resolve source ports over the virtual connections. - Keep track of traversed sources to avoid recursive loops. - """ - if not vsp.get_parent().is_virtual_source(): return vsp - if vsp in traversed: raise Exception, 'Loop found when resolving virtual source %s'%vsp - try: return _get_source_from_virtual_source_port( - _get_source_from_virtual_sink_port( - filter(#get all virtual sinks with a matching stream id - lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(), - filter(#get all enabled blocks that are also virtual sinks - lambda b: b.is_virtual_sink(), - vsp.get_parent().get_parent().get_enabled_blocks(), - ), - )[0].get_sinks()[0] - ), traversed + [vsp], - ) - except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp - -def _get_sink_from_virtual_source_port(vsp): - """ - Resolve the sink port that is connected to the given virtual source port. - Use the get sink from virtual sink to recursively resolve subsequent ports. - """ - try: return _get_sink_from_virtual_sink_port( - vsp.get_enabled_connections()[0].get_sink()) # Could have many connections, but use first - except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp - -def _get_sink_from_virtual_sink_port(vsp, traversed=[]): - """ - Recursively resolve sink ports over the virtual connections. - Keep track of traversed sinks to avoid recursive loops. - """ - if not vsp.get_parent().is_virtual_sink(): return vsp - if vsp in traversed: raise Exception, 'Loop found when resolving virtual sink %s'%vsp - try: return _get_sink_from_virtual_sink_port( - _get_sink_from_virtual_source_port( - filter(#get all virtual source with a matching stream id - lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(), - filter(#get all enabled blocks that are also virtual sinks - lambda b: b.is_virtual_source(), - vsp.get_parent().get_parent().get_enabled_blocks(), - ), - )[0].get_sources()[0] - ), traversed + [vsp], - ) - except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp - -class Port(_Port, _GUIPort): - - def __init__(self, block, n, dir): - """ - Make a new port from nested data. - - Args: - block: the parent element - n: the nested odict - dir: the direction - """ - self._n = n - if n['type'] == 'message': - n['domain'] = GR_MESSAGE_DOMAIN - if 'domain' not in n: - n['domain'] = DEFAULT_DOMAIN - elif n['domain'] == GR_MESSAGE_DOMAIN: - n['key'] = n['name'] - n['type'] = 'message' # for port color - if n['type'] == 'msg': - n['key'] = 'msg' - if not n.find('key'): - n['key'] = str(next(block.port_counters[dir == 'source'])) - # build the port - _Port.__init__( - self, - block=block, - n=n, - dir=dir, - ) - _GUIPort.__init__(self) - self._nports = n.find('nports') or '' - self._vlen = n.find('vlen') or '' - self._optional = bool(n.find('optional')) - self._clones = [] # references to cloned ports (for nports > 1) - - def get_types(self): return Constants.TYPE_TO_SIZEOF.keys() - - def is_type_empty(self): return not self._n['type'] - - def validate(self): - _Port.validate(self) - if not self.get_enabled_connections() and not self.get_optional(): - self.add_error_message('Port is not connected.') - #message port logic - if self.get_type() == 'msg': - if self.get_nports(): - self.add_error_message('A port of type "msg" cannot have "nports" set.') - if self.get_vlen() != 1: - self.add_error_message('A port of type "msg" must have a "vlen" of 1.') - - def rewrite(self): - """ - Handle the port cloning for virtual blocks. - """ - if self.is_type_empty(): - try: #clone type and vlen - source = self.resolve_empty_type() - self._type = str(source.get_type()) - self._vlen = str(source.get_vlen()) - except: #reset type and vlen - self._type = '' - self._vlen = '' - _Port.rewrite(self) - - def resolve_virtual_source(self): - if self.get_parent().is_virtual_sink(): return _get_source_from_virtual_sink_port(self) - if self.get_parent().is_virtual_source(): return _get_source_from_virtual_source_port(self) - - def resolve_empty_type(self): - if self.is_sink(): - try: - src = _get_source_from_virtual_sink_port(self) - if not src.is_type_empty(): return src - except: pass - sink = _get_sink_from_virtual_sink_port(self) - if not sink.is_type_empty(): return sink - if self.is_source(): - try: - src = _get_source_from_virtual_source_port(self) - if not src.is_type_empty(): return src - except: pass - sink = _get_sink_from_virtual_source_port(self) - if not sink.is_type_empty(): return sink - - def get_vlen(self): - """ - Get the vector length. - If the evaluation of vlen cannot be cast to an integer, return 1. - - Returns: - the vector length or 1 - """ - vlen = self.get_parent().resolve_dependencies(self._vlen) - try: return int(self.get_parent().get_parent().evaluate(vlen)) - except: return 1 - - def get_nports(self): - """ - Get the number of ports. - If already blank, return a blank - If the evaluation of nports cannot be cast to a positive integer, return 1. - - Returns: - the number of ports or 1 - """ - if self._nports == '': return '' - - nports = self.get_parent().resolve_dependencies(self._nports) - try: - return max(1, int(self.get_parent().get_parent().evaluate(nports))) - except: - return 1 - - def get_optional(self): return bool(self._optional) - - def get_color(self): - """ - Get the color that represents this port's type. - Codes differ for ports where the vec length is 1 or greater than 1. - - Returns: - a hex color code. - """ - try: - color = Constants.TYPE_TO_COLOR[self.get_type()] - vlen = self.get_vlen() - if vlen == 1: return color - color_val = int(color[1:], 16) - r = (color_val >> 16) & 0xff - g = (color_val >> 8) & 0xff - b = (color_val >> 0) & 0xff - dark = (0, 0, 30, 50, 70)[min(4, vlen)] - r = max(r-dark, 0) - g = max(g-dark, 0) - b = max(b-dark, 0) - return '#%.2x%.2x%.2x'%(r, g, b) - except: return _Port.get_color(self) - - def get_clones(self): - """ - Get the clones of this master port (nports > 1) - - Returns: - a list of ports - """ - return self._clones - - def add_clone(self): - """ - Create a clone of this (master) port and store a reference in self._clones. - - The new port name (and key for message ports) will have index 1... appended. - If this is the first clone, this (master) port will get a 0 appended to its name (and key) - - Returns: - the cloned port - """ - # add index to master port name if there are no clones yet - if not self._clones: - self._name = self._n['name'] + '0' - if not self._key.isdigit(): # also update key for none stream ports - self._key = self._name - - # Prepare a copy of the odict for the clone - n = self._n.copy() - if 'nports' in n: n.pop('nports') # remove nports from the key so the copy cannot be a duplicator - n['name'] = self._n['name'] + str(len(self._clones) + 1) - n['key'] = '99999' if self._key.isdigit() else n['name'] # dummy value 99999 will be fixed later - - port = self.__class__(self.get_parent(), n, self._dir) # clone - self._clones.append(port) - return port - - def remove_clone(self, port): - """ - Remove a cloned port (from the list of clones only) - Remove the index 0 of the master port name (and key9 if there are no more clones left - """ - self._clones.remove(port) - # remove index from master port name if there are no more clones - if not self._clones: - self._name = self._n['name'] - if not self._key.isdigit(): # also update key for none stream ports - self._key = self._name diff --git a/grc/scripts/CMakeLists.txt b/grc/scripts/CMakeLists.txt index e905892308..6cc78c3cf3 100644 --- a/grc/scripts/CMakeLists.txt +++ b/grc/scripts/CMakeLists.txt @@ -23,3 +23,5 @@ GR_PYTHON_INSTALL( DESTINATION ${GR_RUNTIME_DIR} COMPONENT "grc" ) + +add_subdirectory(freedesktop) diff --git a/grc/freedesktop/CMakeLists.txt b/grc/scripts/freedesktop/CMakeLists.txt index 47e836f697..47e836f697 100644 --- a/grc/freedesktop/CMakeLists.txt +++ b/grc/scripts/freedesktop/CMakeLists.txt diff --git a/grc/freedesktop/README b/grc/scripts/freedesktop/README index 0857ecc224..0857ecc224 100644 --- a/grc/freedesktop/README +++ b/grc/scripts/freedesktop/README diff --git a/grc/freedesktop/convert.sh b/grc/scripts/freedesktop/convert.sh index e2cba264a6..e2cba264a6 100755 --- a/grc/freedesktop/convert.sh +++ b/grc/scripts/freedesktop/convert.sh diff --git a/grc/freedesktop/gnuradio-grc.desktop b/grc/scripts/freedesktop/gnuradio-grc.desktop index 39beeca1b8..39beeca1b8 100644 --- a/grc/freedesktop/gnuradio-grc.desktop +++ b/grc/scripts/freedesktop/gnuradio-grc.desktop diff --git a/grc/freedesktop/gnuradio-grc.xml b/grc/scripts/freedesktop/gnuradio-grc.xml index a5cb95d9fd..a5cb95d9fd 100644 --- a/grc/freedesktop/gnuradio-grc.xml +++ b/grc/scripts/freedesktop/gnuradio-grc.xml diff --git a/grc/freedesktop/gnuradio_logo_icon-square.svg b/grc/scripts/freedesktop/gnuradio_logo_icon-square.svg index 3b54bf4001..3b54bf4001 100644 --- a/grc/freedesktop/gnuradio_logo_icon-square.svg +++ b/grc/scripts/freedesktop/gnuradio_logo_icon-square.svg diff --git a/grc/freedesktop/grc-icon-128.png b/grc/scripts/freedesktop/grc-icon-128.png Binary files differindex 13efe806ba..13efe806ba 100644 --- a/grc/freedesktop/grc-icon-128.png +++ b/grc/scripts/freedesktop/grc-icon-128.png diff --git a/grc/freedesktop/grc-icon-16.png b/grc/scripts/freedesktop/grc-icon-16.png Binary files differindex bdd1823b3d..bdd1823b3d 100644 --- a/grc/freedesktop/grc-icon-16.png +++ b/grc/scripts/freedesktop/grc-icon-16.png diff --git a/grc/freedesktop/grc-icon-24.png b/grc/scripts/freedesktop/grc-icon-24.png Binary files differindex a124768125..a124768125 100644 --- a/grc/freedesktop/grc-icon-24.png +++ b/grc/scripts/freedesktop/grc-icon-24.png diff --git a/grc/freedesktop/grc-icon-256.png b/grc/scripts/freedesktop/grc-icon-256.png Binary files differindex 077688eac5..077688eac5 100644 --- a/grc/freedesktop/grc-icon-256.png +++ b/grc/scripts/freedesktop/grc-icon-256.png diff --git a/grc/freedesktop/grc-icon-32.png b/grc/scripts/freedesktop/grc-icon-32.png Binary files differindex a345aace3c..a345aace3c 100644 --- a/grc/freedesktop/grc-icon-32.png +++ b/grc/scripts/freedesktop/grc-icon-32.png diff --git a/grc/freedesktop/grc-icon-48.png b/grc/scripts/freedesktop/grc-icon-48.png Binary files differindex c522a5d0ec..c522a5d0ec 100644 --- a/grc/freedesktop/grc-icon-48.png +++ b/grc/scripts/freedesktop/grc-icon-48.png diff --git a/grc/freedesktop/grc-icon-64.png b/grc/scripts/freedesktop/grc-icon-64.png Binary files differindex df4f6dc07b..df4f6dc07b 100644 --- a/grc/freedesktop/grc-icon-64.png +++ b/grc/scripts/freedesktop/grc-icon-64.png diff --git a/grc/freedesktop/grc_setup_freedesktop.in b/grc/scripts/freedesktop/grc_setup_freedesktop.in index 87a388e2ec..87a388e2ec 100644 --- a/grc/freedesktop/grc_setup_freedesktop.in +++ b/grc/scripts/freedesktop/grc_setup_freedesktop.in diff --git a/grc/scripts/gnuradio-companion b/grc/scripts/gnuradio-companion index 203a8c773d..04a1cb44e7 100755 --- a/grc/scripts/gnuradio-companion +++ b/grc/scripts/gnuradio-companion @@ -1,6 +1,6 @@ #!/usr/bin/env python """ -Copyright 2009-2015 Free Software Foundation, Inc. +Copyright 2016 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -20,111 +20,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import os import sys -import optparse -import warnings - -GR_IMPORT_ERROR_MESSAGE = """\ -Cannot import gnuradio. - -Is the python path environment variable set correctly? - All OS: PYTHONPATH - -Is the library path environment variable set correctly? - Linux: LD_LIBRARY_PATH - Windows: PATH - MacOSX: DYLD_LIBRARY_PATH -""" - -VERSION_AND_DISCLAIMER_TEMPLATE = """\ -GNU Radio Companion %s - -This program is part of GNU Radio -GRC comes with ABSOLUTELY NO WARRANTY. -This is free software, and you are welcome to redistribute it. -""" - - -def die(error, message): - msg = "{0}\n\n({1})".format(message, error) - try: - import gtk - d = gtk.MessageDialog( - type=gtk.MESSAGE_ERROR, - buttons=gtk.BUTTONS_CLOSE, - message_format=msg, - ) - d.set_title(type(error).__name__) - d.run() - exit(1) - except ImportError: - exit(type(error).__name__ + '\n\n' + msg) - - -def check_gtk(): - try: - warnings.filterwarnings("error") - import pygtk - pygtk.require('2.0') - import gtk - gtk.init_check() - warnings.filterwarnings("always") - except Exception as err: - die(err, "Failed to initialize GTK. If you are running over ssh, " - "did you enable X forwarding and start ssh with -X?") - - -def check_gnuradio_import(): - try: - from gnuradio import gr - except ImportError as err: - die(err, GR_IMPORT_ERROR_MESSAGE) - - -def check_blocks_path(): - if 'GR_DONT_LOAD_PREFS' in os.environ and not os.environ.get('GRC_BLOCKS_PATH', ''): - die(EnvironmentError("No block definitions available"), - "Can't find block definitions. Use config.conf or GRC_BLOCKS_PATH.") - - -def get_source_tree_root(): - source_tree_subpath = "/grc/scripts" - script_path = os.path.dirname(os.path.abspath(__file__)) - if script_path.endswith(source_tree_subpath): - return script_path[:-len(source_tree_subpath)] - - -def main(): - check_gnuradio_import() - - from gnuradio import gr - parser = optparse.OptionParser( - usage='usage: %prog [options] [saved flow graphs]', - version=VERSION_AND_DISCLAIMER_TEMPLATE % gr.version()) - options, args = parser.parse_args() - - check_gtk() - check_blocks_path() - source_tree_root = get_source_tree_root() - if not source_tree_root: - # run the installed version - from gnuradio.grc.python.Platform import Platform - from gnuradio.grc.gui.ActionHandler import ActionHandler - - else: - print("Running from source tree") - sys.path.insert(1, source_tree_root) - from grc.python.Platform import Platform - from grc.gui.ActionHandler import ActionHandler - - try: - import gtk - gtk.window_set_default_icon(gtk.IconTheme().load_icon('gnuradio-grc', 256, 0)) - except: - pass - - ActionHandler(args, Platform()) - - -if __name__ == '__main__': - main() +script_path = os.path.dirname(os.path.abspath(__file__)) +source_tree_subpath = "/grc/scripts" + +if not script_path.endswith(source_tree_subpath): + # run the installed version + from gnuradio.grc.main import main + from gnuradio.grc import checks +else: + print("Running from source tree") + sys.path.insert(1, script_path[:-len(source_tree_subpath)]) + from grc.main import main + from grc import checks + +checks.do_all() +exit(main()) diff --git a/grc/todo.txt b/grc/todo.txt deleted file mode 100644 index cedea72aa3..0000000000 --- a/grc/todo.txt +++ /dev/null @@ -1,69 +0,0 @@ -################################################## -# Examples -################################################## -* Push-to-Talk example -* Start/Stop the flow graph - -################################################## -# Blocks -################################################## -* probe: also non-float outputs -* log slider gui control -* packet mod: whitening offset -* wx min window size in options block -* gr_adaptive_fir_ccf -* size params for the graphical sinks -* callbacks for set average on fft, waterfall, number sinks -* add units to params: Sps, Hz, dB... -* add bool type to command line option store_true or store_false -* messages for packet blocks and probe blocks - -################################################## -# Features -################################################## -* extract category from doxygen - * fix up block tree to mirror current doxygen group - * remove blocks in block tree covered by doxygen -* param editor, expand entry boxes in focus -* change param dialog to panel within main window -* gui grid editor for configuring grid params/placing wxgui plots and controls -* drag from one port to another to connect -* per parameter docs - * extract individual param docs from doxygen - * doc tag in param for handwritten notes -* separate generated code into top block and gui class - * use gui.py in gr-wxgui and remove custom top_block_gui -* configuration option for adding block paths -* orientations for ports (top, right, bottom, left) - * source defaults to right, sink defaults to left -* separation of variables and gui controls -* speedup w/ background layer and animation layer -* multiple doxygen directories (doc_dir becomes doc_path) -* use pango markup in tooltips for params -* use get_var_make to determine if it is a variable, not regexp -* concept of a project, or project flow graph - * collection of blocks, hier and top - * system-wide, default/work, and user created -* use templates/macros to generate the repetative stuff in the xml - -################################################## -# Problems -################################################## -* msg ports dont work with virtual connections - * dont fix this until pmts are used? -* hier block generation - * auto generate hier library on changes - * auto clean hier library when block removed - * add hier blocks to tree without restart -* dont generate py files in saved flowgraph dir -* save/restore cwd -* threads dont die on exit in probe and variable sink -* align param titles in properties dialog -* weird grid params misbehaving -* gr hier blocks have more diverse IO capabilities than we allow for - -################################################## -# Future -################################################## -* require pygtk 2.12 for treeview tooltips - * remove try/except in BlockTreeWindow.py |