diff options
author | Manoj Gudi | 2013-10-07 20:19:55 +0530 |
---|---|---|
committer | Manoj Gudi | 2013-10-07 20:20:35 +0530 |
commit | 1826d0763c8595997f5f4af1fdb0354e9c0998ad (patch) | |
tree | acbd852cd5a1bf17241b1038b5e37a0e72e64612 /grc | |
parent | 452defdb4a78e9e826740ddf4b9673e926c568a4 (diff) | |
parent | 24b640997ba7fee0c725e65f401f5cbebdab8d08 (diff) | |
download | gnuradio-1826d0763c8595997f5f4af1fdb0354e9c0998ad.tar.gz gnuradio-1826d0763c8595997f5f4af1fdb0354e9c0998ad.tar.bz2 gnuradio-1826d0763c8595997f5f4af1fdb0354e9c0998ad.zip |
README change
Diffstat (limited to 'grc')
275 files changed, 20857 insertions, 0 deletions
diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt new file mode 100644 index 000000000..1156f1d76 --- /dev/null +++ b/grc/CMakeLists.txt @@ -0,0 +1,128 @@ +# Copyright 2011,2013 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. + +######################################################################## +# Setup dependencies +######################################################################## +include(GrPython) + +GR_PYTHON_CHECK_MODULE("python >= 2.5" sys "sys.version.split()[0] >= '2.5'" PYTHON_MIN_VER_FOUND) +GR_PYTHON_CHECK_MODULE("Cheetah >= 2.0.0" Cheetah "Cheetah.Version >= '2.0.0'" CHEETAH_FOUND) +GR_PYTHON_CHECK_MODULE("lxml >= 1.3.6" lxml.etree "lxml.etree.LXML_VERSION >= (1, 3, 6, 0)" LXML_FOUND) +GR_PYTHON_CHECK_MODULE("pygtk >= 2.10.0" gtk "gtk.pygtk_version >= (2, 10, 0)" PYGTK_FOUND) +GR_PYTHON_CHECK_MODULE("numpy" numpy True NUMPY_FOUND) + +######################################################################## +# Register component +######################################################################## +include(GrComponent) +if(NOT CMAKE_CROSSCOMPILING) + set(grc_python_deps + PYTHON_MIN_VER_FOUND + CHEETAH_FOUND + LXML_FOUND + PYGTK_FOUND + NUMPY_FOUND + ) +endif(NOT CMAKE_CROSSCOMPILING) + +GR_REGISTER_COMPONENT("gnuradio-companion" ENABLE_GRC + ENABLE_GR_CORE + ENABLE_PYTHON + ${grc_python_deps} +) + +######################################################################## +# Begin conditional configuration +######################################################################## +if(ENABLE_GRC) + +######################################################################## +# Setup CPack components +######################################################################## +include(GrPackage) +CPACK_COMPONENT("grc" + DISPLAY_NAME "GNU Radio Companion" + DESCRIPTION "Graphical flow graph designer" + DEPENDS "core_python" +) + +######################################################################## +# Create and install the grc conf file +######################################################################## +file(TO_NATIVE_PATH ${CMAKE_INSTALL_PREFIX}/${GRC_BLOCKS_DIR} blocksdir) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/grc.conf.in + ${CMAKE_CURRENT_BINARY_DIR}/grc.conf +@ONLY) + +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/grc.conf + DESTINATION ${GR_PREFSDIR} + COMPONENT "grc" +) + +GR_PYTHON_INSTALL( + FILES __init__.py + DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc + COMPONENT "grc" +) + +######################################################################## +# Appens NSIS commands to set environment variables +######################################################################## +if(WIN32) + +file(TO_NATIVE_PATH ${GR_PKG_DOC_DIR} GR_DOC_DIR) +string(REPLACE "\\" "\\\\" GR_DOC_DIR ${GR_DOC_DIR}) + +file(TO_NATIVE_PATH ${GRC_BLOCKS_DIR} GRC_BLOCKS_PATH) +string(REPLACE "\\" "\\\\" GRC_BLOCKS_PATH ${GRC_BLOCKS_PATH}) + +file(TO_NATIVE_PATH ${GR_PYTHON_DIR} GR_PYTHON_POSTFIX) +string(REPLACE "\\" "\\\\" GR_PYTHON_POSTFIX ${GR_PYTHON_POSTFIX}) + +CPACK_SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS} + #!include \\\"winmessages.nsh\\\" + WriteRegStr HKLM ${HLKM_ENV} \\\"GRC_BLOCKS_PATH\\\" \\\"$INSTDIR\\\\${GRC_BLOCKS_PATH}\\\" + SendMessage \\\${HWND_BROADCAST} \\\${WM_WININICHANGE} 0 \\\"STR:Environment\\\" /TIMEOUT=5000 +") + +CPACK_SET(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "${CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS} + #!include \\\"winmessages.nsh\\\" + DeleteRegValue HKLM ${HLKM_ENV} \\\"GRC_BLOCKS_PATH\\\" + SendMessage \\\${HWND_BROADCAST} \\\${WM_WININICHANGE} 0 \\\"STR:Environment\\\" /TIMEOUT=5000 +") + +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(scripts) +add_subdirectory(examples) + +endif(ENABLE_GRC) diff --git a/grc/__init__.py b/grc/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/grc/__init__.py diff --git a/grc/base/Block.py b/grc/base/Block.py new file mode 100644 index 000000000..a20be9db9 --- /dev/null +++ b/grc/base/Block.py @@ -0,0 +1,253 @@ +""" +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 + +from Cheetah.Template import Template +from UserDict import UserDict + +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. + @param flow graph the parent element + @param n the nested odict + @return 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._grc_source = n.find('grc_source') or '' + self._block_wrapper_path = n.find('block_wrapper_path') + #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 map(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) + #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) + + def get_enabled(self): + """ + Get the enabled state of the block. + @return true for enabled + """ + try: return eval(self.get_param('_enabled').get_value()) + except: return True + + def set_enabled(self, enabled): + """ + Set the enabled state of the block. + @param enabled true for enabled + """ + self.get_param('_enabled').set_value(str(enabled)) + + 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 get_doc(self): return '' + def get_ports(self): return self.get_sources() + self.get_sinks() + def get_children(self): return self.get_ports() + self.get_params() + def get_block_wrapper_path(self): return self._block_wrapper_path + + ############################################## + # Access Params + ############################################## + 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 + + ############################################## + # 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 + + ############################################## + # 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_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. + @param tmpl the string with dependencies + @return 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, e: return "-------->\n%s: %s\n<--------"%(e, tmpl) + + ############################################## + # Controller Modify + ############################################## + def type_controller_modify(self, direction): + """ + Change the type controller. + @param direction +1 or -1 + @return 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. + @param direction +1 or -1 + @return true for change + """ + return False + + ############################################## + ## Import/Export Methods + ############################################## + def export_data(self): + """ + Export this block's params to nested data. + @return a nested data odict + """ + n = odict() + n['key'] = self.get_key() + n['param'] = map(lambda p: p.export_data(), self.get_params()) + 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. + @param 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() diff --git a/grc/base/CMakeLists.txt b/grc/base/CMakeLists.txt new file mode 100644 index 000000000..1087e842a --- /dev/null +++ b/grc/base/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright 2011 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. + +######################################################################## +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 + flow_graph.dtd + DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/base + COMPONENT "grc" +) diff --git a/grc/base/Connection.py b/grc/base/Connection.py new file mode 100644 index 000000000..3ce7fd07f --- /dev/null +++ b/grc/base/Connection.py @@ -0,0 +1,97 @@ +""" +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 . import odict + +class Connection(Element): + + def __init__(self, flow_graph, porta, portb): + """ + Make a new connection given the parent and 2 ports. + @param flow_graph the parent of this element + @param porta a port (any direction) + @param portb a port (any direction) + @throws Error cannot make connection + @return a new connection + """ + Element.__init__(self, flow_graph) + source = sink = None + #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') + #ensure that this connection (source -> sink) is unique + for connection in self.get_parent().get_connections(): + if connection.get_source() is source and connection.get_sink() is sink: + raise Exception('This connection between source and sink is not unique.') + self._source = source + self._sink = sink + + def __str__(self): + return 'Connection (\n\t%s\n\t\t%s\n\t%s\n\t\t%s\n)'%( + self.get_source().get_parent(), + self.get_source(), + self.get_sink().get_parent(), + self.get_sink(), + ) + + def is_connection(self): return True + + def validate(self): + """ + Validate the connections. + The ports must match in type. + """ + Element.validate(self) + source_type = self.get_source().get_type() + sink_type = self.get_sink().get_type() + if source_type != sink_type: + self.add_error_message('Source type "%s" does not match sink type "%s".'%(source_type, sink_type)) + + def get_enabled(self): + """ + Get the enabled state of this connection. + @return true if source and sink blocks are enabled + """ + return self.get_source().get_parent().get_enabled() and \ + self.get_sink().get_parent().get_enabled() + + ############################# + # Access Ports + ############################# + def get_sink(self): return self._sink + def get_source(self): return self._source + + ############################################## + ## Import/Export Methods + ############################################## + def export_data(self): + """ + Export this connection's info. + @return a nested data odict + """ + n = odict() + n['source_block_id'] = self.get_source().get_parent().get_id() + n['sink_block_id'] = self.get_sink().get_parent().get_id() + n['source_key'] = self.get_source().get_key() + n['sink_key'] = self.get_sink().get_key() + return n diff --git a/grc/base/Constants.py b/grc/base/Constants.py new file mode 100644 index 000000000..ef45be8df --- /dev/null +++ b/grc/base/Constants.py @@ -0,0 +1,25 @@ +""" +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') diff --git a/grc/base/Element.py b/grc/base/Element.py new file mode 100644 index 000000000..a57090f3b --- /dev/null +++ b/grc/base/Element.py @@ -0,0 +1,89 @@ +""" +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 +""" + +class Element(object): + + def __init__(self, parent=None): + self._parent = parent + + ################################################## + # Element Validation API + ################################################## + def validate(self): + """ + Validate this element and call validate on all children. + Call this base method before adding error messages in the subclass. + """ + self._error_messages = list() + for child in self.get_children(): child.validate() + + def is_valid(self): + """ + Is this element valid? + @return true when the element is enabled and has no error messages + """ + return not self.get_error_messages() or not self.get_enabled() + + def add_error_message(self, msg): + """ + Add an error message to the list of errors. + @param msg the error message string + """ + self._error_messages.append(msg) + + def get_error_messages(self): + """ + Get the list of error messages from this element and all of its children. + Do not include the error messages from disabled children. + Cleverly indent the children error messages for printing purposes. + @return a list of error message strings + """ + error_messages = list(self._error_messages) #make a copy + for child in filter(lambda c: c.get_enabled(), self.get_children()): + for msg in child.get_error_messages(): + error_messages.append("%s:\n\t%s"%(child, msg.replace("\n", "\n\t"))) + return error_messages + + def rewrite(self): + """ + 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() + + def get_enabled(self): return True + + ############################################## + ## Tree-like API + ############################################## + def get_parent(self): return self._parent + def get_children(self): return list() + + ############################################## + ## Type testing methods + ############################################## + 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_source(self): return False + def is_sink(self): return False + def is_port(self): return False + def is_param(self): return False diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py new file mode 100644 index 000000000..0ba1f2389 --- /dev/null +++ b/grc/base/FlowGraph.py @@ -0,0 +1,219 @@ +""" +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 +from .. gui import Messages + +class FlowGraph(Element): + + def __init__(self, platform): + """ + Make a flow graph from the arguments. + @param platform a platforms with blocks and contrcutors + @return the flow graph object + """ + #initialize + Element.__init__(self, platform) + #inital blank import + self.import_data() + + def _get_unique_id(self, base_id=''): + """ + Get a unique id starting with the base id. + @param base_id the id starts with this and appends a count + @return a unique id + """ + index = 0 + while True: + id = '%s_%d'%(base_id, index) + 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_option(self, key): + """ + Get the option for a given key. + The option comes from the special options block. + @param key the param key for the options block + @return 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): return filter(lambda b: b.get_id() == id, self.get_blocks())[0] + def get_blocks(self): return filter(lambda e: e.is_block(), self.get_elements()) + def get_connections(self): return filter(lambda e: e.is_connection(), self.get_elements()) + def get_children(self): return self.get_elements() + def get_elements(self): + """ + Get a list of all the elements. + Always ensure that the options block is in the list (only once). + @return 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 + + def get_enabled_blocks(self): + """ + Get a list of all blocks that are enabled. + @return a list of blocks + """ + return filter(lambda b: b.get_enabled(), self.get_blocks()) + + def get_enabled_connections(self): + """ + Get a list of all connections that are enabled. + @return a list of connections + """ + return filter(lambda c: c.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. + @param key the block key + @return 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) + return block + + def connect(self, porta, portb): + """ + Create a connection between porta and portb. + @param porta a port + @param portb another port + @throw Exception bad connection + @return 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()) + self.get_elements().remove(element) + + def evaluate(self, expr): + """ + Evaluate the expression. + @param 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. + @return a nested data odict + """ + import time + n = odict() + n['timestamp'] = time.ctime() + n['block'] = [block.export_data() for block in self.get_blocks()] + n['connection'] = [connection.export_data() for connection in self.get_connections()] + return odict({'flow_graph': n}) + + 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. + @param n the nested data odict + """ + #remove previous elements + self._elements = list() + #use blank data if none provided + fg_n = n and n.find('flow_graph') or odict() + blocks_n = fg_n.findall('block') + connections_n = fg_n.findall('connection') + #create option block + self._options_block = self.get_parent().get_new_block(self, 'options') + #build the blocks + for block_n in blocks_n: + key = block_n.find('key') + if key == 'options': block = self._options_block + else: block = self.get_new_block(key) + #only load the block when the block key was valid + if block: block.import_data(block_n) + else: Messages.send_error_load('Block key "%s" not found in %s'%(key, self.get_parent())) + #build the connections + for connection_n in connections_n: + #try to make the connection + try: + #get the block ids + source_block_id = connection_n.find('source_block_id') + sink_block_id = connection_n.find('sink_block_id') + #get the port keys + source_key = connection_n.find('source_key') + sink_key = connection_n.find('sink_key') + #verify the blocks + block_ids = map(lambda b: b.get_id(), self.get_blocks()) + if source_block_id not in block_ids: + raise LookupError('source block id "%s" not in block ids'%source_block_id) + if sink_block_id not in block_ids: + raise LookupError('sink block id "%s" not in block ids'%sink_block_id) + #get the blocks + source_block = self.get_block(source_block_id) + sink_block = self.get_block(sink_block_id) + #verify the ports + if source_key not in source_block.get_source_keys(): + raise LookupError('source key "%s" not in source block keys'%source_key) + if sink_key not in sink_block.get_sink_keys(): + raise LookupError('sink key "%s" not in sink block keys'%sink_key) + #get the ports + source = source_block.get_source(source_key) + sink = sink_block.get_sink(sink_key) + #build the connection + self.connect(source, sink) + except LookupError, 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 + ) + ) + self.rewrite() #global rewrite diff --git a/grc/base/Param.py b/grc/base/Param.py new file mode 100644 index 000000000..c2fa5461a --- /dev/null +++ b/grc/base/Param.py @@ -0,0 +1,181 @@ +""" +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. + @param block the parent element + @param n the nested odict + """ + #grab the data + self._name = n.find('name') + self._key = n.find('key') + value = n.find('value') or '' + self._type = n.find('type') + self._hide = n.find('hide') or '' + #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 '' + + 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._name + 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 get_type(self): return self.get_parent().resolve_dependencies(self._type) + 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. + @return 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. + @return 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/base/ParseXML.py new file mode 100644 index 000000000..078ebd078 --- /dev/null +++ b/grc/base/ParseXML.py @@ -0,0 +1,102 @@ +""" +Copyright 2008 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 lxml import etree +from . import odict + +class XMLSyntaxError(Exception): + def __init__(self, error_log): + self._error_log = error_log + def __str__(self): + return '\n'.join(map(str, self._error_log.filter_from_errors())) + +def validate_dtd(xml_file, dtd_file=None): + """ + Validate an xml file against its dtd. + @param xml_file the xml file + @param dtd_file the optional dtd file + @throws Exception validation fails + """ + #perform parsing, use dtd validation if dtd file is not specified + parser = etree.XMLParser(dtd_validation=not dtd_file) + xml = etree.parse(xml_file, parser=parser) + if parser.error_log: raise XMLSyntaxError(parser.error_log) + #perform dtd validation if the dtd file is specified + if not dtd_file: return + dtd = etree.DTD(dtd_file) + if not dtd.validate(xml.getroot()): raise XMLSyntaxError(dtd.error_log) + +def from_file(xml_file): + """ + Create nested data from an xml file using the from xml helper. + @param xml_file the xml file path + @return the nested data + """ + xml = etree.parse(xml_file).getroot() + return _from_file(xml) + +def _from_file(xml): + """ + Recursivly parse the xml tree into nested data format. + @param xml the xml tree + @return the nested data + """ + tag = xml.tag + if not len(xml): + return odict({tag: xml.text or ''}) #store empty tags (text is None) as empty string + 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 + for key, values in nested_data.iteritems(): + if len(values) == 1: nested_data[key] = values[0] + return odict({tag: nested_data}) + +def to_file(nested_data, xml_file): + """ + Write an xml file and use the to xml helper method to load it. + @param nested_data the nested data + @param xml_file the xml file path + """ + xml = _to_file(nested_data)[0] + open(xml_file, 'w').write(etree.tostring(xml, xml_declaration=True, pretty_print=True)) + +def _to_file(nested_data): + """ + Recursivly parse the nested data into xml tree format. + @param nested_data the nested data + @return the xml tree filled with child nodes + """ + nodes = list() + for key, values in nested_data.iteritems(): + #listify the values if not a list + if not isinstance(values, (list, set, tuple)): + values = [values] + for value in values: + node = etree.Element(key) + if isinstance(value, (str, unicode)): node.text = value + else: node.extend(_to_file(value)) + nodes.append(node) + return nodes + +if __name__ == '__main__': + """Use the main method to test parse xml's functions.""" + pass diff --git a/grc/base/Platform.py b/grc/base/Platform.py new file mode 100644 index 000000000..d4b09088b --- /dev/null +++ b/grc/base/Platform.py @@ -0,0 +1,178 @@ +""" +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 + +class Platform(_Element): + + def __init__(self, name, version, key, + block_paths, block_dtd, default_flow_graph, generator, + license='', website=None, colors=[]): + """ + Make a platform from the arguments. + @param name the platform name + @param version the version string + @param key the unique platform key + @param block_paths the file paths to blocks in this platform + @param block_dtd the dtd validator for xml block wrappers + @param default_flow_graph the default flow graph file path + @param generator the generator class for this platform + @param colors a list of title, color_spec tuples + @param license a multi-line license (first line is copyright) + @param website the website url for this platform + @return a platform object + """ + _Element.__init__(self) + self._name = name + self._version = version + self._key = key + self._license = license + self._website = website + self._block_paths = block_paths + self._block_dtd = block_dtd + self._default_flow_graph = default_flow_graph + self._generator = generator + self._colors = colors + #create a dummy flow graph for the blocks + self._flow_graph = _Element(self) + #search for *.xml files in the given search path + + self.loadblocks(); + + def loadblocks(self): + xml_files = list() + for block_path in self._block_paths: + if os.path.isfile(block_path): xml_files.append(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)): + xml_files.append(os.path.join(dirpath, filename)) + #load the blocks + self._blocks = odict() + self._blocks_n = odict() + self._block_tree_files = list() + for xml_file in xml_files: + try: #try to add the xml file as a block wrapper + ParseXML.validate_dtd(xml_file, self._block_dtd) + n = ParseXML.from_file(xml_file).find('block') + #inject block wrapper path + n['block_wrapper_path'] = xml_file + block = self.Block(self._flow_graph, n) + key = block.get_key() + #test against repeated keys + if key in self.get_block_keys(): + print >> sys.stderr, 'Warning: Block with key "%s" already exists.\n\tIgnoring: %s'%(key, xml_file) + #store the block + else: + self._blocks[key] = block + self._blocks_n[key] = n + except ParseXML.XMLSyntaxError, e: + try: #try to add the xml file as a block tree + ParseXML.validate_dtd(xml_file, BLOCK_TREE_DTD) + self._block_tree_files.append(xml_file) + except ParseXML.XMLSyntaxError, e: + print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file) + except Exception, e: + print >> sys.stderr, 'Warning: Block loading failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file) + + def parse_flow_graph(self, flow_graph_file): + """ + Parse a saved flow graph file. + Ensure that the file exists, and passes the dtd check. + @param flow_graph_file the flow graph file + @return 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. + @param block_tree the block tree object + """ + #recursive function to load categories and blocks + def load_category(cat_n, parent=[]): + #add this category + parent = parent + [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 overrides the block tree + if not block.get_category(): block_tree.add_block(parent, block) + #load the block tree + for block_tree_file in self._block_tree_files: + #recursivly add all blocks in the tree + load_category(ParseXML.from_file(block_tree_file).find('cat')) + #add all other blocks, use the catgory tag + for block in self.get_blocks(): + #blocks with empty categories are in the xml block tree or 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_name(self): return self._name + def get_version(self): return self._version + 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 + + ############################################## + # Constructors + ############################################## + FlowGraph = _FlowGraph + Connection = _Connection + Block = _Block + Port = _Port + Param = _Param diff --git a/grc/base/Port.py b/grc/base/Port.py new file mode 100644 index 000000000..7a1b5d4e6 --- /dev/null +++ b/grc/base/Port.py @@ -0,0 +1,83 @@ +""" +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 + +class Port(Element): + + def __init__(self, block, n, dir): + """ + Make a new port from nested data. + @param block the parent element + @param n the nested odict + @param 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'] + self._dir = dir + + 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()) + + 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): return self._name + 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_connections(self): + """ + Get all connections that use this port. + @return 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. + @return a list of connection objects + """ + return filter(lambda c: c.get_enabled(), self.get_connections()) diff --git a/grc/base/__init__.py b/grc/base/__init__.py new file mode 100644 index 000000000..2682db812 --- /dev/null +++ b/grc/base/__init__.py @@ -0,0 +1,20 @@ +""" +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/base/block_tree.dtd b/grc/base/block_tree.dtd new file mode 100644 index 000000000..7d4a13ccc --- /dev/null +++ b/grc/base/block_tree.dtd @@ -0,0 +1,26 @@ +<!-- +Copyright 2008 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 +--> +<!-- + block_tree.dtd + Josh Blum + The document type definition for a block tree category listing. + --> +<!ELEMENT cat (name, cat*, block*)> +<!ELEMENT name (#PCDATA)> +<!ELEMENT block (#PCDATA)> diff --git a/grc/base/flow_graph.dtd b/grc/base/flow_graph.dtd new file mode 100644 index 000000000..74f48f10a --- /dev/null +++ b/grc/base/flow_graph.dtd @@ -0,0 +1,36 @@ +<!-- +Copyright 2008 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 +--> +<!-- + flow_graph.dtd + Josh Blum + The document type definition for flow graph xml files. + --> +<!ELEMENT flow_graph (timestamp?, block*, connection*)> <!-- optional timestamp --> +<!ELEMENT timestamp (#PCDATA)> +<!-- Block --> +<!ELEMENT block (key, param*)> +<!ELEMENT param (key, value)> +<!ELEMENT key (#PCDATA)> +<!ELEMENT value (#PCDATA)> +<!-- Connection --> +<!ELEMENT connection (source_block_id, sink_block_id, source_key, sink_key)> +<!ELEMENT source_block_id (#PCDATA)> +<!ELEMENT sink_block_id (#PCDATA)> +<!ELEMENT source_key (#PCDATA)> +<!ELEMENT sink_key (#PCDATA)> diff --git a/grc/base/odict.py b/grc/base/odict.py new file mode 100644 index 000000000..044d04ad7 --- /dev/null +++ b/grc/base/odict.py @@ -0,0 +1,93 @@ +""" +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 UserDict import DictMixin + +class odict(DictMixin): + + def __init__(self, d={}): + self._keys = list(d.keys()) + self._data = dict(d.copy()) + + def __setitem__(self, key, value): + if key not in self._data: + self._keys.append(key) + self._data[key] = value + + def __getitem__(self, key): + return self._data[key] + + def __delitem__(self, key): + del self._data[key] + self._keys.remove(key) + + def keys(self): + return list(self._keys) + + def copy(self): + copy_dict = odict() + copy_dict._data = self._data.copy() + copy_dict._keys = list(self._keys) + return copy_dict + + def insert_after(self, pos_key, key, val): + """ + Insert the new key, value entry after the entry given by the position key. + If the positional key is None, insert at the end. + @param pos_key the positional key + @param key the key for the new entry + @param 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)) + self._keys.insert(index+1, key) + self._data[key] = val + + def insert_before(self, pos_key, key, val): + """ + Insert the new key, value entry before the entry given by the position key. + If the positional key is None, insert at the begining. + @param pos_key the positional key + @param key the key for the new entry + @param 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)) + self._keys.insert(index, key) + self._data[key] = val + + def find(self, key): + """ + Get the value for this key if exists. + @param key the key to search for + @return the value or None + """ + if self.has_key(key): return self[key] + return None + + def findall(self, key): + """ + Get a list of values for this key. + @param key the key to search for + @return a list of values or empty list + """ + obj = self.find(key) + if obj is None: obj = list() + if isinstance(obj, list): return obj + return [obj] diff --git a/grc/blocks/CMakeLists.txt b/grc/blocks/CMakeLists.txt new file mode 100644 index 000000000..fce4a1907 --- /dev/null +++ b/grc/blocks/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright 2011 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 xml_files "*.xml") +install(FILES ${xml_files} DESTINATION ${GRC_BLOCKS_DIR} COMPONENT "grc") diff --git a/grc/blocks/band_pass_filter.xml b/grc/blocks/band_pass_filter.xml new file mode 100644 index 000000000..af083473d --- /dev/null +++ b/grc/blocks/band_pass_filter.xml @@ -0,0 +1,166 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Band Pass Filter: Custom wrapper +################################################### + --> +<block> + <name>Band Pass Filter</name> + <key>band_pass_filter</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.$(type.fcn)( + $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</make> + <callback>set_taps(firdes.$(type.fcn)($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</callback> + <param> + <name>FIR Type</name> + <key>type</key> + <type>enum</type> + <!-- Real Band Pass Taps --> + <option> + <name>Complex->Complex (Real Taps) (Decim)</name> + <key>fir_filter_ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>fcn:band_pass</opt> + </option> + <option> + <name>Complex->Complex (Real Taps) (Interp)</name> + <key>interp_fir_filter_ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>fcn:band_pass</opt> + </option> + <option> + <name>Float->Float (Real Taps) (Decim)</name> + <key>fir_filter_fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + <opt>fcn:band_pass</opt> + </option> + <option> + <name>Float->Float (Real Taps) (Interp)</name> + <key>interp_fir_filter_fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + <opt>fcn:band_pass</opt> + </option> + <!-- Complex Band Pass Taps --> + <option> + <name>Complex->Complex (Complex Taps) (Decim)</name> + <key>fir_filter_ccc</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>fcn:complex_band_pass</opt> + </option> + <option> + <name>Complex->Complex (Complex Taps) (Interp)</name> + <key>interp_fir_filter_ccc</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>fcn:complex_band_pass</opt> + </option> + <option> + <name>Float->Complex (Complex Taps) (Decim)</name> + <key>fir_filter_fcc</key> + <opt>input:float</opt> + <opt>output:complex</opt> + <opt>fcn:complex_band_pass</opt> + </option> + <option> + <name>Float->Complex (Complex Taps) (Interp)</name> + <key>interp_fir_filter_fcc</key> + <opt>input:float</opt> + <opt>output:complex</opt> + <opt>fcn:complex_band_pass</opt> + </option> + </param> + <param> + <name>Decimation</name> + <key>decim</key> + <value>1</value> + <type>int</type> + <hide>#if str($type).startswith('interp') then 'all' else 'none'#</hide> + </param> + <param> + <name>Interpolation</name> + <key>interp</key> + <value>1</value> + <type>int</type> + <hide>#if str($type).startswith('interp') then 'none' else 'all'#</hide> + </param> + <param> + <name>Gain</name> + <key>gain</key> + <value>1</value> + <type>real</type> + </param> + <param> + <name>Sample Rate</name> + <key>samp_rate</key> + <value>samp_rate</value> + <type>real</type> + </param> + <param> + <name>Low Cutoff Freq</name> + <key>low_cutoff_freq</key> + <type>real</type> + </param> + <param> + <name>High Cutoff Freq</name> + <key>high_cutoff_freq</key> + <type>real</type> + </param> + <param> + <name>Transition Width</name> + <key>width</key> + <type>real</type> + </param> + <param> + <name>Window</name> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + <type>int</type> + <option> + <name>Hamming</name> + <key>firdes.WIN_HAMMING</key> + </option> + <option> + <name>Hann</name> + <key>firdes.WIN_HANN</key> + </option> + <option> + <name>Blackman</name> + <key>firdes.WIN_BLACKMAN</key> + </option> + <option> + <name>Rectangular</name> + <key>firdes.WIN_RECTANGULAR</key> + </option> + <option> + <name>Kaiser</name> + <key>firdes.WIN_KAISER</key> + </option> + </param> + <param> + <name>Beta</name> + <key>beta</key> + <value>6.76</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> + <doc> +This filter is a convenience wrapper for an fir filter and a firdes taps generating function. + +Sample rate, cutoff frequency, and transition width are in Hertz. + +The beta paramater only applies to the Kaiser window. + </doc> +</block> diff --git a/grc/blocks/band_reject_filter.xml b/grc/blocks/band_reject_filter.xml new file mode 100644 index 000000000..dd5e7a9d7 --- /dev/null +++ b/grc/blocks/band_reject_filter.xml @@ -0,0 +1,132 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Band Reject Filter: Custom wrapper +################################################### + --> +<block> + <name>Band Reject Filter</name> + <key>band_reject_filter</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.band_reject( + $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</make> + <callback>set_taps(firdes.band_reject($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</callback> + <param> + <name>FIR Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex->Complex (Decimating)</name> + <key>fir_filter_ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + </option> + <option> + <name>Complex->Complex (Interpolating)</name> + <key>interp_fir_filter_ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + </option> + <option> + <name>Float->Float (Decimating)</name> + <key>fir_filter_fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + </option> + <option> + <name>Float->Float (Interpolating)</name> + <key>interp_fir_filter_fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + </option> + </param> + <param> + <name>Decimation</name> + <key>decim</key> + <value>1</value> + <type>int</type> + <hide>#if str($type).startswith('interp') then 'all' else 'none'#</hide> + </param> + <param> + <name>Interpolation</name> + <key>interp</key> + <value>1</value> + <type>int</type> + <hide>#if str($type).startswith('interp') then 'none' else 'all'#</hide> + </param> + <param> + <name>Gain</name> + <key>gain</key> + <value>1</value> + <type>real</type> + </param> + <param> + <name>Sample Rate</name> + <key>samp_rate</key> + <value>samp_rate</value> + <type>real</type> + </param> + <param> + <name>Low Cutoff Freq</name> + <key>low_cutoff_freq</key> + <type>real</type> + </param> + <param> + <name>High Cutoff Freq</name> + <key>high_cutoff_freq</key> + <type>real</type> + </param> + <param> + <name>Transition Width</name> + <key>width</key> + <type>real</type> + </param> + <param> + <name>Window</name> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + <type>int</type> + <option> + <name>Hamming</name> + <key>firdes.WIN_HAMMING</key> + </option> + <option> + <name>Hann</name> + <key>firdes.WIN_HANN</key> + </option> + <option> + <name>Blackman</name> + <key>firdes.WIN_BLACKMAN</key> + </option> + <option> + <name>Rectangular</name> + <key>firdes.WIN_RECTANGULAR</key> + </option> + <option> + <name>Kaiser</name> + <key>firdes.WIN_KAISER</key> + </option> + </param> + <param> + <name>Beta</name> + <key>beta</key> + <value>6.76</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> + <doc> +This filter is a convenience wrapper for an fir filter and a firdes taps generating function. + +Sample rate, cutoff frequency, and transition width are in Hertz. + +The beta paramater only applies to the Kaiser window. + </doc> +</block> diff --git a/grc/blocks/blks2_am_demod_cf.xml b/grc/blocks/blks2_am_demod_cf.xml new file mode 100644 index 000000000..898c613be --- /dev/null +++ b/grc/blocks/blks2_am_demod_cf.xml @@ -0,0 +1,47 @@ +<?xml version="1.0"?> +<!-- +################################################### +##AM Demod +################################################### + --> +<block> + <name>AM Demod</name> + <key>blks2_am_demod_cf</key> + <import>from gnuradio import blks2</import> + <make>blks2.am_demod_cf( + channel_rate=$chan_rate, + audio_decim=$audio_decim, + audio_pass=$audio_pass, + audio_stop=$audio_stop, +)</make> + <param> + <name>Channel Rate</name> + <key>chan_rate</key> + <type>real</type> + </param> + <param> + <name>Audio Decimation</name> + <key>audio_decim</key> + <type>int</type> + </param> + <param> + <name>Audio Pass</name> + <key>audio_pass</key> + <value>5000</value> + <type>real</type> + </param> + <param> + <name>Audio Stop</name> + <key>audio_stop</key> + <value>5500</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/blks2_analysis_filterbank.xml b/grc/blocks/blks2_analysis_filterbank.xml new file mode 100644 index 000000000..93cfa30af --- /dev/null +++ b/grc/blocks/blks2_analysis_filterbank.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Analysis Filterbank +################################################### + --> +<block> + <name>Analysis Filterbank</name> + <key>blks2_analysis_filterbank</key> + <import>from gnuradio import blks2</import> + <make>blks2.analysis_filterbank(mpoints=$mpoints, taps=$taps)</make> + <param> + <name>MPoints</name> + <key>mpoints</key> + <value>3</value> + <type>int</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <type>complex_vector</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + <nports>$mpoints</nports> + </source> +</block> diff --git a/grc/blocks/blks2_error_rate.xml b/grc/blocks/blks2_error_rate.xml new file mode 100644 index 000000000..91a303206 --- /dev/null +++ b/grc/blocks/blks2_error_rate.xml @@ -0,0 +1,69 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Error Rate: +## Custom blks2 block +################################################### + --> +<block> + <name>Error Rate</name> + <key>blks2_error_rate</key> + <import>from grc_gnuradio import blks2 as grc_blks2</import> + <make>grc_blks2.error_rate( + type=$type, + win_size=$win_size, + bits_per_symbol=$bits_per_symbol, +)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Bit Error Rate</name> + <key>'BER'</key> + <opt>hide_bps:</opt> + </option> + <option> + <name>Symbol Error Rate</name> + <key>'SER'</key> + <opt>hide_bps:all</opt> + </option> + </param> + <param> + <name>Window Size</name> + <key>win_size</key> + <value>1000</value> + <type>int</type> + </param> + <param> + <name>Bits per Symbol</name> + <key>bits_per_symbol</key> + <value>2</value> + <type>int</type> + <hide>$type.hide_bps</hide> + </param> + <sink> + <name>ref</name> + <type>byte</type> + </sink> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> + <doc> +Calculate the bit error rate (BER) or the symbol error rate (SER) over a number of samples given by the window size. \ +The actual window size will start at size one and grow to the full window size as new samples arrive. \ +Once the window has reached full size, old samples are shifted out of the window and new samples shfited in. + +The error block compares the input byte stream to the reference byte stream. \ +For example, the reference byte stream could be the input to a modulator, \ +and the input byte stream could be the output of a modulator. + +Each byte in the incoming stream represents one symbol. \ +The bits per symbol parameter is only useful for calculating the BER. + </doc> +</block> diff --git a/grc/blocks/blks2_fm_deemph.xml b/grc/blocks/blks2_fm_deemph.xml new file mode 100644 index 000000000..6f38dab6d --- /dev/null +++ b/grc/blocks/blks2_fm_deemph.xml @@ -0,0 +1,31 @@ +<?xml version="1.0"?> +<!-- +################################################### +##FM Deemphasis +################################################### + --> +<block> + <name>FM Deemphasis</name> + <key>blks2_fm_deemph</key> + <import>from gnuradio import blks2</import> + <make>blks2.fm_deemph(fs=$samp_rate, tau=$tau)</make> + <param> + <name>Sample Rate</name> + <key>samp_rate</key> + <type>real</type> + </param> + <param> + <name>Tau</name> + <key>tau</key> + <value>75e-6</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/blks2_fm_demod_cf.xml b/grc/blocks/blks2_fm_demod_cf.xml new file mode 100644 index 000000000..2ce1fb973 --- /dev/null +++ b/grc/blocks/blks2_fm_demod_cf.xml @@ -0,0 +1,68 @@ +<?xml version="1.0"?> +<!-- +################################################### +##FM Demod +################################################### + --> +<block> + <name>FM Demod</name> + <key>blks2_fm_demod_cf</key> + <import>from gnuradio import blks2</import> + <make>blks2.fm_demod_cf( + channel_rate=$chan_rate, + audio_decim=$audio_decim, + deviation=$deviation, + audio_pass=$audio_pass, + audio_stop=$audio_stop, + gain=$gain, + tau=$tau, +)</make> + <param> + <name>Channel Rate</name> + <key>chan_rate</key> + <type>real</type> + </param> + <param> + <name>Audio Decimation</name> + <key>audio_decim</key> + <type>int</type> + </param> + <param> + <name>Deviation</name> + <key>deviation</key> + <value>75000</value> + <type>real</type> + </param> + <param> + <name>Audio Pass</name> + <key>audio_pass</key> + <value>15000</value> + <type>real</type> + </param> + <param> + <name>Audio Stop</name> + <key>audio_stop</key> + <value>16000</value> + <type>real</type> + </param> + <param> + <name>Gain</name> + <key>gain</key> + <value>1.0</value> + <type>real</type> + </param> + <param> + <name>Tau</name> + <key>tau</key> + <value>75e-6</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/blks2_fm_preemph.xml b/grc/blocks/blks2_fm_preemph.xml new file mode 100644 index 000000000..672a7a7b2 --- /dev/null +++ b/grc/blocks/blks2_fm_preemph.xml @@ -0,0 +1,31 @@ +<?xml version="1.0"?> +<!-- +################################################### +##FM Preemphasis +################################################### + --> +<block> + <name>FM Preemphasis</name> + <key>blks2_fm_preemph</key> + <import>from gnuradio import blks2</import> + <make>blks2.fm_preemph(fs=$samp_rate, tau=$tau)</make> + <param> + <name>Sample Rate</name> + <key>samp_rate</key> + <type>real</type> + </param> + <param> + <name>Tau</name> + <key>tau</key> + <value>75e-6</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/blks2_logpwrfft_x.xml b/grc/blocks/blks2_logpwrfft_x.xml new file mode 100644 index 000000000..79a3bfc4b --- /dev/null +++ b/grc/blocks/blks2_logpwrfft_x.xml @@ -0,0 +1,90 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Log Power FFT +################################################### + --> +<block> + <name>Log Power FFT</name> + <key>blks2_logpwrfft_x</key> + <import>from gnuradio import blks2</import> + <make>blks2.logpwrfft_$(type.fcn)( + sample_rate=$sample_rate, + fft_size=$fft_size, + ref_scale=$ref_scale, + frame_rate=$frame_rate, + avg_alpha=$avg_alpha, + average=$average, +)</make> + <callback>set_sample_rate($sample_rate)</callback> + <callback>set_avg_alpha($avg_alpha)</callback> + <callback>set_average($average)</callback> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:c</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + </option> + </param> + <param> + <name>Sample Rate</name> + <key>sample_rate</key> + <value>samp_rate</value> + <type>real</type> + </param> + <param> + <name>FFT Size</name> + <key>fft_size</key> + <value>1024</value> + <type>int</type> + </param> + <param> + <name>Reference Scale</name> + <key>ref_scale</key> + <value>2</value> + <type>real</type> + </param> + <param> + <name>Frame Rate</name> + <key>frame_rate</key> + <value>30</value> + <type>real</type> + </param> + <param> + <name>Average</name> + <key>average</key> + <value>False</value> + <type>bool</type> + <option> + <name>On</name> + <key>True</key> + </option> + <option> + <name>Off</name> + <key>False</key> + </option> + </param> + <param> + <name>Average Alpha</name> + <key>avg_alpha</key> + <value>1.0</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>float</type> + <vlen>$fft_size</vlen> + </source> +</block> diff --git a/grc/blocks/blks2_nbfm_rx.xml b/grc/blocks/blks2_nbfm_rx.xml new file mode 100644 index 000000000..d332b9a6b --- /dev/null +++ b/grc/blocks/blks2_nbfm_rx.xml @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<!-- +################################################### +##NBFM Receive +################################################### + --> +<block> + <name>NBFM Receive</name> + <key>blks2_nbfm_rx</key> + <import>from gnuradio import blks2</import> + <make>blks2.nbfm_rx( + audio_rate=$audio_rate, + quad_rate=$quad_rate, + tau=$tau, + max_dev=$max_dev, +)</make> + <param> + <name>Audio Rate</name> + <key>audio_rate</key> + <type>int</type> + </param> + <param> + <name>Quadrature Rate</name> + <key>quad_rate</key> + <type>int</type> + </param> + <param> + <name>Tau</name> + <key>tau</key> + <value>75e-6</value> + <type>real</type> + </param> + <param> + <name>Max Deviation</name> + <key>max_dev</key> + <value>5e3</value> + <type>real</type> + </param> + <check>$quad_rate%$audio_rate == 0</check> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/blks2_nbfm_tx.xml b/grc/blocks/blks2_nbfm_tx.xml new file mode 100644 index 000000000..3aa7ede0e --- /dev/null +++ b/grc/blocks/blks2_nbfm_tx.xml @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<!-- +################################################### +##NBFM Transmit +################################################### + --> +<block> + <name>NBFM Transmit</name> + <key>blks2_nbfm_tx</key> + <import>from gnuradio import blks2</import> + <make>blks2.nbfm_tx( + audio_rate=$audio_rate, + quad_rate=$quad_rate, + tau=$tau, + max_dev=$max_dev, +)</make> + <param> + <name>Audio Rate</name> + <key>audio_rate</key> + <type>int</type> + </param> + <param> + <name>Quadrature Rate</name> + <key>quad_rate</key> + <type>int</type> + </param> + <param> + <name>Tau</name> + <key>tau</key> + <value>75e-6</value> + <type>real</type> + </param> + <param> + <name>Max Deviation</name> + <key>max_dev</key> + <value>5e3</value> + <type>real</type> + </param> + <check>$quad_rate%$audio_rate == 0</check> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/blks2_packet_decoder.xml b/grc/blocks/blks2_packet_decoder.xml new file mode 100644 index 000000000..07b0d1f2e --- /dev/null +++ b/grc/blocks/blks2_packet_decoder.xml @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Packet Decoder +################################################### + --> +<block> + <name>Packet Decoder</name> + <key>blks2_packet_decoder</key> + <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, + threshold=$threshold, + callback=lambda ok, payload: self.$(id).recv_pkt(ok, payload), + ), +)</make> + <param> + <name>Output Type</name> + <key>type</key> + <value>float</value> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:c</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:i</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:s</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:b</opt> + </option> + </param> + <param> + <name>Access Code</name> + <key>access_code</key> + <value></value> + <type>string</type> + </param> + <param> + <name>Threshold</name> + <key>threshold</key> + <value>-1</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> + <doc> +Packet decoder block, for use with the gnuradio demodulator blocks: gmsk, psk, qam. + +Access Code: string of 1's and 0's, leave blank for automatic. + +Threshold: -1 for automatic. + </doc> +</block> diff --git a/grc/blocks/blks2_packet_encoder.xml b/grc/blocks/blks2_packet_encoder.xml new file mode 100644 index 000000000..b184ebd31 --- /dev/null +++ b/grc/blocks/blks2_packet_encoder.xml @@ -0,0 +1,110 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Packet Encoder +################################################### + --> +<block> + <name>Packet Encoder</name> + <key>blks2_packet_encoder</key> + <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, + bits_per_symbol=$bits_per_symbol, + access_code=$access_code, + pad_for_usrp=$pad_for_usrp, + ), + payload_length=$payload_length, +)</make> + <param> + <name>Input Type</name> + <key>type</key> + <value>float</value> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:c</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:i</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:s</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:b</opt> + </option> + </param> + <param> + <name>Samples/Symbol</name> + <key>samples_per_symbol</key> + <type>int</type> + </param> + <param> + <name>Bits/Symbol</name> + <key>bits_per_symbol</key> + <type>int</type> + </param> + <param> + <name>Access Code</name> + <key>access_code</key> + <value></value> + <type>string</type> + </param> + <param> + <name>Pad for USRP</name> + <key>pad_for_usrp</key> + <type>enum</type> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + </param> + <param> + <name>Payload Length</name> + <key>payload_length</key> + <value>0</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> + <doc> +Packet encoder block, for use with the gnuradio modulator blocks: gmsk, dpsk, qam. + +Access Code: string of 1's and 0's, leave blank for automatic. + +Payload Length: 0 for automatic. + +Bits/Symbol should be set accordingly: + gmsk -> 1 + dbpsk -> 1 + dqpsk -> 2 + d8psk -> 3 + qam8 -> 3 + qam16 -> 4 + qam64 -> 6 + qam256 -> 8 + </doc> +</block> diff --git a/grc/blocks/blks2_pfb_arb_resampler.xml b/grc/blocks/blks2_pfb_arb_resampler.xml new file mode 100644 index 000000000..b58e70f1c --- /dev/null +++ b/grc/blocks/blks2_pfb_arb_resampler.xml @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Polyphase Arbitrary Resampler +################################################### + --> +<block> + <name>Polyphase Resampler</name> + <key>blks2_pfb_arb_resampler_ccf</key> + <import>from gnuradio import blks2</import> + <import>from gnuradio.gr import firdes</import> + <make>blks2.pfb_arb_resampler_ccf( + $rate, + $taps, + $size, +)</make> + <!-- Set taps not implemented yet + <callback>set_taps($taps)</callback> + --> + <callback>set_rate($rate)</callback> + <param> + <name>Resample Rate</name> + <key>rate</key> + <type>real</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <type>real_vector</type> + </param> + <param> + <name>Size (# phases)</name> + <key>size</key> + <value>32</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/blks2_pfb_channelizer.xml b/grc/blocks/blks2_pfb_channelizer.xml new file mode 100644 index 000000000..5a93c0866 --- /dev/null +++ b/grc/blocks/blks2_pfb_channelizer.xml @@ -0,0 +1,62 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Polyphase Channelizer +################################################### + --> +<block> + <name>Polyphase Channelizer</name> + <key>blks2_pfb_channelizer_ccf</key> + <import>from gnuradio import blks2</import> + <import>from gnuradio.gr import firdes</import> + <make>blks2.pfb_channelizer_ccf( + $nchans, + $taps, + $osr, + $atten) +self.$(id).set_channel_map($ch_map) + </make> + <!-- Set taps not implemented yet + <callback>set_taps($taps)</callback> + --> + <callback>set_channel_map($ch_map)</callback> + + <param> + <name>Channels</name> + <key>nchans</key> + <type>int</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <value>None</value> + <type>real_vector</type> + </param> + <param> + <name>Over Sample Ratio</name> + <key>osr</key> + <value>1.0</value> + <type>real</type> + </param> + <param> + <name>Attenuation</name> + <key>atten</key> + <value>100</value> + <type>real</type> + </param> + <param> + <name>Channel Map</name> + <key>ch_map</key> + <value>[]</value> + <type>int_vector</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + <nports>$nchans</nports> + </source> +</block> diff --git a/grc/blocks/blks2_rational_resampler_xxx.xml b/grc/blocks/blks2_rational_resampler_xxx.xml new file mode 100644 index 000000000..b92ec8ec2 --- /dev/null +++ b/grc/blocks/blks2_rational_resampler_xxx.xml @@ -0,0 +1,88 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Rational Resampler +################################################### + --> +<block> + <name>Rational Resampler</name> + <key>blks2_rational_resampler_xxx</key> + <import>from gnuradio import blks2</import> + <import>from gnuradio.gr import firdes</import> + <make>blks2.rational_resampler_$(type)( + interpolation=$interp, + decimation=$decim, +#if $taps() + taps=$taps, +#else + taps=None, +#end if +#if $fractional_bw() != 0 + fractional_bw=$fractional_bw, +#else + fractional_bw=None, +#end if +)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex->Complex (Complex Taps)</name> + <key>ccc</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + <option> + <name>Complex->Complex (Real Taps)</name> + <key>ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>taps:real_vector</opt> + </option> + <option> + <name>Float->Float (Real Taps)</name> + <key>fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + <opt>taps:real_vector</opt> + </option> + </param> + <param> + <name>Decimation</name> + <key>decim</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Interpolation</name> + <key>interp</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <value>[]</value> + <type>$type.taps</type> + </param> + <param> + <name>Fractional BW</name> + <key>fractional_bw</key> + <value>0</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> + <doc> +Leave taps empty for automatic value. +Leave fractional bandwidth 0 for automatic value. + </doc> +</block> diff --git a/grc/blocks/blks2_selector.xml b/grc/blocks/blks2_selector.xml new file mode 100644 index 000000000..2d89df186 --- /dev/null +++ b/grc/blocks/blks2_selector.xml @@ -0,0 +1,97 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Selector: +## Custom blks2 block +################################################### + --> +<block> + <name>Selector</name> + <key>blks2_selector</key> + <import>from grc_gnuradio import blks2 as grc_blks2</import> + <make>grc_blks2.selector( + item_size=$type.size*$vlen, + num_inputs=$num_inputs, + num_outputs=$num_outputs, + input_index=$input_index, + output_index=$output_index, +)</make> + <callback>set_input_index(int($input_index))</callback> + <callback>set_output_index(int($output_index))</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Num Inputs</name> + <key>num_inputs</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Num Outputs</name> + <key>num_outputs</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Input Index</name> + <key>input_index</key> + <value>0</value> + <type>int</type> + </param> + <param> + <name>Output Index</name> + <key>output_index</key> + <value>0</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_inputs</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_outputs</nports> + </source> + <doc> +Connect the sink at input index to the source at output index. Leave all other ports disconnected. + </doc> +</block> diff --git a/grc/blocks/blks2_standard_squelch.xml b/grc/blocks/blks2_standard_squelch.xml new file mode 100644 index 000000000..f0baeb662 --- /dev/null +++ b/grc/blocks/blks2_standard_squelch.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Standard Squelch +################################################### + --> +<block> + <name>Standard Squelch</name> + <key>blks2_standard_squelch</key> + <import>from gnuradio import blks2</import> + <make>blks2.standard_squelch(audio_rate=$audio_rate) +self.$(id).set_threshold($threshold)</make> + <callback>set_threshold($threshold)</callback> + <param> + <name>Audio Rate</name> + <key>audio_rate</key> + <type>real</type> + </param> + <param> + <name>Threshold</name> + <key>threshold</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/blks2_stream_to_vector_decimator.xml b/grc/blocks/blks2_stream_to_vector_decimator.xml new file mode 100644 index 000000000..25f8f7a62 --- /dev/null +++ b/grc/blocks/blks2_stream_to_vector_decimator.xml @@ -0,0 +1,77 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Stream to Vector Decimator +################################################### + --> +<block> + <name>Stream to Vec Decim</name> + <key>blks2_stream_to_vector_decimator</key> + <import>from gnuradio import blks2</import> + <make>blks2.stream_to_vector_decimator( + item_size=$type.size, + sample_rate=$sample_rate, + vec_rate=$vec_rate, + vec_len=$vlen, +)</make> + <callback>set_sample_rate($sample_rate)</callback> + <callback>set_vec_rate($vec_rate)</callback> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Sample Rate</name> + <key>sample_rate</key> + <value>samp_rate</value> + <type>real</type> + </param> + <param> + <name>Vec Rate</name> + <key>vec_rate</key> + <value>30</value> + <type>real</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1024</value> + <type>int</type> + </param> + <check>$vlen >= 1</check> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/blks2_synthesis_filterbank.xml b/grc/blocks/blks2_synthesis_filterbank.xml new file mode 100644 index 000000000..5979ed3f7 --- /dev/null +++ b/grc/blocks/blks2_synthesis_filterbank.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Synthesis Filterbank +################################################### + --> +<block> + <name>Synthesis Filterbank</name> + <key>blks2_synthesis_filterbank</key> + <import>from gnuradio import blks2</import> + <make>blks2.synthesis_filterbank(mpoints=$mpoints, taps=$taps)</make> + <param> + <name>MPoints</name> + <key>mpoints</key> + <value>3</value> + <type>int</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <type>complex_vector</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + <nports>$mpoints</nports> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/blks2_tcp_sink.xml b/grc/blocks/blks2_tcp_sink.xml new file mode 100644 index 000000000..cfe7b42d8 --- /dev/null +++ b/grc/blocks/blks2_tcp_sink.xml @@ -0,0 +1,89 @@ +<?xml version="1.0"?> +<!-- +################################################### +##TCP Sink: Custom blks2 block +################################################### + --> +<block> + <name>TCP Sink</name> + <key>blks2_tcp_sink</key> + <import>from grc_gnuradio import blks2 as grc_blks2</import> + <make>grc_blks2.tcp_sink( + itemsize=$type.size*$vlen, + addr=$addr, + port=$port, + server=$server, +)</make> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Address</name> + <key>addr</key> + <value>127.0.0.1</value> + <type>string</type> + </param> + <param> + <name>Port</name> + <key>port</key> + <value>0</value> + <type>int</type> + </param> + <param> + <name>Mode</name> + <key>server</key> + <value>False</value> + <type>enum</type> + <option> + <name>Server</name> + <key>True</key> + </option> + <option> + <name>Client</name> + <key>False</key> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <doc> +In client mode, we attempt to connect to a server at the given address and port. \ +In server mode, we bind a socket to the given address and port and accept the first client. + </doc> +</block> diff --git a/grc/blocks/blks2_tcp_source.xml b/grc/blocks/blks2_tcp_source.xml new file mode 100644 index 000000000..6bf742aa0 --- /dev/null +++ b/grc/blocks/blks2_tcp_source.xml @@ -0,0 +1,89 @@ +<?xml version="1.0"?> +<!-- +################################################### +##TCP Source: Custom blks2 block +################################################### + --> +<block> + <name>TCP Source</name> + <key>blks2_tcp_source</key> + <import>from grc_gnuradio import blks2 as grc_blks2</import> + <make>grc_blks2.tcp_source( + itemsize=$type.size*$vlen, + addr=$addr, + port=$port, + server=$server, +)</make> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Address</name> + <key>addr</key> + <value>127.0.0.1</value> + <type>string</type> + </param> + <param> + <name>Port</name> + <key>port</key> + <value>0</value> + <type>int</type> + </param> + <param> + <name>Mode</name> + <key>server</key> + <value>True</value> + <type>enum</type> + <option> + <name>Server</name> + <key>True</key> + </option> + <option> + <name>Client</name> + <key>False</key> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> + <doc> +In client mode, we attempt to connect to a server at the given address and port. \ +In server mode, we bind a socket to the given address and port and accept the first client. + </doc> +</block> diff --git a/grc/blocks/blks2_valve.xml b/grc/blocks/blks2_valve.xml new file mode 100644 index 000000000..47c553523 --- /dev/null +++ b/grc/blocks/blks2_valve.xml @@ -0,0 +1,72 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Valve: +## Custom blks2 block +################################################### + --> +<block> + <name>Valve</name> + <key>blks2_valve</key> + <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> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Open</name> + <key>open</key> + <value>0</value> + <type>raw</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_inputs</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_outputs</nports> + </source> + <doc> +Connect output to input when valve is closed (not open). + </doc> +</block> diff --git a/grc/blocks/blks2_wfm_rcv.xml b/grc/blocks/blks2_wfm_rcv.xml new file mode 100644 index 000000000..37fb3ba8c --- /dev/null +++ b/grc/blocks/blks2_wfm_rcv.xml @@ -0,0 +1,33 @@ +<?xml version="1.0"?> +<!-- +################################################### +##WBFM Receive +################################################### + --> +<block> + <name>WBFM Receive</name> + <key>blks2_wfm_rcv</key> + <import>from gnuradio import blks2</import> + <make>blks2.wfm_rcv( + quad_rate=$quad_rate, + audio_decimation=$audio_decimation, +)</make> + <param> + <name>Quadrature Rate</name> + <key>quad_rate</key> + <type>real</type> + </param> + <param> + <name>Audio Decimation</name> + <key>audio_decimation</key> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/blks2_wfm_rcv_pll.xml b/grc/blocks/blks2_wfm_rcv_pll.xml new file mode 100644 index 000000000..2771350cf --- /dev/null +++ b/grc/blocks/blks2_wfm_rcv_pll.xml @@ -0,0 +1,37 @@ +<?xml version="1.0"?> +<!-- +################################################### +##WBFM Receive PLL +################################################### + --> +<block> + <name>WBFM Receive PLL</name> + <key>blks2_wfm_rcv_pll</key> + <import>from gnuradio import blks2</import> + <make>blks2.wfm_rcv_pll( + demod_rate=$quad_rate, + audio_decimation=$audio_decimation, +)</make> + <param> + <name>Quadrature Rate</name> + <key>quad_rate</key> + <type>real</type> + </param> + <param> + <name>Audio Decimation</name> + <key>audio_decimation</key> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>Lout</name> + <type>float</type> + </source> + <source> + <name>Rout</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/blks2_wfm_tx.xml b/grc/blocks/blks2_wfm_tx.xml new file mode 100644 index 000000000..cff92d819 --- /dev/null +++ b/grc/blocks/blks2_wfm_tx.xml @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<!-- +################################################### +##WBFM Transmit +################################################### + --> +<block> + <name>WBFM Transmit</name> + <key>blks2_wfm_tx</key> + <import>from gnuradio import blks2</import> + <make>blks2.wfm_tx( + audio_rate=$audio_rate, + quad_rate=$quad_rate, + tau=$tau, + max_dev=$max_dev, +)</make> + <param> + <name>Audio Rate</name> + <key>audio_rate</key> + <type>int</type> + </param> + <param> + <name>Quadrature Rate</name> + <key>quad_rate</key> + <type>int</type> + </param> + <param> + <name>Tau</name> + <key>tau</key> + <value>75e-6</value> + <type>real</type> + </param> + <param> + <name>Max Deviation</name> + <key>max_dev</key> + <value>75e3</value> + <type>real</type> + </param> + <check>$quad_rate%$audio_rate == 0</check> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/block_tree.xml b/grc/blocks/block_tree.xml new file mode 100644 index 000000000..dcd6c5448 --- /dev/null +++ b/grc/blocks/block_tree.xml @@ -0,0 +1,283 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Block Tree for platform gnuradio python. +################################################### + --> +<cat> + <name></name> <!-- Blank for Root Name --> + <cat> + <name>Sources</name> + <block>const_source_x</block> + <block>gr_sig_source_x</block> + <block>gr_noise_source_x</block> + <block>gr_vector_source_x</block> + <block>random_source_x</block> + <block>gr_glfsr_source_x</block> + <block>gr_null_source</block> + <block>gr_file_source</block> + <block>blks2_tcp_source</block> + <block>gr_udp_source</block> + <block>gr_wavfile_source</block> + <block>gr_message_source</block> + <block>gr_message_burst_source</block> + <block>pad_source</block> + <block>virtual_source</block> + </cat> + <cat> + <name>Sinks</name> + <block>gr_vector_sink_x</block> + <block>gr_null_sink</block> + <block>gr_file_sink</block> + <block>blks2_tcp_sink</block> + <block>gr_udp_sink</block> + <block>gr_wavfile_sink</block> + <block>gr_message_sink</block> + <block>pad_sink</block> + <block>virtual_sink</block> + <block>gr_tag_debug</block> + </cat> + <cat> + <name>Message Tools</name> + <block>gr_message_debug</block> + <block>gr_message_strobe</block> + <block>gr_pdu_to_tagged_stream</block> + <block>gr_tagged_stream_to_pdu</block> + <block>gr_tuntap_pdu</block> + <block>gr_socket_pdu</block> + <block>gr_random_pdu</block> + </cat> + <cat> + <name>Operators</name> + <block>gr_add_xx</block> + <block>gr_sub_xx</block> + <block>gr_multiply_xx</block> + <block>gr_divide_xx</block> + <block>gr_nlog10_ff</block> + <block>gr_transcendental</block> + <block>gr_add_const_vxx</block> + <block>gr_multiply_const_vxx</block> + <block>gr_and_const_xx</block> + + <block>gr_not_xx</block> + <block>gr_and_xx</block> + <block>gr_or_xx</block> + <block>gr_xor_xx</block> + + <block>gr_max_xx</block> + <block>gr_argmax_xx</block> + <block>gr_rms_xx</block> + <block>gr_integrate_xx</block> + + <block>gr_conjugate_cc</block> + + <block>gr_fft_vxx</block> + <block>blks2_logpwrfft_x</block> + <block>gr_vector_insert_x</block> + + <block>gr_endian_swap</block> + </cat> + <cat> + <name>Type Conversions</name> + <block>gr_complex_to_arg</block> + <block>gr_complex_to_mag</block> + <block>gr_complex_to_mag_squared</block> + <block>gr_complex_to_real</block> + <block>gr_complex_to_imag</block> + + <block>gr_complex_to_float</block> + <block>gr_float_to_complex</block> + + <block>gr_float_to_int</block> + <block>gr_float_to_short</block> + <block>gr_short_to_float</block> + <block>gr_short_to_char</block> + + <block>gr_int_to_float</block> + + <block>gr_float_to_char</block> + <block>gr_char_to_float</block> + <block>gr_char_to_short</block> + + <block>gr_float_to_uchar</block> + <block>gr_uchar_to_float</block> + + <block>gr_complex_to_interleaved_short</block> + <block>gr_interleaved_short_to_complex</block> + </cat> + <cat> + <name>Stream Conversions</name> + <block>gr_interleave</block> + <block>gr_deinterleave</block> + + <block>gr_streams_to_stream</block> + <block>gr_stream_to_streams</block> + + <block>gr_streams_to_vector</block> + <block>gr_vector_to_streams</block> + + <block>gr_stream_to_vector</block> + <block>gr_vector_to_stream</block> + + <block>blks2_stream_to_vector_decimator</block> + + <block>gr_stream_mux</block> + <block>gr_burst_tagger</block> + </cat> + <cat> + <name>Misc Conversions</name> + <block>gr_unpacked_to_packed_xx</block> + <block>gr_packed_to_unpacked_xx</block> + <block>gr_unpack_k_bits_bb</block> + <block>gr_pack_k_bits_bb</block> + <block>gr_chunks_to_symbols_xx</block> + <block>gr_map_bb</block> + </cat> + <cat> + <name>Synchronizers</name> + <block>gr_pfb_clock_sync_xxx</block> + + <block>gr_mpsk_sync_cc</block> + + <block>gr_pll_carriertracking_cc</block> + <block>gr_pll_freqdet_cf</block> + <block>gr_pll_refout_cc</block> + + <block>gr_pn_correlator_cc</block> + <block>gr_simple_correlator</block> + <block>gr_simple_framer</block> + + <block>blks2_packet_decoder</block> + <block>blks2_packet_encoder</block> + </cat> + <cat> + <name>Level Controls</name> + <block>gr_dpll_bb</block> + <block>gr_peak_detector_xb</block> + <block>gr_peak_detector2_fb</block> + <block>gr_sample_and_hold_xx</block> + + <block>gr_agc_xx</block> + <block>gr_agc2_xx</block> + <block>gr_feedforward_agc_cc</block> + + <block>gr_mute_xx</block> + <block>gr_simple_squelch_cc</block> + <block>blks2_standard_squelch</block> + <block>gr_pwr_squelch_xx</block> + <block>gr_ctcss_squelch_ff</block> + <block>gr_threshold_ff</block> + </cat> + <cat> + <name>Filters</name> + <!-- FIR convenience filters --> + <block>low_pass_filter</block> + <block>high_pass_filter</block> + <block>band_pass_filter</block> + <block>band_reject_filter</block> + <block>root_raised_cosine_filter</block> + <!-- Filters that take taps as arguments --> + <block>gr_fir_filter_xxx</block> + <block>gr_interp_fir_filter_xxx</block> + <block>gr_fft_filter_xxx</block> + <block>gr_freq_xlating_fir_filter_xxx</block> + <block>gr_iir_filter_ffd</block> + <block>gr_filter_delay_fc</block> + <block>gr_channel_model</block> + <!-- Filter banks --> + <block>blks2_synthesis_filterbank</block> + <block>blks2_analysis_filterbank</block> + <!-- Polyphase filters --> + <block>blks2_pfb_arb_resampler_ccf</block> + <block>blks2_pfb_channelizer_ccf</block> + <block>gr_pfb_synthesizer_ccf</block> + <!-- Other filters --> + <block>gr_single_pole_iir_filter_xx</block> + <block>gr_hilbert_fc</block> + <block>gr_goertzel_fc</block> + <block>gr_rational_resampler_base_xxx</block> + <block>blks2_rational_resampler_xxx</block> + <block>gr_fractional_interpolator_xx</block> + <block>gr_keep_one_in_n</block> + <block>gr_keep_m_in_n</block> + <block>gr_moving_average_xx</block> + <block>gr_iqcomp_cc</block> + <block>gr_dc_blocker</block> + </cat> + <cat> + <name>Modulators</name> + <block>gr_vco_f</block> + <block>gr_frequency_modulator_fc</block> + <block>gr_phase_modulator_fc</block> + <block>gr_quadrature_demod_cf</block> + <block>gr_cpfsk_bc</block> + + <block>gr_diff_phasor_cc</block> + + <block>gr_diff_encoder_bb</block> + <block>gr_diff_decoder_bb</block> + + <block>blks2_wfm_tx</block> + <block>blks2_wfm_rcv</block> + <block>blks2_wfm_rcv_pll</block> + + <block>blks2_nbfm_tx</block> + <block>blks2_nbfm_rx</block> + + <block>blks2_am_demod_cf</block> + <block>blks2_fm_demod_cf</block> + <block>blks2_fm_deemph</block> + <block>blks2_fm_preemph</block> + </cat> + <cat> + <name>Error Correction</name> + <cat> + <name>Trellis</name> + </cat> + + <block>gr_encode_ccsds_27_bb</block> + <block>gr_decode_ccsds_27_fb</block> + </cat> + <cat> + <name>Line Coding</name> + <block>gr_scrambler_bb</block> + <block>gr_descrambler_bb</block> + <block>gr_additive_scrambler_bb</block> + </cat> + <cat> + <name>Probes</name> + <block>gr_probe_avg_mag_sqrd_x</block> + <block>gr_probe_density_b</block> + <block>gr_probe_signal_f</block> + </cat> + <cat> + <name>Variables</name> + <block>variable</block> + <block>variable_config</block> + <block>variable_function_probe</block> + <block>parameter</block> + </cat> + <cat> + <name>Misc</name> + <block>note</block> + <block>import</block> + + <block>gr_throttle</block> + <block>gr_delay</block> + <block>gr_repeat</block> + + <block>blks2_selector</block> + <block>blks2_valve</block> + <block>blks2_error_rate</block> + + <block>gr_head</block> + <block>gr_skiphead</block> + + <block>gr_kludge_copy</block> + <block>gr_copy</block> + <block>gr_nop</block> + + <block>xmlrpc_server</block> + <block>xmlrpc_client</block> + </cat> +</cat> diff --git a/grc/blocks/const_source_x.xml b/grc/blocks/const_source_x.xml new file mode 100644 index 000000000..fe8e56ec4 --- /dev/null +++ b/grc/blocks/const_source_x.xml @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Constant Source: Custom wrapper +################################################### + --> +<block> + <name>Constant Source</name> + <key>const_source_x</key> + <import>from gnuradio import gr</import> + <make>gr.sig_source_$(type.fcn)(0, gr.GR_CONST_WAVE, 0, 0, $const)</make> + <callback>set_offset($const)</callback> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:c</opt> + <opt>const_type:complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + <opt>const_type:real</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:i</opt> + <opt>const_type:int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:s</opt> + <opt>const_type:int</opt> + </option> + </param> + <param> + <name>Constant</name> + <key>const</key> + <value>0</value> + <type>$type.const_type</type> + </param> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_add_const_vxx.xml b/grc/blocks/gr_add_const_vxx.xml new file mode 100644 index 000000000..9f1c545ab --- /dev/null +++ b/grc/blocks/gr_add_const_vxx.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Add Const Block: +## all types, 1 output, 1 input & const +################################################### + --> +<block> + <name>Add Const</name> + <key>gr_add_const_vxx</key> + <import>from gnuradio import gr</import> + <make>gr.add_const_v$(type.fcn)($const)</make> + <callback>set_k($const)</callback> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>const_type:complex_vector</opt> + <opt>fcn:cc</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>const_type:real_vector</opt> + <opt>fcn:ff</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>const_type:int_vector</opt> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>const_type:int_vector</opt> + <opt>fcn:ss</opt> + </option> + </param> + <param> + <name>Constant</name> + <key>const</key> + <value>0</value> + <type>$type.const_type</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>len($const) == $vlen</check> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_add_xx.xml b/grc/blocks/gr_add_xx.xml new file mode 100644 index 000000000..97ed9283c --- /dev/null +++ b/grc/blocks/gr_add_xx.xml @@ -0,0 +1,63 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Add Block: +## all types, 1 output, 2 to inf inputs +################################################### + --> +<block> + <name>Add</name> + <key>gr_add_xx</key> + <import>from gnuradio import gr</import> + <make>gr.add_v$(type.fcn)($vlen)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:cc</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + </param> + <param> + <name>Num Inputs</name> + <key>num_inputs</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_inputs > 1</check> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_inputs</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_additive_scrambler_bb.xml b/grc/blocks/gr_additive_scrambler_bb.xml new file mode 100644 index 000000000..a15d6eefb --- /dev/null +++ b/grc/blocks/gr_additive_scrambler_bb.xml @@ -0,0 +1,44 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Additive Scrambler +################################################### + --> +<block> + <name>Additive Scrambler</name> + <key>gr_additive_scrambler_bb</key> + <import>from gnuradio import gr</import> + <make>gr.additive_scrambler_bb($mask, $seed, $len, $count)</make> + <param> + <name>Mask</name> + <key>mask</key> + <value>0x8A</value> + <type>hex</type> + </param> + <param> + <name>Seed</name> + <key>seed</key> + <value>0x7F</value> + <type>hex</type> + </param> + <param> + <name>Length</name> + <key>len</key> + <value>7</value> + <type>int</type> + </param> + <param> + <name>Count</name> + <key>count</key> + <value>0</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/grc/blocks/gr_agc2_xx.xml b/grc/blocks/gr_agc2_xx.xml new file mode 100644 index 000000000..55b20d4e8 --- /dev/null +++ b/grc/blocks/gr_agc2_xx.xml @@ -0,0 +1,70 @@ +<?xml version="1.0"?> +<!-- +################################################### +##AGC2 +################################################### + --> +<block> + <name>AGC2</name> + <key>gr_agc2_xx</key> + <import>from gnuradio import gr</import> + <make>gr.agc2_$(type.fcn)($attack_rate, $decay_rate, $reference, $gain, $max_gain)</make> + <callback>set_attack_rate($attack_rate)</callback> + <callback>set_decay_rate($decay_rate)</callback> + <callback>set_reference($reference)</callback> + <callback>set_gain($gain)</callback> + <callback>set_max_gain($max_gain)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:cc</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + </option> + </param> + <param> + <name>Attack Rate</name> + <key>attack_rate</key> + <value>1e-1</value> + <type>real</type> + </param> + <param> + <name>Decay Rate</name> + <key>decay_rate</key> + <value>1e-2</value> + <type>real</type> + </param> + <param> + <name>Reference</name> + <key>reference</key> + <value>1.0</value> + <type>real</type> + </param> + <param> + <name>Gain</name> + <key>gain</key> + <value>1.0</value> + <type>real</type> + </param> + <param> + <name>Max Gain</name> + <key>max_gain</key> + <value>0.0</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_agc_xx.xml b/grc/blocks/gr_agc_xx.xml new file mode 100644 index 000000000..c87d239ed --- /dev/null +++ b/grc/blocks/gr_agc_xx.xml @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<!-- +################################################### +##AGC +################################################### + --> +<block> + <name>AGC</name> + <key>gr_agc_xx</key> + <import>from gnuradio import gr</import> + <make>gr.agc_$(type.fcn)($rate, $reference, $gain, $max_gain)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:cc</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + </option> + </param> + <param> + <name>Rate</name> + <key>rate</key> + <value>1e-4</value> + <type>real</type> + </param> + <param> + <name>Reference</name> + <key>reference</key> + <value>1.0</value> + <type>real</type> + </param> + <param> + <name>Gain</name> + <key>gain</key> + <value>1.0</value> + <type>real</type> + </param> + <param> + <name>Max Gain</name> + <key>max_gain</key> + <value>0.0</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_and_const_xx.xml b/grc/blocks/gr_and_const_xx.xml new file mode 100644 index 000000000..dc9649311 --- /dev/null +++ b/grc/blocks/gr_and_const_xx.xml @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<!-- +################################################### +## And Const Block: +## all types, 1 output, 1 input & const +################################################### + --> +<block> + <name>And Const</name> + <key>gr_and_const_xx</key> + <import>from gnuradio import gr</import> + <make>gr.and_const_$(type.fcn)($const)</make> + <callback>set_k($const)</callback> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:bb</opt> + </option> + </param> + <param> + <name>Constant</name> + <key>const</key> + <value>0</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_and_xx.xml b/grc/blocks/gr_and_xx.xml new file mode 100644 index 000000000..9ed006090 --- /dev/null +++ b/grc/blocks/gr_and_xx.xml @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Logical And Block +################################################### + --> +<block> + <name>And</name> + <key>gr_and_xx</key> + <import>from gnuradio import gr</import> + <make>gr.and_$(type.fcn)()</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:bb</opt> + </option> + </param> + <param> + <name>Num Inputs</name> + <key>num_inputs</key> + <value>2</value> + <type>int</type> + </param> + <check>$num_inputs >= 2</check> + <sink> + <name>in</name> + <type>$type</type> + <nports>$num_inputs</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_argmax_xx.xml b/grc/blocks/gr_argmax_xx.xml new file mode 100644 index 000000000..95269292e --- /dev/null +++ b/grc/blocks/gr_argmax_xx.xml @@ -0,0 +1,61 @@ +<?xml version="1.0"?> +<!-- +################################################### +##ArgMax: +## 1 output, 2 to inf inputs +################################################### + --> +<block> + <name>Argmax</name> + <key>gr_argmax_xx</key> + <import>from gnuradio import gr</import> + <make>gr.argmax_$(type.fcn)($vlen)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:fs</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:is</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:dd</opt> + </option> + </param> + <param> + <name>Num Inputs</name> + <key>num_inputs</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_inputs >= 1</check> + <check>$vlen >= 1</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_inputs</nports> + </sink> + <source> + <name>max_vec</name> + <type>short</type> + </source> + <source> + <name>max_inp</name> + <type>short</type> + </source> +</block> diff --git a/grc/blocks/gr_burst_tagger.xml b/grc/blocks/gr_burst_tagger.xml new file mode 100644 index 000000000..58c909999 --- /dev/null +++ b/grc/blocks/gr_burst_tagger.xml @@ -0,0 +1,87 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Burst tagger: +## all types, 1 output, 2 input: stream & trigger (short) +################################################### + --> +<block> + <name>Burst Tagger</name> + <key>gr_burst_tagger</key> + <import>from gnuradio import gr</import> + <make>gr.burst_tagger($type.size) +self.$(id).set_true_tag($true_key,$true_value) +self.$(id).set_false_tag($false_key,$false_value) + </make> + <callback>set_true_tag($true_key,$true_value)</callback> + <callback>set_false_tag($false_key,$false_value)</callback> + <param> + <name>Stream Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>True KeyID</name> + <key>true_key</key> + <value>burst</value> + <type>string</type> + </param> + <param> + <name>True Value</name> + <key>true_value</key> + <value>True</value> + <type>bool</type> + </param> + <param> + <name>False KeyID</name> + <key>false_key</key> + <value>burst</value> + <type>string</type> + </param> + <param> + <name>False Value</name> + <key>false_value</key> + <value>False</value> + <type>bool</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + <vlen>1</vlen> + </sink> + <sink> + <name>trigger</name> + <type>short</type> + <vlen>1</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>1</vlen> + </source> +</block> diff --git a/grc/blocks/gr_channel_model.xml b/grc/blocks/gr_channel_model.xml new file mode 100644 index 000000000..d0d178d34 --- /dev/null +++ b/grc/blocks/gr_channel_model.xml @@ -0,0 +1,61 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Channel Model +################################################### + --> +<block> + <name>Channel Model</name> + <key>gr_channel_model</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <make>gr.channel_model( + noise_voltage=$noise_voltage, + frequency_offset=$freq_offset, + epsilon=$epsilon, + taps=$taps, + noise_seed=$seed, +)</make> + <callback>set_noise_voltage($noise_voltage)</callback> + <callback>set_frequency_offset($freq_offset)</callback> + <callback>set_taps($taps)</callback> + <callback>set_timing_offset($epsilon)</callback> + <param> + <name>Noise Voltage</name> + <key>noise_voltage</key> + <value>0.0</value> + <type>real</type> + </param> + <param> + <name>Frequency Offset</name> + <key>freq_offset</key> + <value>0.0</value> + <type>real</type> + </param> + <param> + <name>Epsilon</name> + <key>epsilon</key> + <value>1.0</value> + <type>real</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <value>1.0 + 1.0j</value> + <type>complex_vector</type> + </param> + <param> + <name>Seed</name> + <key>seed</key> + <value>0</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_char_to_float.xml b/grc/blocks/gr_char_to_float.xml new file mode 100644 index 000000000..838b6a203 --- /dev/null +++ b/grc/blocks/gr_char_to_float.xml @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Char to Float: +################################################### + --> +<block> + <name>Char To Float</name> + <key>gr_char_to_float</key> + <import>from gnuradio import gr</import> + <make>gr.char_to_float($vlen, $scale)</make> + <callback>set_scale($scale)</callback> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Scale</name> + <key>scale</key> + <value>1</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>float</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_char_to_short.xml b/grc/blocks/gr_char_to_short.xml new file mode 100644 index 000000000..57261e084 --- /dev/null +++ b/grc/blocks/gr_char_to_short.xml @@ -0,0 +1,28 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Char to Short: +################################################### + --> +<block> + <name>Char To Short</name> + <key>gr_char_to_short</key> + <import>from gnuradio import gr</import> + <make>gr.char_to_short($vlen)</make> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>short</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_chunks_to_symbols.xml b/grc/blocks/gr_chunks_to_symbols.xml new file mode 100644 index 000000000..e9da38e9a --- /dev/null +++ b/grc/blocks/gr_chunks_to_symbols.xml @@ -0,0 +1,77 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Chunks to Symbols +################################################### + --> +<block> + <name>Chunks to Symbols</name> + <key>gr_chunks_to_symbols_xx</key> + <import>from gnuradio import gr</import> + <make>gr.chunks_to_symbols_$(in_type.fcn)$(out_type.fcn)($symbol_table, $dimension)</make> + <param> + <name>Input Type</name> + <key>in_type</key> + <type>enum</type> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:i</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:s</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:b</opt> + </option> + </param> + <param> + <name>Output Type</name> + <key>out_type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:c</opt> + <opt>table:complex_vector</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + <opt>table:real_vector</opt> + </option> + </param> + <param> + <name>Symbol Table</name> + <key>symbol_table</key> + <type>$out_type.table</type> + </param> + <param> + <name>Dimension</name> + <key>dimension</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Num Ports</name> + <key>num_ports</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_ports > 0</check> + <sink> + <name>in</name> + <type>$in_type</type> + <nports>$num_ports</nports> + </sink> + <source> + <name>out</name> + <type>$out_type</type> + <nports>$num_ports</nports> + </source> +</block> diff --git a/grc/blocks/gr_complex_to_arg.xml b/grc/blocks/gr_complex_to_arg.xml new file mode 100644 index 000000000..a7bbacd74 --- /dev/null +++ b/grc/blocks/gr_complex_to_arg.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Complex to Arg +################################################### + --> +<block> + <name>Complex to Arg</name> + <key>gr_complex_to_arg</key> + <import>from gnuradio import gr</import> + <make>gr.complex_to_arg($vlen)</make> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>complex</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>float</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_complex_to_float.xml b/grc/blocks/gr_complex_to_float.xml new file mode 100644 index 000000000..05681b0b9 --- /dev/null +++ b/grc/blocks/gr_complex_to_float.xml @@ -0,0 +1,36 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Complex to Float: +## one or two output streams +################################################### + --> +<block> + <name>Complex To Float</name> + <key>gr_complex_to_float</key> + <import>from gnuradio import gr</import> + <make>gr.complex_to_float($vlen)</make> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>complex</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>re</name> + <type>float</type> + <vlen>$vlen</vlen> + </source> + <source> + <name>im</name> + <type>float</type> + <vlen>$vlen</vlen> + <optional>1</optional> + </source> +</block> diff --git a/grc/blocks/gr_complex_to_imag.xml b/grc/blocks/gr_complex_to_imag.xml new file mode 100644 index 000000000..7c120eedd --- /dev/null +++ b/grc/blocks/gr_complex_to_imag.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Complex to Imaginary +################################################### + --> +<block> + <name>Complex to Imag</name> + <key>gr_complex_to_imag</key> + <import>from gnuradio import gr</import> + <make>gr.complex_to_imag($vlen)</make> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>complex</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>float</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_complex_to_interleaved_short.xml b/grc/blocks/gr_complex_to_interleaved_short.xml new file mode 100644 index 000000000..5e999599a --- /dev/null +++ b/grc/blocks/gr_complex_to_interleaved_short.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Complex to Interleaved Short: +################################################### + --> +<block> + <name>Complex To IShort</name> + <key>gr_complex_to_interleaved_short</key> + <import>from gnuradio import gr</import> + <make>gr.complex_to_interleaved_short()</make> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>short</type> + </source> +</block> diff --git a/grc/blocks/gr_complex_to_mag.xml b/grc/blocks/gr_complex_to_mag.xml new file mode 100644 index 000000000..adc95f207 --- /dev/null +++ b/grc/blocks/gr_complex_to_mag.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Complex to Magnitude +################################################### + --> +<block> + <name>Complex to Mag</name> + <key>gr_complex_to_mag</key> + <import>from gnuradio import gr</import> + <make>gr.complex_to_mag($vlen)</make> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>complex</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>float</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_complex_to_mag_squared.xml b/grc/blocks/gr_complex_to_mag_squared.xml new file mode 100644 index 000000000..cd23bfb5c --- /dev/null +++ b/grc/blocks/gr_complex_to_mag_squared.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Complex to Magnitude Squared +################################################### + --> +<block> + <name>Complex to Mag^2</name> + <key>gr_complex_to_mag_squared</key> + <import>from gnuradio import gr</import> + <make>gr.complex_to_mag_squared($vlen)</make> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>complex</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>float</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_complex_to_real.xml b/grc/blocks/gr_complex_to_real.xml new file mode 100644 index 000000000..ae9ec7b14 --- /dev/null +++ b/grc/blocks/gr_complex_to_real.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Complex to Real +################################################### + --> +<block> + <name>Complex to Real</name> + <key>gr_complex_to_real</key> + <import>from gnuradio import gr</import> + <make>gr.complex_to_real($vlen)</make> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>complex</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>float</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_conjugate_cc.xml b/grc/blocks/gr_conjugate_cc.xml new file mode 100644 index 000000000..0b4deb347 --- /dev/null +++ b/grc/blocks/gr_conjugate_cc.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Complex Conjugate +################################################### + --> +<block> + <name>Complex Conjugate</name> + <key>gr_conjugate_cc</key> + <import>from gnuradio import gr</import> + <make>gr.conjugate_cc()</make> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_copy.xml b/grc/blocks/gr_copy.xml new file mode 100644 index 000000000..8b12eaca7 --- /dev/null +++ b/grc/blocks/gr_copy.xml @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Copy +################################################### + --> +<block> + <name>Copy</name> + <key>gr_copy</key> + <import>from gnuradio import gr</import> + <make>gr.copy($type.size*$vlen) +self.$(id).set_enabled($enabled)</make> + <callback>set_enabled($enabled)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Enabled</name> + <key>enabled</key> + <value>True</value> + <type>bool</type> + <option> + <name>Enabled</name> + <key>True</key> + </option> + <option> + <name>Disabled</name> + <key>False</key> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_cpfsk_bc.xml b/grc/blocks/gr_cpfsk_bc.xml new file mode 100644 index 000000000..d5549d933 --- /dev/null +++ b/grc/blocks/gr_cpfsk_bc.xml @@ -0,0 +1,37 @@ +<?xml version="1.0"?> +<!-- +################################################### +##CPFSK +################################################### + --> +<block> + <name>CPFSK</name> + <key>gr_cpfsk_bc</key> + <import>from gnuradio import gr</import> + <make>gr.cpfsk_bc($k, $amplitude, $samples_per_symbol)</make> + <callback>set_amplitude($amplitude)</callback> + <param> + <name>K</name> + <key>k</key> + <type>real</type> + </param> + <param> + <name>Amplitude</name> + <key>amplitude</key> + <type>real</type> + </param> + <param> + <name>Samples/Symbol</name> + <key>samples_per_symbol</key> + <value>2</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_ctcss_squelch_ff.xml b/grc/blocks/gr_ctcss_squelch_ff.xml new file mode 100644 index 000000000..a34c75374 --- /dev/null +++ b/grc/blocks/gr_ctcss_squelch_ff.xml @@ -0,0 +1,79 @@ +<?xml version="1.0"?> +<!-- +# +# Copyright 2011 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. +--> + +<!-- +################################################### +##CTCSS Squelch +################################################### + --> +<block> + <name>CTCSS Squelch</name> + <key>gr_ctcss_squelch_ff</key> + <import>from gnuradio import gr</import> + <make>gr.ctcss_squelch_ff($rate, $freq, $level, $len, $ramp, $gate)</make> + <callback>set_level($level)</callback> + <param> + <name>Sampling Rate (Hz)</name> + <key>rate</key> + <value>samp_rate</value> + <type>real</type> + </param> + <param> + <name>Tone Frequency</name> + <key>freq</key> + <value>100.0</value> + <type>real</type> + </param> + <param> + <name>Level</name> + <key>level</key> + <value>0.01</value> + <type>real</type> + </param> + <param> + <name>Length</name> + <key>len</key> + <value>0</value> + <type>int</type> + </param> + <param> + <name>Ramp</name> + <key>ramp</key> + <value>0</value> + <type>int</type> + </param> + <param> + <name>Gate</name> + <key>gate</key> + <value>False</value> + <type>bool</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/gr_dc_blocker.xml b/grc/blocks/gr_dc_blocker.xml new file mode 100644 index 000000000..05c342074 --- /dev/null +++ b/grc/blocks/gr_dc_blocker.xml @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<!-- +################################################### +## DC Blocker +################################################### + --> +<block> + <name>DC Blocker</name> + <key>gr_dc_blocker</key> + <import>from gnuradio import gr</import> + <make>gr.dc_blocker_$(type)($length, $long_form)</make> + <!-- <callback>set_length($length)</callback> --> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex->Complex</name> + <key>cc</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + </option> + <option> + <name>Float->Float</name> + <key>ff</key> + <opt>input:float</opt> + <opt>output:float</opt> + </option> + </param> + <param> + <name>Length</name> + <key>length</key> + <value>32</value> + <type>int</type> + </param> + <param> + <name>Long Form</name> + <key>long_form</key> + <value>True</value> + <type>bool</type> + </param> + + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> +</block> diff --git a/grc/blocks/gr_decode_ccsds_27_fb.xml b/grc/blocks/gr_decode_ccsds_27_fb.xml new file mode 100644 index 000000000..03b31db83 --- /dev/null +++ b/grc/blocks/gr_decode_ccsds_27_fb.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Decode CCSDS 27 +################################################### + --> +<block> + <name>Decode CCSDS 27</name> + <key>gr_decode_ccsds_27_fb</key> + <import>from gnuradio import gr</import> + <make>gr.decode_ccsds_27_fb()</make> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/grc/blocks/gr_deinterleave.xml b/grc/blocks/gr_deinterleave.xml new file mode 100644 index 000000000..a7482978c --- /dev/null +++ b/grc/blocks/gr_deinterleave.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Deinterleave +################################################### + --> +<block> + <name>Deinterleave</name> + <key>gr_deinterleave</key> + <import>from gnuradio import gr</import> + <make>gr.deinterleave($type.size*$vlen)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Num Streams</name> + <key>num_streams</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_streams > 0</check> + <check>$vlen >= 1</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_streams</nports> + </source> +</block> diff --git a/grc/blocks/gr_delay.xml b/grc/blocks/gr_delay.xml new file mode 100644 index 000000000..5cc411a78 --- /dev/null +++ b/grc/blocks/gr_delay.xml @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Delay +################################################### + --> +<block> + <name>Delay</name> + <key>gr_delay</key> + <import>from gnuradio import gr</import> + <make>gr.delay($type.size*$vlen, $delay)</make> + <callback>set_delay($delay)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Delay</name> + <key>delay</key> + <value>0</value> + <type>int</type> + </param> + <param> + <name>Num Ports</name> + <key>num_ports</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_ports > 0</check> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_ports</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_ports</nports> + </source> +</block> diff --git a/grc/blocks/gr_descrambler_bb.xml b/grc/blocks/gr_descrambler_bb.xml new file mode 100644 index 000000000..5cfbcc203 --- /dev/null +++ b/grc/blocks/gr_descrambler_bb.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Descrambler +################################################### + --> +<block> + <name>Descrambler</name> + <key>gr_descrambler_bb</key> + <import>from gnuradio import gr</import> + <make>gr.descrambler_bb($mask, $seed, $len)</make> + <param> + <name>Mask</name> + <key>mask</key> + <value>0x8A</value> + <type>hex</type> + </param> + <param> + <name>Seed</name> + <key>seed</key> + <value>0x7F</value> + <type>hex</type> + </param> + <param> + <name>Length</name> + <key>len</key> + <value>7</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/grc/blocks/gr_diff_decoder_bb.xml b/grc/blocks/gr_diff_decoder_bb.xml new file mode 100644 index 000000000..ea7cf1734 --- /dev/null +++ b/grc/blocks/gr_diff_decoder_bb.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Differential Decoder +################################################### + --> +<block> + <name>Differential Decoder</name> + <key>gr_diff_decoder_bb</key> + <import>from gnuradio import gr</import> + <make>gr.diff_decoder_bb($modulus)</make> + <param> + <name>Modulus</name> + <key>modulus</key> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/grc/blocks/gr_diff_encoder_bb.xml b/grc/blocks/gr_diff_encoder_bb.xml new file mode 100644 index 000000000..21241eac2 --- /dev/null +++ b/grc/blocks/gr_diff_encoder_bb.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Differential Encoder +################################################### + --> +<block> + <name>Differential Encoder</name> + <key>gr_diff_encoder_bb</key> + <import>from gnuradio import gr</import> + <make>gr.diff_encoder_bb($modulus)</make> + <param> + <name>Modulus</name> + <key>modulus</key> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/grc/blocks/gr_diff_phasor_cc.xml b/grc/blocks/gr_diff_phasor_cc.xml new file mode 100644 index 000000000..2b2d7e372 --- /dev/null +++ b/grc/blocks/gr_diff_phasor_cc.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Differential Phasor +################################################### + --> +<block> + <name>Differential Phasor</name> + <key>gr_diff_phasor_cc</key> + <import>from gnuradio import gr</import> + <make>gr.diff_phasor_cc()</make> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_divide_xx.xml b/grc/blocks/gr_divide_xx.xml new file mode 100644 index 000000000..04667bc2a --- /dev/null +++ b/grc/blocks/gr_divide_xx.xml @@ -0,0 +1,63 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Divide Block: +## all types, 1 output, 2 to inf inputs +################################################### + --> +<block> + <name>Divide</name> + <key>gr_divide_xx</key> + <import>from gnuradio import gr</import> + <make>gr.divide_$(type.fcn)($vlen)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:cc</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Num Inputs</name> + <key>num_inputs</key> + <value>2</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <check>$num_inputs >= 2</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_inputs</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_dpll_bb.xml b/grc/blocks/gr_dpll_bb.xml new file mode 100644 index 000000000..044d398ff --- /dev/null +++ b/grc/blocks/gr_dpll_bb.xml @@ -0,0 +1,30 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Detect Peak +################################################### + --> +<block> + <name>Detect Peak</name> + <key>gr_dpll_bb</key> + <import>from gnuradio import gr</import> + <make>gr.dpll_bb($period, $gain)</make> + <param> + <name>Period</name> + <key>period</key> + <type>real</type> + </param> + <param> + <name>Gain</name> + <key>gain</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/grc/blocks/gr_encode_ccsds_27_bb.xml b/grc/blocks/gr_encode_ccsds_27_bb.xml new file mode 100644 index 000000000..f31e6b6c8 --- /dev/null +++ b/grc/blocks/gr_encode_ccsds_27_bb.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Encode CCSDS 27 +################################################### + --> +<block> + <name>Encode CCSDS 27</name> + <key>gr_encode_ccsds_27_bb</key> + <import>from gnuradio import gr</import> + <make>gr.encode_ccsds_27_bb()</make> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/grc/blocks/gr_endian_swap.xml b/grc/blocks/gr_endian_swap.xml new file mode 100644 index 000000000..aa564026c --- /dev/null +++ b/grc/blocks/gr_endian_swap.xml @@ -0,0 +1,41 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Add Block: +## all types, 1 output, 2 to inf inputs +################################################### + --> +<block> + <name>Endian Swap</name> + <key>gr_endian_swap</key> + <import>from gnuradio import gr</import> + <make>gr.endian_swap($type.size)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:8</opt> + </option> + <option> + <name>Int</name> + <key>s32</key> + <opt>size:4</opt> + </option> + <option> + <name>Short</name> + <key>s16</key> + <opt>size:2</opt> + </option> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_feedforward_agc_cc.xml b/grc/blocks/gr_feedforward_agc_cc.xml new file mode 100644 index 000000000..24e80953f --- /dev/null +++ b/grc/blocks/gr_feedforward_agc_cc.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Feed Forward AGC +################################################### + --> +<block> + <name>Feed Forward AGC</name> + <key>gr_feedforward_agc_cc</key> + <import>from gnuradio import gr</import> + <make>gr.feedforward_agc_cc($num_samples, $reference)</make> + <param> + <name>Num Samples</name> + <key>num_samples</key> + <value>1024</value> + <type>int</type> + </param> + <param> + <name>Reference</name> + <key>reference</key> + <value>1.0</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_fft_filter_xxx.xml b/grc/blocks/gr_fft_filter_xxx.xml new file mode 100644 index 000000000..5b4cd83cc --- /dev/null +++ b/grc/blocks/gr_fft_filter_xxx.xml @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<!-- +################################################### +##FFT Filter +################################################### + --> +<block> + <name>FFT Filter</name> + <key>gr_fft_filter_xxx</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <make>gr.fft_filter_$(type)($decim, $taps, $nthreads)</make> + <callback>set_taps($taps)</callback> + <callback>set_nthreads($nthreads)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex->Complex (Complex Taps)</name> + <key>ccc</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + <option> + <name>Float->Float (Real Taps)</name> + <key>fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + <opt>taps:real_vector</opt> + </option> + </param> + <param> + <name>Decimation</name> + <key>decim</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <type>$type.taps</type> + </param> + <param> + <name>Num. Threads</name> + <key>nthreads</key> + <value>1</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> +</block> diff --git a/grc/blocks/gr_fft_vxx.xml b/grc/blocks/gr_fft_vxx.xml new file mode 100644 index 000000000..565354e41 --- /dev/null +++ b/grc/blocks/gr_fft_vxx.xml @@ -0,0 +1,88 @@ +<?xml version="1.0"?> +<!-- +################################################### +##FFT +################################################### + --> +<block> + <name>FFT</name> + <key>gr_fft_vxx</key> + <import>from gnuradio import gr</import> + <import>from gnuradio import window</import> + <make>#if $type() == "complex" +gr.fft_vcc($fft_size, $forward, $window, $shift, $nthreads) +#else +gr.fft_vfc($fft_size, $forward, $window, $nthreads) +#end if</make> + <callback>set_nthreads($nthreads)</callback> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>hide_shift:</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>hide_shift:all</opt> + </option> + </param> + <param> + <name>FFT Size</name> + <key>fft_size</key> + <value>1024</value> + <type>int</type> + </param> + <param> + <name>Forward/Reverse</name> + <key>forward</key> + <type>enum</type> + <option> + <name>Forward</name> + <key>True</key> + </option> + <option> + <name>Reverse</name> + <key>False</key> + </option> + </param> + <param> + <name>Window</name> + <key>window</key> + <value>window.blackmanharris(1024)</value> + <type>real_vector</type> + </param> + <param> + <name>Shift</name> + <key>shift</key> + <type>enum</type> + <hide>$type.hide_shift</hide> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + </param> + <param> + <name>Num. Threads</name> + <key>nthreads</key> + <value>1</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$fft_size</vlen> + </sink> + <source> + <name>out</name> + <type>complex</type> + <vlen>$fft_size</vlen> + </source> +</block> diff --git a/grc/blocks/gr_file_sink.xml b/grc/blocks/gr_file_sink.xml new file mode 100644 index 000000000..d0a693900 --- /dev/null +++ b/grc/blocks/gr_file_sink.xml @@ -0,0 +1,78 @@ +<?xml version="1.0"?> +<!-- +################################################### +##File Sink +################################################### + --> +<block> + <name>File Sink</name> + <key>gr_file_sink</key> + <import>from gnuradio import gr</import> + <make>gr.file_sink($type.size*$vlen, $file) +self.$(id).set_unbuffered($unbuffered)</make> + <callback>set_unbuffered($unbuffered)</callback> + <callback>open($file)</callback> + <param> + <name>File</name> + <key>file</key> + <value></value> + <type>file_save</type> + </param> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Unbuffered</name> + <key>unbuffered</key> + <value>False</value> + <type>bool</type> + <option> + <name>Off</name> + <key>False</key> + </option> + <option> + <name>On</name> + <key>True</key> + </option> + </param> + + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> +</block> diff --git a/grc/blocks/gr_file_source.xml b/grc/blocks/gr_file_source.xml new file mode 100644 index 000000000..5f0e16b27 --- /dev/null +++ b/grc/blocks/gr_file_source.xml @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<!-- +################################################### +##File Source +################################################### + --> +<block> + <name>File Source</name> + <key>gr_file_source</key> + <import>from gnuradio import gr</import> + <make>gr.file_source($type.size*$vlen, $file, $repeat)</make> + <callback>open($file, $repeat)</callback> + <param> + <name>File</name> + <key>file</key> + <value></value> + <type>file_open</type> + </param> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Repeat</name> + <key>repeat</key> + <value>True</value> + <type>enum</type> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_filter_delay_fc.xml b/grc/blocks/gr_filter_delay_fc.xml new file mode 100644 index 000000000..30d65bf82 --- /dev/null +++ b/grc/blocks/gr_filter_delay_fc.xml @@ -0,0 +1,31 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Filter Delay +################################################### + --> +<block> + <name>Filter Delay</name> + <key>gr_filter_delay_fc</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <make>gr.filter_delay_fc($taps)</make> + <param> + <name>Taps</name> + <key>taps</key> + <type>real_vector</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <sink> + <name>in</name> + <type>float</type> + <optional>1</optional> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_fir_filter_xxx.xml b/grc/blocks/gr_fir_filter_xxx.xml new file mode 100644 index 000000000..c4de8f539 --- /dev/null +++ b/grc/blocks/gr_fir_filter_xxx.xml @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Decimating FIR Filter +################################################### + --> +<block> + <name>Decimating FIR Filter</name> + <key>gr_fir_filter_xxx</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <make>gr.fir_filter_$(type)($decim, $taps)</make> + <callback>set_taps($taps)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex->Complex (Complex Taps)</name> + <key>ccc</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + <option> + <name>Complex->Complex (Real Taps)</name> + <key>ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>taps:real_vector</opt> + </option> + <option> + <name>Float->Complex (Complex Taps)</name> + <key>fcc</key> + <opt>input:float</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + <option> + <name>Float->Float (Real Taps)</name> + <key>fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + <opt>taps:real_vector</opt> + </option> + <option> + <name>Float->Short (Real Taps)</name> + <key>fsf</key> + <opt>input:float</opt> + <opt>output:short</opt> + <opt>taps:real_vector</opt> + </option> + <option> + <name>Short->Complex (Complex Taps)</name> + <key>scc</key> + <opt>input:short</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + </param> + <param> + <name>Decimation</name> + <key>decim</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <type>$type.taps</type> + </param> + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> +</block> diff --git a/grc/blocks/gr_float_to_char.xml b/grc/blocks/gr_float_to_char.xml new file mode 100644 index 000000000..1fa500e3c --- /dev/null +++ b/grc/blocks/gr_float_to_char.xml @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Float to Char: +################################################### + --> +<block> + <name>Float To Char</name> + <key>gr_float_to_char</key> + <import>from gnuradio import gr</import> + <make>gr.float_to_char($vlen, $scale)</make> + <callback>set_scale($scale)</callback> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Scale</name> + <key>scale</key> + <value>1</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>byte</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_float_to_complex.xml b/grc/blocks/gr_float_to_complex.xml new file mode 100644 index 000000000..a42cff358 --- /dev/null +++ b/grc/blocks/gr_float_to_complex.xml @@ -0,0 +1,36 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Float to Complex: +## one or two input streams +################################################### + --> +<block> + <name>Float To Complex</name> + <key>gr_float_to_complex</key> + <import>from gnuradio import gr</import> + <make>gr.float_to_complex($vlen)</make> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>re</name> + <type>float</type> + <vlen>$vlen</vlen> + </sink> + <sink> + <name>im</name> + <type>float</type> + <vlen>$vlen</vlen> + <optional>1</optional> + </sink> + <source> + <name>out</name> + <type>complex</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_float_to_int.xml b/grc/blocks/gr_float_to_int.xml new file mode 100644 index 000000000..b43c208a5 --- /dev/null +++ b/grc/blocks/gr_float_to_int.xml @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Float to Int: +################################################### + --> +<block> + <name>Float To Int</name> + <key>gr_float_to_int</key> + <import>from gnuradio import gr</import> + <make>gr.float_to_int($vlen, $scale)</make> + <callback>set_scale($scale)</callback> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Scale</name> + <key>scale</key> + <value>1</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>int</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_float_to_short.xml b/grc/blocks/gr_float_to_short.xml new file mode 100644 index 000000000..4f76b8f58 --- /dev/null +++ b/grc/blocks/gr_float_to_short.xml @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Float to Short: +################################################### + --> +<block> + <name>Float To Short</name> + <key>gr_float_to_short</key> + <import>from gnuradio import gr</import> + <make>gr.float_to_short($vlen, $scale)</make> + <callback>set_scale($scale)</callback> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Scale</name> + <key>scale</key> + <value>1</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>short</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_float_to_uchar.xml b/grc/blocks/gr_float_to_uchar.xml new file mode 100644 index 000000000..aa804d7d9 --- /dev/null +++ b/grc/blocks/gr_float_to_uchar.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Float to Unsigned Char: +################################################### + --> +<block> + <name>Float To UChar</name> + <key>gr_float_to_uchar</key> + <import>from gnuradio import gr</import> + <make>gr.float_to_uchar()</make> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/grc/blocks/gr_fractional_interpolator_xx.xml b/grc/blocks/gr_fractional_interpolator_xx.xml new file mode 100644 index 000000000..8d65ff8bf --- /dev/null +++ b/grc/blocks/gr_fractional_interpolator_xx.xml @@ -0,0 +1,46 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Fractional Interpolator +################################################### + --> +<block> + <name>Fractional Interpolator</name> + <key>gr_fractional_interpolator_xx</key> + <import>from gnuradio import gr</import> + <make>gr.fractional_interpolator_$(type.fcn)($phase_shift, $interp_ratio)</make> + <callback>set_interp_ratio($interp_ratio)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:cc</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + </option> + </param> + <param> + <name>Phase Shift</name> + <key>phase_shift</key> + <type>real</type> + </param> + <param> + <name>Interpolation Ratio</name> + <key>interp_ratio</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_freq_xlating_fir_filter_xxx.xml b/grc/blocks/gr_freq_xlating_fir_filter_xxx.xml new file mode 100644 index 000000000..e3ee66977 --- /dev/null +++ b/grc/blocks/gr_freq_xlating_fir_filter_xxx.xml @@ -0,0 +1,93 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Frequency Xlating Filter +################################################### + --> +<block> + <name>Frequency Xlating FIR Filter</name> + <key>gr_freq_xlating_fir_filter_xxx</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <make>gr.freq_xlating_fir_filter_$(type)($decim, $taps, $center_freq, $samp_rate)</make> + <callback>set_taps($taps)</callback> + <callback>set_center_freq($center_freq)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex->Complex (Complex Taps)</name> + <key>ccc</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + <option> + <name>Complex->Complex (Real Taps)</name> + <key>ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>taps:real_vector</opt> + </option> + <option> + <name>Float->Complex (Complex Taps)</name> + <key>fcc</key> + <opt>input:float</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + <option> + <name>Float->Complex (Real Taps)</name> + <key>fcf</key> + <opt>input:float</opt> + <opt>output:complex</opt> + <opt>taps:real_vector</opt> + </option> + <option> + <name>Short->Complex (Complex Taps)</name> + <key>scc</key> + <opt>input:short</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + <option> + <name>Short->Complex (Real Taps)</name> + <key>scf</key> + <opt>input:short</opt> + <opt>output:complex</opt> + <opt>taps:real_vector</opt> + </option> + </param> + <param> + <name>Decimation</name> + <key>decim</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <type>$type.taps</type> + </param> + <param> + <name>Center Frequency</name> + <key>center_freq</key> + <value>0</value> + <type>real</type> + </param> + <param> + <name>Sample Rate</name> + <key>samp_rate</key> + <value>samp_rate</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> +</block> diff --git a/grc/blocks/gr_frequency_modulator_fc.xml b/grc/blocks/gr_frequency_modulator_fc.xml new file mode 100644 index 000000000..d5f8fcfe3 --- /dev/null +++ b/grc/blocks/gr_frequency_modulator_fc.xml @@ -0,0 +1,26 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Frequency Modulator +################################################### + --> +<block> + <name>Frequency Mod</name> + <key>gr_frequency_modulator_fc</key> + <import>from gnuradio import gr</import> + <make>gr.frequency_modulator_fc($sensitivity)</make> + <callback>set_sensitivity($sensitivity)</callback> + <param> + <name>Sensitivity</name> + <key>sensitivity</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_glfsr_source_x.xml b/grc/blocks/gr_glfsr_source_x.xml new file mode 100644 index 000000000..88fb66797 --- /dev/null +++ b/grc/blocks/gr_glfsr_source_x.xml @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<!-- +################################################### +##GLFSR Source +################################################### + --> +<block> + <name>GLFSR Source</name> + <key>gr_glfsr_source_x</key> + <import>from gnuradio import gr</import> + <make>gr.glfsr_source_$(type.fcn)($degree, $repeat, $mask, $seed)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:b</opt> + </option> + </param> + <param> + <name>Degree</name> + <key>degree</key> + <type>int</type> + </param> + <param> + <name>Repeat</name> + <key>repeat</key> + <type>enum</type> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + </param> + <param> + <name>Mask</name> + <key>mask</key> + <type>int</type> + </param> + <param> + <name>Seed</name> + <key>seed</key> + <type>int</type> + </param> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_goertzel_fc.xml b/grc/blocks/gr_goertzel_fc.xml new file mode 100644 index 000000000..f27d9582e --- /dev/null +++ b/grc/blocks/gr_goertzel_fc.xml @@ -0,0 +1,37 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Goertzel +################################################### + --> +<block> + <name>Goertzel</name> + <key>gr_goertzel_fc</key> + <import>from gnuradio import gr</import> + <make>gr.goertzel_fc($rate, $len, $freq)</make> + <callback>set_freq($freq)</callback> + <callback>set_rate($rate)</callback> + <param> + <name>Rate</name> + <key>rate</key> + <type>int</type> + </param> + <param> + <name>Length</name> + <key>len</key> + <type>int</type> + </param> + <param> + <name>Frequency</name> + <key>freq</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_head.xml b/grc/blocks/gr_head.xml new file mode 100644 index 000000000..e5ff7f6aa --- /dev/null +++ b/grc/blocks/gr_head.xml @@ -0,0 +1,65 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Head +################################################### + --> +<block> + <name>Head</name> + <key>gr_head</key> + <import>from gnuradio import gr</import> + <make>gr.head($type.size*$vlen, $num_items)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Num Items</name> + <key>num_items</key> + <value>1024</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_hilbert_fc.xml b/grc/blocks/gr_hilbert_fc.xml new file mode 100644 index 000000000..165e8da23 --- /dev/null +++ b/grc/blocks/gr_hilbert_fc.xml @@ -0,0 +1,26 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Hilbert +################################################### + --> +<block> + <name>Hilbert</name> + <key>gr_hilbert_fc</key> + <import>from gnuradio import gr</import> + <make>gr.hilbert_fc($num_taps)</make> + <param> + <name>Num Taps</name> + <key>num_taps</key> + <value>64</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_iir_filter_ffd.xml b/grc/blocks/gr_iir_filter_ffd.xml new file mode 100644 index 000000000..9799150e8 --- /dev/null +++ b/grc/blocks/gr_iir_filter_ffd.xml @@ -0,0 +1,31 @@ +<?xml version="1.0"?> +<!-- +################################################### +##IIR Filter +################################################### + --> +<block> + <name>IIR Filter</name> + <key>gr_iir_filter_ffd</key> + <import>from gnuradio import gr</import> + <make>gr.iir_filter_ffd($fftaps, $fbtaps)</make> + <callback>set_taps($fftaps, $fbtaps)</callback> + <param> + <name>Feed-forward Taps</name> + <key>fftaps</key> + <type>real_vector</type> + </param> + <param> + <name>Feedback Taps</name> + <key>fbtaps</key> + <type>real_vector</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/gr_int_to_float.xml b/grc/blocks/gr_int_to_float.xml new file mode 100644 index 000000000..7430fec72 --- /dev/null +++ b/grc/blocks/gr_int_to_float.xml @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Int to Float: +################################################### + --> +<block> + <name>Int To Float</name> + <key>gr_int_to_float</key> + <import>from gnuradio import gr</import> + <make>gr.int_to_float($vlen, $scale)</make> + <callback>set_scale($scale)</callback> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Scale</name> + <key>scale</key> + <value>1</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>int</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>float</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_integrate_xx.xml b/grc/blocks/gr_integrate_xx.xml new file mode 100644 index 000000000..d0ebd42e2 --- /dev/null +++ b/grc/blocks/gr_integrate_xx.xml @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Integrate +################################################### + --> +<block> + <name>Integrate</name> + <key>gr_integrate_xx</key> + <import>from gnuradio import gr</import> + <make>gr.integrate_$(type.fcn)($decim)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:cc</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + </param> + <param> + <name>Decimation</name> + <key>decim</key> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_interleave.xml b/grc/blocks/gr_interleave.xml new file mode 100644 index 000000000..3db16ab55 --- /dev/null +++ b/grc/blocks/gr_interleave.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Interleave +################################################### + --> +<block> + <name>Interleave</name> + <key>gr_interleave</key> + <import>from gnuradio import gr</import> + <make>gr.interleave($type.size*$vlen)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Num Streams</name> + <key>num_streams</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_streams > 0</check> + <check>$vlen >= 1</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_streams</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_interleaved_short_to_complex.xml b/grc/blocks/gr_interleaved_short_to_complex.xml new file mode 100644 index 000000000..e3023e499 --- /dev/null +++ b/grc/blocks/gr_interleaved_short_to_complex.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Interleaved Short to Complex: +################################################### + --> +<block> + <name>IShort To Complex</name> + <key>gr_interleaved_short_to_complex</key> + <import>from gnuradio import gr</import> + <make>gr.interleaved_short_to_complex()</make> + <sink> + <name>in</name> + <type>short</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_interp_fir_filter_xxx.xml b/grc/blocks/gr_interp_fir_filter_xxx.xml new file mode 100644 index 000000000..55375ae02 --- /dev/null +++ b/grc/blocks/gr_interp_fir_filter_xxx.xml @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Interpolating FIR Filter +################################################### + --> +<block> + <name>Interpolating FIR Filter</name> + <key>gr_interp_fir_filter_xxx</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <make>gr.interp_fir_filter_$(type)($interp, $taps)</make> + <callback>set_taps($taps)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex->Complex (Complex Taps)</name> + <key>ccc</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + <option> + <name>Complex->Complex (Real Taps)</name> + <key>ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>taps:real_vector</opt> + </option> + <option> + <name>Float->Complex (Complex Taps)</name> + <key>fcc</key> + <opt>input:float</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + <option> + <name>Float->Float (Real Taps)</name> + <key>fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + <opt>taps:real_vector</opt> + </option> + <option> + <name>Float->Short (Real Taps)</name> + <key>fsf</key> + <opt>input:float</opt> + <opt>output:short</opt> + <opt>taps:real_vector</opt> + </option> + <option> + <name>Short->Complex (Complex Taps)</name> + <key>scc</key> + <opt>input:short</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + </param> + <param> + <name>Interpolation</name> + <key>interp</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <type>$type.taps</type> + </param> + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> +</block> diff --git a/grc/blocks/gr_iqcomp_cc.xml b/grc/blocks/gr_iqcomp_cc.xml new file mode 100644 index 000000000..1603bdc42 --- /dev/null +++ b/grc/blocks/gr_iqcomp_cc.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> +<!-- +################################################### +##IQ Comp +################################################### + --> +<block> + <name>IQ Comp</name> + <key>gr_iqcomp_cc</key> + <import>from gnuradio import gr</import> + <make>gr.iqcomp_cc($mu)</make> + <param> + <name>Mu</name> + <key>mu</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_keep_m_in_n.xml b/grc/blocks/gr_keep_m_in_n.xml new file mode 100644 index 000000000..35a156176 --- /dev/null +++ b/grc/blocks/gr_keep_m_in_n.xml @@ -0,0 +1,76 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Keep M in N +################################################### + --> +<block> + <name>Keep M in N</name> + <key>gr_keep_m_in_n</key> + <import>from gnuradio import gr</import> + <make>gr.keep_m_in_n($type.size, $m, $n, $offset)</make> + <callback>set_offset($offset)</callback> + <callback>set_m($m)</callback> + <callback>set_n($n)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>M</name> + <key>m</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>N</name> + <key>n</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>initial offset</name> + <key>offset</key> + <value>0</value> + <type>int</type> + </param> + <check>$n > 0</check> + <check>$m > 0</check> + <check>$m < $n</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>1</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>1</vlen> + </source> +</block> diff --git a/grc/blocks/gr_keep_one_in_n.xml b/grc/blocks/gr_keep_one_in_n.xml new file mode 100644 index 000000000..21595b755 --- /dev/null +++ b/grc/blocks/gr_keep_one_in_n.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Keep 1 in N +################################################### + --> +<block> + <name>Keep 1 in N</name> + <key>gr_keep_one_in_n</key> + <import>from gnuradio import gr</import> + <make>gr.keep_one_in_n($type.size*$vlen, $n)</make> + <callback>set_n($n)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>N</name> + <key>n</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$n > 0</check> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_kludge_copy.xml b/grc/blocks/gr_kludge_copy.xml new file mode 100644 index 000000000..8058b082d --- /dev/null +++ b/grc/blocks/gr_kludge_copy.xml @@ -0,0 +1,68 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Kludge Copy +################################################### + --> +<block> + <name>Kludge Copy</name> + <key>gr_kludge_copy</key> + <import>from gnuradio import gr</import> + <make>gr.kludge_copy($type.size*$vlen)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Num Ports</name> + <key>num_ports</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_ports > 0</check> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_ports</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_ports</nports> + </source> +</block> diff --git a/grc/blocks/gr_map_bb.xml b/grc/blocks/gr_map_bb.xml new file mode 100644 index 000000000..20d6bd2b4 --- /dev/null +++ b/grc/blocks/gr_map_bb.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Map +################################################### + --> +<block> + <name>Map</name> + <key>gr_map_bb</key> + <import>from gnuradio import gr</import> + <make>gr.map_bb($map)</make> + <param> + <name>Map</name> + <key>map</key> + <type>int_vector</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/grc/blocks/gr_max_xx.xml b/grc/blocks/gr_max_xx.xml new file mode 100644 index 000000000..9dbbe60e5 --- /dev/null +++ b/grc/blocks/gr_max_xx.xml @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Max: +## 1 output, 2 to inf inputs +################################################### + --> +<block> + <name>Max</name> + <key>gr_max_xx</key> + <import>from gnuradio import gr</import> + <make>gr.max_$(type.fcn)($vlen)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:dd</opt> + </option> + </param> + <param> + <name>Num Inputs</name> + <key>num_inputs</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_inputs >= 2</check> + <check>$vlen >= 1</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_inputs</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_message_burst_source.xml b/grc/blocks/gr_message_burst_source.xml new file mode 100644 index 000000000..e835d2a2c --- /dev/null +++ b/grc/blocks/gr_message_burst_source.xml @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Message Burst Source (the sink port is a message) +################################################### + --> +<block> + <name>Message Burst Source</name> + <key>gr_message_burst_source</key> + <import>from gnuradio import gr</import> + <make>gr.message_burst_source($type.size*$vlen, $(id)_msgq_in)</make> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>msg</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_message_debug.xml b/grc/blocks/gr_message_debug.xml new file mode 100644 index 000000000..964f95756 --- /dev/null +++ b/grc/blocks/gr_message_debug.xml @@ -0,0 +1,27 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Message Debug +################################################### + --> +<block> + <name>Message Debug</name> + <key>gr_message_debug</key> + <import>from gnuradio import gr</import> + <make>gr.message_debug()</make> + <sink> + <name>print</name> + <type>message</type> + <optional>1</optional> + </sink> + <sink> + <name>store</name> + <type>message</type> + <optional>1</optional> + </sink> + <sink> + <name>print_pdu</name> + <type>message</type> + <optional>1</optional> + </sink> +</block> diff --git a/grc/blocks/gr_message_sink.xml b/grc/blocks/gr_message_sink.xml new file mode 100644 index 000000000..18e92adb9 --- /dev/null +++ b/grc/blocks/gr_message_sink.xml @@ -0,0 +1,72 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Message Sink (the source port is a message) +################################################### + --> +<block> + <name>Message Sink</name> + <key>gr_message_sink</key> + <import>from gnuradio import gr</import> + <make>gr.message_sink($type.size*$vlen, $(id)_msgq_out, $dont_block)</make> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Don't Block</name> + <key>dont_block</key> + <value>False</value> + <type>enum</type> + <option> + <name>Don't Block</name> + <key>True</key> + </option> + <option> + <name>Block</name> + <key>False</key> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>msg</type> + </source> +</block> diff --git a/grc/blocks/gr_message_source.xml b/grc/blocks/gr_message_source.xml new file mode 100644 index 000000000..72367b21b --- /dev/null +++ b/grc/blocks/gr_message_source.xml @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Message Source (the sink port is a message) +################################################### + --> +<block> + <name>Message Source</name> + <key>gr_message_source</key> + <import>from gnuradio import gr</import> + <make>gr.message_source($type.size*$vlen, $(id)_msgq_in)</make> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>msg</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_message_strobe.xml b/grc/blocks/gr_message_strobe.xml new file mode 100644 index 000000000..60a7724df --- /dev/null +++ b/grc/blocks/gr_message_strobe.xml @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Message Strobe +################################################### + --> +<block> + <name>Message Strobe</name> + <key>gr_message_strobe</key> + <import>from gnuradio import gr</import> + <import>from gruel import pmt</import> + <make>gr.message_strobe($msg, $period)</make> + <param> + <name>Message PMT</name> + <key>msg</key> + <value>pmt.pmt_intern("TEST")</value> + <type>raw</type> + </param> + <param> + <name>Period (ms)</name> + <key>period</key> + <value>1000</value> + <type>real</type> + </param> + <sink> + <name>set_msg</name> + <type>message</type> + <optional>1</optional> + </sink> + <source> + <name>strobe</name> + <type>message</type> + <optional>1</optional> + </source> +</block> diff --git a/grc/blocks/gr_moving_average_xx.xml b/grc/blocks/gr_moving_average_xx.xml new file mode 100644 index 000000000..b70943c78 --- /dev/null +++ b/grc/blocks/gr_moving_average_xx.xml @@ -0,0 +1,68 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Moving Average +################################################### + --> +<block> + <name>Moving Average</name> + <key>gr_moving_average_xx</key> + <import>from gnuradio import gr</import> + <make>gr.moving_average_$(type.fcn)($length, $scale, $max_iter)</make> + <callback>set_length_and_scale($length, $scale)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:cc</opt> + <opt>scale:complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + <opt>scale:real</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + <opt>scale:int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + <opt>scale:int</opt> + </option> + </param> + <param> + <name>Length</name> + <key>length</key> + <value>1000</value> + <type>int</type> + </param> + <param> + <name>Scale</name> + <key>scale</key> + <value>1</value> + <type>$type.scale</type> + </param> + <param> + <name>Max Iter</name> + <key>max_iter</key> + <value>4000</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_mpsk_sync_cc.xml b/grc/blocks/gr_mpsk_sync_cc.xml new file mode 100644 index 000000000..fd08f8340 --- /dev/null +++ b/grc/blocks/gr_mpsk_sync_cc.xml @@ -0,0 +1,69 @@ +<?xml version="1.0"?> +<!-- +################################################### +##MPSK Sync +################################################### + --> +<block> + <name>MPSK Sync</name> + <key>gr_mpsk_sync_cc</key> + <import>from gnuradio import gr</import> + <make>gr.mpsk_sync_cc($alpha, $beta, $max_freq, $min_freq, $ref_phase, $omega, $gain_omega, $mu, $gain_mu)</make> + <callback>set_mu($mu)</callback> + <callback>set_gain_mu($gain_mu)</callback> + <callback>set_omega($omega)</callback> + <callback>set_gain_omega($gain_omega)</callback> + <param> + <name>Alpha</name> + <key>alpha</key> + <type>real</type> + </param> + <param> + <name>Beta</name> + <key>beta</key> + <type>real</type> + </param> + <param> + <name>Max Freq</name> + <key>max_freq</key> + <type>real</type> + </param> + <param> + <name>Min Freq</name> + <key>min_freq</key> + <type>real</type> + </param> + <param> + <name>Reference Phase</name> + <key>ref_phase</key> + <type>real</type> + </param> + <param> + <name>Omega</name> + <key>omega</key> + <type>real</type> + </param> + <param> + <name>Gain Omega</name> + <key>gain_omega</key> + <type>real</type> + </param> + <param> + <name>Mu</name> + <key>mu</key> + <type>real</type> + </param> + <param> + <name>Gain Mu</name> + <key>gain_mu</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_multiply_const_vxx.xml b/grc/blocks/gr_multiply_const_vxx.xml new file mode 100644 index 000000000..1309d75cd --- /dev/null +++ b/grc/blocks/gr_multiply_const_vxx.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Multiply Const Block: +## all types, 1 output, 1 input & const +################################################### + --> +<block> + <name>Multiply Const</name> + <key>gr_multiply_const_vxx</key> + <import>from gnuradio import gr</import> + <make>gr.multiply_const_v$(type.fcn)($const)</make> + <callback>set_k($const)</callback> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>const_type:complex_vector</opt> + <opt>fcn:cc</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>const_type:real_vector</opt> + <opt>fcn:ff</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>const_type:int_vector</opt> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>const_type:int_vector</opt> + <opt>fcn:ss</opt> + </option> + </param> + <param> + <name>Constant</name> + <key>const</key> + <value>0</value> + <type>$type.const_type</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>len($const) == $vlen</check> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_multiply_xx.xml b/grc/blocks/gr_multiply_xx.xml new file mode 100644 index 000000000..60f65c274 --- /dev/null +++ b/grc/blocks/gr_multiply_xx.xml @@ -0,0 +1,63 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Multiply Block: +## all types, 1 output, 2 to inf inputs +################################################### + --> +<block> + <name>Multiply</name> + <key>gr_multiply_xx</key> + <import>from gnuradio import gr</import> + <make>gr.multiply_v$(type.fcn)($vlen)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:cc</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + </param> + <param> + <name>Num Inputs</name> + <key>num_inputs</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_inputs > 1</check> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_inputs</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_mute_xx.xml b/grc/blocks/gr_mute_xx.xml new file mode 100644 index 000000000..a9a857c6a --- /dev/null +++ b/grc/blocks/gr_mute_xx.xml @@ -0,0 +1,61 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Mute Block: +## Cast input to bool. +################################################### + --> +<block> + <name>Mute</name> + <key>gr_mute_xx</key> + <import>from gnuradio import gr</import> + <make>gr.mute_$(type.fcn)(bool($mute))</make> + <callback>set_mute(bool($mute))</callback> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:cc</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + </param> + <param> + <name>Mute</name> + <key>mute</key> + <value>False</value> + <type>raw</type> + <option> + <name>True</name> + <key>True</key> + </option> + <option> + <name>False</name> + <key>False</key> + </option> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_nlog10_ff.xml b/grc/blocks/gr_nlog10_ff.xml new file mode 100644 index 000000000..935078236 --- /dev/null +++ b/grc/blocks/gr_nlog10_ff.xml @@ -0,0 +1,42 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Log10 Block: +## float in/ float out +################################################### + --> +<block> + <name>Log10</name> + <key>gr_nlog10_ff</key> + <import>from gnuradio import gr</import> + <make>gr.nlog10_ff($n, $vlen, $k)</make> + <param> + <name>n</name> + <key>n</key> + <value>1</value> + <type>real</type> + </param> + <param> + <name>k</name> + <key>k</key> + <value>0</value> + <type>real</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen >= 1</check> + <sink> + <name>in</name> + <type>float</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>float</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_noise_source_x.xml b/grc/blocks/gr_noise_source_x.xml new file mode 100644 index 000000000..72daaaa20 --- /dev/null +++ b/grc/blocks/gr_noise_source_x.xml @@ -0,0 +1,77 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Noise Source +################################################### + --> +<block> + <name>Noise Source</name> + <key>gr_noise_source_x</key> + <import>from gnuradio import gr</import> + <make>gr.noise_source_$(type.fcn)($noise_type, $amp, $seed)</make> + <callback>set_type($noise_type)</callback> + <callback>set_amplitude($amp)</callback> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:c</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:i</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:s</opt> + </option> + </param> + <param> + <name>Noise Type</name> + <key>noise_type</key> + <value>gr.GR_GAUSSIAN</value> + <type>int</type> + <option> + <name>Uniform</name> + <key>gr.GR_UNIFORM</key> + </option> + <option> + <name>Gaussian</name> + <key>gr.GR_GAUSSIAN</key> + </option> + <option> + <name>Laplacian</name> + <key>gr.GR_LAPLACIAN</key> + </option> + <option> + <name>Impulse</name> + <key>gr.GR_IMPULSE</key> + </option> + </param> + <param> + <name>Amplitude</name> + <key>amp</key> + <value>1</value> + <type>real</type> + </param> + <param> + <name>Seed</name> + <key>seed</key> + <value>0</value> + <type>int</type> + </param> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_nop.xml b/grc/blocks/gr_nop.xml new file mode 100644 index 000000000..bd884d6b8 --- /dev/null +++ b/grc/blocks/gr_nop.xml @@ -0,0 +1,68 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Nop +################################################### + --> +<block> + <name>Nop</name> + <key>gr_nop</key> + <import>from gnuradio import gr</import> + <make>gr.nop($type.size*$vlen)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Num Ports</name> + <key>num_ports</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_ports > 0</check> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_ports</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_ports</nports> + </source> +</block> diff --git a/grc/blocks/gr_not_xx.xml b/grc/blocks/gr_not_xx.xml new file mode 100644 index 000000000..1c2bb8709 --- /dev/null +++ b/grc/blocks/gr_not_xx.xml @@ -0,0 +1,40 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Logical Not Block +################################################### + --> +<block> + <name>Not</name> + <key>gr_not_xx</key> + <import>from gnuradio import gr</import> + <make>gr.not_$(type.fcn)()</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:bb</opt> + </option> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_null_sink.xml b/grc/blocks/gr_null_sink.xml new file mode 100644 index 000000000..ed106b495 --- /dev/null +++ b/grc/blocks/gr_null_sink.xml @@ -0,0 +1,54 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Null Sink +################################################### + --> +<block> + <name>Null Sink</name> + <key>gr_null_sink</key> + <import>from gnuradio import gr</import> + <make>gr.null_sink($type.size*$vlen)</make> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> +</block> diff --git a/grc/blocks/gr_null_source.xml b/grc/blocks/gr_null_source.xml new file mode 100644 index 000000000..6132eae3c --- /dev/null +++ b/grc/blocks/gr_null_source.xml @@ -0,0 +1,54 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Null Source +################################################### + --> +<block> + <name>Null Source</name> + <key>gr_null_source</key> + <import>from gnuradio import gr</import> + <make>gr.null_source($type.size*$vlen)</make> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_or_xx.xml b/grc/blocks/gr_or_xx.xml new file mode 100644 index 000000000..b374aa22a --- /dev/null +++ b/grc/blocks/gr_or_xx.xml @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Logical Or Block +################################################### + --> +<block> + <name>Or</name> + <key>gr_or_xx</key> + <import>from gnuradio import gr</import> + <make>gr.or_$(type.fcn)()</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:bb</opt> + </option> + </param> + <param> + <name>Num Inputs</name> + <key>num_inputs</key> + <value>2</value> + <type>int</type> + </param> + <check>$num_inputs >= 2</check> + <sink> + <name>in</name> + <type>$type</type> + <nports>$num_inputs</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_pack_k_bits_bb.xml b/grc/blocks/gr_pack_k_bits_bb.xml new file mode 100644 index 000000000..34e64a5d9 --- /dev/null +++ b/grc/blocks/gr_pack_k_bits_bb.xml @@ -0,0 +1,30 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Pack K Bits +################################################### + --> +<block> + <name>Pack K Bits</name> + <key>gr_pack_k_bits_bb</key> + <import>from gnuradio import gr</import> + <make>gr.pack_k_bits_bb($k)</make> + <param> + <name>K</name> + <key>k</key> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> + + <doc> + Pack K unpacked bits (one bit per byte) into a single packed byte containing k bits and 8 - k zeros. + </doc> + +</block> diff --git a/grc/blocks/gr_packed_to_unpacked_xx.xml b/grc/blocks/gr_packed_to_unpacked_xx.xml new file mode 100644 index 000000000..c1477dd9c --- /dev/null +++ b/grc/blocks/gr_packed_to_unpacked_xx.xml @@ -0,0 +1,68 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Packed to Unpacked +################################################### + --> +<block> + <name>Packed to Unpacked</name> + <key>gr_packed_to_unpacked_xx</key> + <import>from gnuradio import gr</import> + <make>gr.packed_to_unpacked_$(type.fcn)($bits_per_chunk, $endianness)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:bb</opt> + </option> + </param> + <param> + <name>Bits per Chunk</name> + <key>bits_per_chunk</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Endianness</name> + <key>endianness</key> + <type>int</type> + <option> + <name>MSB</name> + <key>gr.GR_MSB_FIRST</key> + </option> + <option> + <name>LSB</name> + <key>gr.GR_LSB_FIRST</key> + </option> + </param> + <param> + <name>Num Ports</name> + <key>num_ports</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_ports > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <nports>$num_ports</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <nports>$num_ports</nports> + </source> +</block> diff --git a/grc/blocks/gr_pdu_to_tagged_stream.xml b/grc/blocks/gr_pdu_to_tagged_stream.xml new file mode 100644 index 000000000..6d2fea97e --- /dev/null +++ b/grc/blocks/gr_pdu_to_tagged_stream.xml @@ -0,0 +1,40 @@ +<?xml version="1.0"?> +<!-- +################################################### +## PDU Message to Tagged Stream +################################################### + --> +<block> + <name>PDU to Tagged Stream</name> + <key>gr_pdu_to_tagged_stream</key> + <import>from gnuradio import gr</import> + <make>gr.pdu_to_tagged_stream($type.tv)</make> + <param> + <name>Item Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Byte</name> + <key>byte</key> + <opt>tv:gr.pdu_byte</opt> + </option> + <option> + <name>Complex</name> + <key>complex</key> + <opt>tv:gr.pdu_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>tv:gr.pdu_float</opt> + </option> + </param> + <sink> + <name>pdus</name> + <type>message</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_peak_detector2_fb.xml b/grc/blocks/gr_peak_detector2_fb.xml new file mode 100644 index 000000000..128c6244f --- /dev/null +++ b/grc/blocks/gr_peak_detector2_fb.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Peak Detector2 +################################################### + --> +<block> + <name>Peak Detector2</name> + <key>gr_peak_detector2_fb</key> + <import>from gnuradio import gr</import> + <make>gr.peak_detector2_fb($threshold_factor_rise, $look_ahead, $alpha)</make> + <callback>set_threshold_factor_rise($threshold_factor_rise)</callback> + <callback>set_look_ahead($look_ahead)</callback> + <callback>set_alpha($alpha)</callback> + <param> + <name>TH Factor Rise</name> + <key>threshold_factor_rise</key> + <type>real</type> + </param> + <param> + <name>Look Ahead</name> + <key>look_ahead</key> + <type>int</type> + </param> + <param> + <name>Alpha</name> + <key>alpha</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/grc/blocks/gr_peak_detector_xb.xml b/grc/blocks/gr_peak_detector_xb.xml new file mode 100644 index 000000000..394b0697f --- /dev/null +++ b/grc/blocks/gr_peak_detector_xb.xml @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Peak Detector +################################################### + --> +<block> + <name>Peak Detector</name> + <key>gr_peak_detector_xb</key> + <import>from gnuradio import gr</import> + <make>gr.peak_detector_$(type.fcn)b($threshold_factor_rise, $threshold_factor_fall, $look_ahead, $alpha)</make> + <callback>set_threshold_factor_rise($threshold_factor_rise)</callback> + <callback>set_threshold_factor_fall($threshold_factor_fall)</callback> + <callback>set_look_ahead($look_ahead)</callback> + <callback>set_alpha($alpha)</callback> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:i</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:s</opt> + </option> + </param> + <param> + <name>TH Factor Rise</name> + <key>threshold_factor_rise</key> + <type>real</type> + </param> + <param> + <name>TH Factor Fall</name> + <key>threshold_factor_fall</key> + <type>real</type> + </param> + <param> + <name>Look Ahead</name> + <key>look_ahead</key> + <type>int</type> + </param> + <param> + <name>Alpha</name> + <key>alpha</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/grc/blocks/gr_pfb_clock_sync.xml b/grc/blocks/gr_pfb_clock_sync.xml new file mode 100644 index 000000000..3e5e65d12 --- /dev/null +++ b/grc/blocks/gr_pfb_clock_sync.xml @@ -0,0 +1,100 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Polyphase Filter based Clock Sync +################################################### + --> +<block> + <name>Polyphase Clock Sync</name> + <key>gr_pfb_clock_sync_xxx</key> + <import>from gnuradio import gr</import> + <make>gr.pfb_clock_sync_$(type)($sps, $alpha, $taps, $filter_size, $init_phase, $max_dev, $osps) +self.$(id).set_beta($beta)</make> + <callback>set_taps($taps)</callback> + <callback>set_alpha($alpha)</callback> + <callback>set_beta($beta)</callback> + + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex->Complex (Real Taps)</name> + <key>ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>taps:real_vector</opt> + </option> + <option> + <name>Float->Float (Real Taps)</name> + <key>fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + <opt>taps:real_vector</opt> + </option> + </param> + + <param> + <name>Samples/Symbol</name> + <key>sps</key> + <type>real</type> + </param> + <param> + <name>Alpha</name> + <key>alpha</key> + <type>real</type> + </param> + <param> + <name>Beta</name> + <key>beta</key> + <type>real</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <type>real_vector</type> + </param> + <param> + <name>Filter Size</name> + <key>filter_size</key> + <type>int</type> + </param> + <param> + <name>Initial Phase</name> + <key>init_phase</key> + <type>real</type> + </param> + <param> + <name>Maximum Rate Deviation</name> + <key>max_dev</key> + <type>real</type> + </param> + <param> + <name>Output SPS</name> + <key>osps</key> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> + <source> + <name>err</name> + <type>float</type> + <optional>1</optional> + </source> + <source> + <name>rate</name> + <type>float</type> + <optional>1</optional> + </source> + <source> + <name>phase</name> + <type>float</type> + <optional>1</optional> + </source> +</block> diff --git a/grc/blocks/gr_pfb_synthesizer.xml b/grc/blocks/gr_pfb_synthesizer.xml new file mode 100644 index 000000000..49e5cb032 --- /dev/null +++ b/grc/blocks/gr_pfb_synthesizer.xml @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Polyphase Synthesis Filterbank +################################################### + --> +<block> + <name>Polyphase Synthesizer</name> + <key>gr_pfb_synthesizer_ccf</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <make>gr.pfb_synthesizer_ccf( + $numchans, $taps, $twox) +self.$(id).set_channel_map($ch_map) + </make> + <callback>set_taps($taps)</callback> + <callback>set_channel_map($ch_map)</callback> + + <param> + <name>Channels</name> + <key>numchans</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Connections</name> + <key>connections</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <type>real_vector</type> + </param> + <param> + <name>2x Sample Rate</name> + <key>twox</key> + <value>False</value> + <type>bool</type> + </param> + <param> + <name>Channel Map</name> + <key>ch_map</key> + <value>[]</value> + <type>int_vector</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + <nports>$connections</nports> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_phase_modulator_fc.xml b/grc/blocks/gr_phase_modulator_fc.xml new file mode 100644 index 000000000..758c50863 --- /dev/null +++ b/grc/blocks/gr_phase_modulator_fc.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Phase Modulator +################################################### + --> +<block> + <name>Phase Mod</name> + <key>gr_phase_modulator_fc</key> + <import>from gnuradio import gr</import> + <make>gr.phase_modulator_fc($sensitivity)</make> + <param> + <name>Sensitivity</name> + <key>sensitivity</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_pll_carriertracking_cc.xml b/grc/blocks/gr_pll_carriertracking_cc.xml new file mode 100644 index 000000000..27e673248 --- /dev/null +++ b/grc/blocks/gr_pll_carriertracking_cc.xml @@ -0,0 +1,36 @@ +<?xml version="1.0"?> +<!-- +################################################### +##PLL Carrier Tracking +################################################### + --> +<block> + <name>PLL Carrier Tracking</name> + <key>gr_pll_carriertracking_cc</key> + <import>from gnuradio import gr</import> + <make>gr.pll_carriertracking_cc($w, $max_freq, $min_freq)</make> + <callback>set_loop_bandwidth($w)</callback> + <param> + <name>Loop Bandwidth</name> + <key>w</key> + <type>real</type> + </param> + <param> + <name>Max Freq</name> + <key>max_freq</key> + <type>real</type> + </param> + <param> + <name>Min Freq</name> + <key>min_freq</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_pll_freqdet_cf.xml b/grc/blocks/gr_pll_freqdet_cf.xml new file mode 100644 index 000000000..d6e4694f0 --- /dev/null +++ b/grc/blocks/gr_pll_freqdet_cf.xml @@ -0,0 +1,36 @@ +<?xml version="1.0"?> +<!-- +################################################### +##PLL Frequency Det +################################################### + --> +<block> + <name>PLL Freq Det</name> + <key>gr_pll_freqdet_cf</key> + <import>from gnuradio import gr</import> + <make>gr.pll_freqdet_cf($w, $max_freq, $min_freq)</make> + <callback>set_loop_bandwidth($w)</callback> + <param> + <name>Loop Bandwidth</name> + <key>w</key> + <type>real</type> + </param> + <param> + <name>Max Freq</name> + <key>max_freq</key> + <type>real</type> + </param> + <param> + <name>Min Freq</name> + <key>min_freq</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/gr_pll_refout_cc.xml b/grc/blocks/gr_pll_refout_cc.xml new file mode 100644 index 000000000..b231ddd19 --- /dev/null +++ b/grc/blocks/gr_pll_refout_cc.xml @@ -0,0 +1,36 @@ +<?xml version="1.0"?> +<!-- +################################################### +##PLL Reference Out +################################################### + --> +<block> + <name>PLL Ref Out</name> + <key>gr_pll_refout_cc</key> + <import>from gnuradio import gr</import> + <make>gr.pll_refout_cc($w, $max_freq, $min_freq)</make> + <callback>set_loop_bandwidth($w)</callback> + <param> + <name>Loop Bandwidth</name> + <key>w</key> + <type>real</type> + </param> + <param> + <name>Max Freq</name> + <key>max_freq</key> + <type>real</type> + </param> + <param> + <name>Min Freq</name> + <key>min_freq</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_pn_correlator_cc.xml b/grc/blocks/gr_pn_correlator_cc.xml new file mode 100644 index 000000000..094f46cdf --- /dev/null +++ b/grc/blocks/gr_pn_correlator_cc.xml @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<!-- +################################################### +##PN Correlator +################################################### + --> +<block> + <name>PN Correlator</name> + <key>gr_pn_correlator_cc</key> + <import>from gnuradio import gr</import> + <make>gr.pn_correlator_cc($degree, $mask, $seed)</make> + <param> + <name>Degree</name> + <key>degree</key> + <type>int</type> + </param> + <param> + <name>Mask</name> + <key>mask</key> + <type>int</type> + </param> + <param> + <name>Seed</name> + <key>seed</key> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_probe_avg_mag_sqrd_x.xml b/grc/blocks/gr_probe_avg_mag_sqrd_x.xml new file mode 100644 index 000000000..6bf706ae1 --- /dev/null +++ b/grc/blocks/gr_probe_avg_mag_sqrd_x.xml @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Probe Average Magnitude Squared +################################################### + --> +<block> + <name>Probe Avg Mag^2</name> + <key>gr_probe_avg_mag_sqrd_x</key> + <import>from gnuradio import gr</import> + <make>gr.probe_avg_mag_sqrd_$(type)($threshold, $alpha)</make> + <callback>set_alpha($alpha)</callback> + <callback>set_threshold($threshold)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>c</key> + <opt>input:complex</opt> + </option> + <option> + <name>Float</name> + <key>f</key> + <opt>input:float</opt> + </option> + </param> + <param> + <name>Threshold (dB)</name> + <key>threshold</key> + <value>0</value> + <type>real</type> + </param> + <param> + <name>Alpha</name> + <key>alpha</key> + <value>1</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <doc> +Available functions to probe: level() + +Use with the function probe block. + </doc> +</block> diff --git a/grc/blocks/gr_probe_density_b.xml b/grc/blocks/gr_probe_density_b.xml new file mode 100644 index 000000000..3a91256aa --- /dev/null +++ b/grc/blocks/gr_probe_density_b.xml @@ -0,0 +1,34 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Probe Density +################################################### + --> +<block> + <name>Probe Density</name> + <key>gr_probe_density_b</key> + <import>from gnuradio import gr</import> + <make>gr.probe_density_b($alpha)</make> + <callback>set_alpha($alpha)</callback> + <param> + <name>Alpha</name> + <key>alpha</key> + <value>1</value> + <type>real</type> + </param> + <param> + <name>Probe Rate</name> + <key>probe_rate</key> + <value>10</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <doc> +Available functions to probe: density() + +Use with the function probe block. + </doc> +</block> diff --git a/grc/blocks/gr_probe_signal_f.xml b/grc/blocks/gr_probe_signal_f.xml new file mode 100644 index 000000000..5c38e816f --- /dev/null +++ b/grc/blocks/gr_probe_signal_f.xml @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Probe Signal +################################################### + --> +<block> + <name>Probe Signal</name> + <key>gr_probe_signal_f</key> + <import>from gnuradio import gr</import> + <make>gr.probe_signal_f()</make> + <sink> + <name>in</name> + <type>float</type> + </sink> + <doc> +Available functions to probe: level() + +Use with the function probe block. + </doc> +</block> diff --git a/grc/blocks/gr_pwr_squelch_xx.xml b/grc/blocks/gr_pwr_squelch_xx.xml new file mode 100644 index 000000000..08d621177 --- /dev/null +++ b/grc/blocks/gr_pwr_squelch_xx.xml @@ -0,0 +1,65 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Power Squelch +################################################### + --> +<block> + <name>Power Squelch</name> + <key>gr_pwr_squelch_xx</key> + <import>from gnuradio import gr</import> + <make>gr.pwr_squelch_$(type.fcn)($threshold, $alpha, $ramp, $gate)</make> + <callback>set_threshold($threshold)</callback> + <callback>set_alpha($alpha)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:cc</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + </option> + </param> + <param> + <name>Threshold (dB)</name> + <key>threshold</key> + <type>real</type> + </param> + <param> + <name>Alpha</name> + <key>alpha</key> + <type>real</type> + </param> + <param> + <name>Ramp</name> + <key>ramp</key> + <type>int</type> + </param> + <param> + <name>Gate</name> + <key>gate</key> + <type>enum</type> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_quadrature_demod_cf.xml b/grc/blocks/gr_quadrature_demod_cf.xml new file mode 100644 index 000000000..fad0b3879 --- /dev/null +++ b/grc/blocks/gr_quadrature_demod_cf.xml @@ -0,0 +1,26 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Quadrature Demodulator +################################################### + --> +<block> + <name>Quadrature Demod</name> + <key>gr_quadrature_demod_cf</key> + <import>from gnuradio import gr</import> + <make>gr.quadrature_demod_cf($gain)</make> + <callback>set_gain($gain)</callback> + <param> + <name>Gain</name> + <key>gain</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/gr_random_pdu.xml b/grc/blocks/gr_random_pdu.xml new file mode 100644 index 000000000..ed5a79a92 --- /dev/null +++ b/grc/blocks/gr_random_pdu.xml @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Random PDU +################################################### + --> +<block> + <name>Random PDU Generator</name> + <key>gr_random_pdu</key> + <import>from gnuradio import gr</import> + <import>from gruel import pmt</import> + <make>gr.random_pdu($minsize, $maxsize)</make> + <param> + <name>Min Bytes</name> + <key>minsize</key> + <value>50</value> + <type>int</type> + </param> + <param> + <name>Max Bytes</name> + <key>maxsize</key> + <value>2000</value> + <type>int</type> + </param> + <sink> + <name>generate</name> + <type>message</type> + <optional>1</optional> + </sink> + <source> + <name>pdus</name> + <type>message</type> + <optional>1</optional> + </source> +</block> diff --git a/grc/blocks/gr_rational_resampler_base_xxx.xml b/grc/blocks/gr_rational_resampler_base_xxx.xml new file mode 100644 index 000000000..4b7720173 --- /dev/null +++ b/grc/blocks/gr_rational_resampler_base_xxx.xml @@ -0,0 +1,86 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Rational Resampler Base +################################################### + --> +<block> + <name>Rational Resampler Base</name> + <key>gr_rational_resampler_base_xxx</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <make>gr.rational_resampler_base_$(type)($interp, $decim, $taps)</make> + <callback>set_taps($taps)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex->Complex (Complex Taps)</name> + <key>ccc</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + <option> + <name>Complex->Complex (Real Taps)</name> + <key>ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + <opt>taps:real_vector</opt> + </option> + <option> + <name>Float->Complex (Complex Taps)</name> + <key>fcc</key> + <opt>input:float</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + <option> + <name>Float->Float (Real Taps)</name> + <key>fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + <opt>taps:real_vector</opt> + </option> + <option> + <name>Float->Short (Real Taps)</name> + <key>fsf</key> + <opt>input:float</opt> + <opt>output:short</opt> + <opt>taps:real_vector</opt> + </option> + <option> + <name>Short->Complex (Complex Taps)</name> + <key>scc</key> + <opt>input:short</opt> + <opt>output:complex</opt> + <opt>taps:complex_vector</opt> + </option> + </param> + <param> + <name>Interpolation</name> + <key>interp</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Decimation</name> + <key>decim</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <type>$type.taps</type> + </param> + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> +</block> diff --git a/grc/blocks/gr_repeat.xml b/grc/blocks/gr_repeat.xml new file mode 100644 index 000000000..ba652a4d7 --- /dev/null +++ b/grc/blocks/gr_repeat.xml @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Repeat +################################################### + --> +<block> + <name>Repeat</name> + <key>gr_repeat</key> + <import>from gnuradio import gr</import> + <make>gr.repeat($type.size*$vlen, $interp)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Interpolation</name> + <key>interp</key> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_rms_xx.xml b/grc/blocks/gr_rms_xx.xml new file mode 100644 index 000000000..1e0947192 --- /dev/null +++ b/grc/blocks/gr_rms_xx.xml @@ -0,0 +1,41 @@ +<?xml version="1.0"?> +<!-- +################################################### +##RMS +################################################### + --> +<block> + <name>RMS</name> + <key>gr_rms_xx</key> + <import>from gnuradio import gr</import> + <make>gr.rms_$(type.fcn)f($alpha)</make> + <callback>set_alpha($alpha)</callback> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:c</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + </option> + </param> + <param> + <name>Alpha</name> + <key>alpha</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/gr_sample_and_hold_xx.xml b/grc/blocks/gr_sample_and_hold_xx.xml new file mode 100644 index 000000000..2a036c3fd --- /dev/null +++ b/grc/blocks/gr_sample_and_hold_xx.xml @@ -0,0 +1,49 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Sample and Hold +################################################### + --> +<block> + <name>Sample and Hold</name> + <key>gr_sample_and_hold_xx</key> + <import>from gnuradio import gr</import> + <make>gr.sample_and_hold_$(type.fcn)()</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:bb</opt> + </option> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <sink> + <name>ctrl</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_scrambler_bb.xml b/grc/blocks/gr_scrambler_bb.xml new file mode 100644 index 000000000..d079c4015 --- /dev/null +++ b/grc/blocks/gr_scrambler_bb.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Descrambler +################################################### + --> +<block> + <name>Scrambler</name> + <key>gr_scrambler_bb</key> + <import>from gnuradio import gr</import> + <make>gr.scrambler_bb($mask, $seed, $len)</make> + <param> + <name>Mask</name> + <key>mask</key> + <value>0x8A</value> + <type>hex</type> + </param> + <param> + <name>Seed</name> + <key>seed</key> + <value>0x7F</value> + <type>hex</type> + </param> + <param> + <name>Length</name> + <key>len</key> + <value>7</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/grc/blocks/gr_short_to_char.xml b/grc/blocks/gr_short_to_char.xml new file mode 100644 index 000000000..9c41da84e --- /dev/null +++ b/grc/blocks/gr_short_to_char.xml @@ -0,0 +1,28 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Short to char: +################################################### + --> +<block> + <name>Short To Char</name> + <key>gr_short_to_char</key> + <import>from gnuradio import gr</import> + <make>gr.short_to_char($vlen)</make> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>short</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>byte</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_short_to_float.xml b/grc/blocks/gr_short_to_float.xml new file mode 100644 index 000000000..529f8c78c --- /dev/null +++ b/grc/blocks/gr_short_to_float.xml @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Short to Float: +################################################### + --> +<block> + <name>Short To Float</name> + <key>gr_short_to_float</key> + <import>from gnuradio import gr</import> + <make>gr.short_to_float($vlen, $scale)</make> + <callback>set_scale($scale)</callback> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Scale</name> + <key>scale</key> + <value>1</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>short</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>float</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_sig_source_x.xml b/grc/blocks/gr_sig_source_x.xml new file mode 100644 index 000000000..644cf52d0 --- /dev/null +++ b/grc/blocks/gr_sig_source_x.xml @@ -0,0 +1,104 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Signal Source +################################################### + --> +<block> + <name>Signal Source</name> + <key>gr_sig_source_x</key> + <import>from gnuradio import gr</import> + <make>gr.sig_source_$(type.fcn)($samp_rate, $waveform, $freq, $amp, $offset)</make> + <callback>set_sampling_freq($samp_rate)</callback> + <callback>set_waveform($waveform)</callback> + <callback>set_frequency($freq)</callback> + <callback>set_amplitude($amp)</callback> + <callback>set_offset($offset)</callback> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:c</opt> + <opt>offset_type:complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + <opt>offset_type:real</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:i</opt> + <opt>offset_type:int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:s</opt> + <opt>offset_type:int</opt> + </option> + </param> + <param> + <name>Sample Rate</name> + <key>samp_rate</key> + <value>samp_rate</value> + <type>real</type> + </param> + <param> + <name>Waveform</name> + <key>waveform</key> + <value>gr.GR_COS_WAVE</value> + <type>int</type> + <option> + <name>Constant</name> + <key>gr.GR_CONST_WAVE</key> + </option> + <option> + <name>Sine</name> + <key>gr.GR_SIN_WAVE</key> + </option> + <option> + <name>Cosine</name> + <key>gr.GR_COS_WAVE</key> + </option> + <option> + <name>Square</name> + <key>gr.GR_SQR_WAVE</key> + </option> + <option> + <name>Triangle</name> + <key>gr.GR_TRI_WAVE</key> + </option> + <option> + <name>Saw Tooth</name> + <key>gr.GR_SAW_WAVE</key> + </option> + </param> + <param> + <name>Frequency</name> + <key>freq</key> + <value>1000</value> + <type>real</type> + </param> + <param> + <name>Amplitude</name> + <key>amp</key> + <value>1</value> + <type>real</type> + </param> + <param> + <name>Offset</name> + <key>offset</key> + <value>0</value> + <type>$type.offset_type</type> + </param> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/gr_simple_correlator.xml b/grc/blocks/gr_simple_correlator.xml new file mode 100644 index 000000000..820523a64 --- /dev/null +++ b/grc/blocks/gr_simple_correlator.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Simple Correlator +################################################### + --> +<block> + <name>Simple Correlator</name> + <key>gr_simple_correlator</key> + <import>from gnuradio import gr</import> + <make>gr.simple_correlator($payload_bytesize)</make> + <param> + <name>Payload Byte Size</name> + <key>payload_bytesize</key> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/grc/blocks/gr_simple_framer.xml b/grc/blocks/gr_simple_framer.xml new file mode 100644 index 000000000..2a0295c41 --- /dev/null +++ b/grc/blocks/gr_simple_framer.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Simple Framer +################################################### + --> +<block> + <name>Simple Framer</name> + <key>gr_simple_framer</key> + <import>from gnuradio import gr</import> + <make>gr.simple_framer($payload_bytesize)</make> + <param> + <name>Payload Byte Size</name> + <key>payload_bytesize</key> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/grc/blocks/gr_simple_squelch_cc.xml b/grc/blocks/gr_simple_squelch_cc.xml new file mode 100644 index 000000000..5c0727f5f --- /dev/null +++ b/grc/blocks/gr_simple_squelch_cc.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Simple Squelch +################################################### + --> +<block> + <name>Simple Squelch</name> + <key>gr_simple_squelch_cc</key> + <import>from gnuradio import gr</import> + <make>gr.simple_squelch_cc($threshold, $alpha)</make> + <callback>set_threshold($threshold)</callback> + <callback>set_alpha($alpha)</callback> + <param> + <name>Threshold (dB)</name> + <key>threshold</key> + <type>real</type> + </param> + <param> + <name>Alpha</name> + <key>alpha</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_single_pole_iir_filter_xx.xml b/grc/blocks/gr_single_pole_iir_filter_xx.xml new file mode 100644 index 000000000..50cf4a82d --- /dev/null +++ b/grc/blocks/gr_single_pole_iir_filter_xx.xml @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Single Pole IIR Filter +################################################### + --> +<block> + <name>Single Pole IIR Filter</name> + <key>gr_single_pole_iir_filter_xx</key> + <import>from gnuradio import gr</import> + <make>gr.single_pole_iir_filter_$(type.fcn)($alpha, $vlen)</make> + <callback>set_taps($alpha)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:cc</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + </option> + </param> + <param> + <name>Alpha</name> + <key>alpha</key> + <value>1.0</value> + <type>real</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_skiphead.xml b/grc/blocks/gr_skiphead.xml new file mode 100644 index 000000000..0849ad298 --- /dev/null +++ b/grc/blocks/gr_skiphead.xml @@ -0,0 +1,65 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Skip Head +################################################### + --> +<block> + <name>Skip Head</name> + <key>gr_skiphead</key> + <import>from gnuradio import gr</import> + <make>gr.skiphead($type.size*$vlen, $num_items)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Num Items</name> + <key>num_items</key> + <value>1024</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_socket_pdu.xml b/grc/blocks/gr_socket_pdu.xml new file mode 100644 index 000000000..a175c3699 --- /dev/null +++ b/grc/blocks/gr_socket_pdu.xml @@ -0,0 +1,62 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Socket PDU Message source/sink +################################################### + --> +<block> + <name>Socket PDU</name> + <key>gr_socket_pdu</key> + <import>from gnuradio import gr</import> + <make>gr.socket_pdu($type, $host, $port, $mtu)</make> + <param> + <name>Type</name> + <key>type</key> + <value>TCP_SERVER</value> + <type>enum</type> + <option> + <name>TCP Server</name> + <key>"TCP_SERVER"</key> + </option> + <option> + <name>TCP Client</name> + <key>"TCP_CLIENT"</key> + </option> + <option> + <name>UDP Server</name> + <key>"UDP_SERVER"</key> + </option> + <option> + <name>UDP Client</name> + <key>"UDP_CLIENT"</key> + </option> + </param> + <param> + <name>Host</name> + <key>host</key> + <value></value> + <type>string</type> + </param> + <param> + <name>Port</name> + <key>port</key> + <value>52001</value> + <type>string</type> + </param> + <param> + <name>MTU</name> + <key>mtu</key> + <value>10000</value> + <type>int</type> + </param> + <sink> + <name>pdus</name> + <type>message</type> + <optional>1</optional> + </sink> + <source> + <name>pdus</name> + <type>message</type> + <optional>1</optional> + </source> +</block> diff --git a/grc/blocks/gr_stream_mux.xml b/grc/blocks/gr_stream_mux.xml new file mode 100644 index 000000000..8efe7b655 --- /dev/null +++ b/grc/blocks/gr_stream_mux.xml @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Stream Mux: +## all types, many inputs, only one output +################################################### + --> +<block> + <name>Stream Mux</name> + <key>gr_stream_mux</key> + <import>from gnuradio import gr</import> + <make>gr.stream_mux($type.size*$vlen, $lengths)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Lengths</name> + <key>lengths</key> + <value>1, 1</value> + <type>int_vector</type> + </param> + <param> + <name>Num Inputs</name> + <key>num_inputs</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_inputs > 0</check> + <check>$num_inputs == len($lengths)</check> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_inputs</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_stream_to_streams.xml b/grc/blocks/gr_stream_to_streams.xml new file mode 100644 index 000000000..82542b8d4 --- /dev/null +++ b/grc/blocks/gr_stream_to_streams.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Stream to Streams +################################################### + --> +<block> + <name>Stream to Streams</name> + <key>gr_stream_to_streams</key> + <import>from gnuradio import gr</import> + <make>gr.stream_to_streams($type.size*$vlen, $num_streams)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Num Streams</name> + <key>num_streams</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_streams > 0</check> + <check>$vlen >= 1</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_streams</nports> + </source> +</block> diff --git a/grc/blocks/gr_stream_to_vector.xml b/grc/blocks/gr_stream_to_vector.xml new file mode 100644 index 000000000..296d786f8 --- /dev/null +++ b/grc/blocks/gr_stream_to_vector.xml @@ -0,0 +1,66 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Stream to Vector +################################################### + --> +<block> + <name>Stream to Vector</name> + <key>gr_stream_to_vector</key> + <import>from gnuradio import gr</import> + <make>gr.stream_to_vector($type.size*$vlen, $num_items)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Num Items</name> + <key>num_items</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_items > 0</check> + <check>$vlen >= 1</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen*$num_items</vlen> + </source> +</block> diff --git a/grc/blocks/gr_streams_to_stream.xml b/grc/blocks/gr_streams_to_stream.xml new file mode 100644 index 000000000..7aadd7eef --- /dev/null +++ b/grc/blocks/gr_streams_to_stream.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Streams to Stream +################################################### + --> +<block> + <name>Streams to Stream</name> + <key>gr_streams_to_stream</key> + <import>from gnuradio import gr</import> + <make>gr.streams_to_stream($type.size*$vlen, $num_streams)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Num Streams</name> + <key>num_streams</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_streams > 0</check> + <check>$vlen >= 1</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_streams</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_streams_to_vector.xml b/grc/blocks/gr_streams_to_vector.xml new file mode 100644 index 000000000..4ecdcb2d4 --- /dev/null +++ b/grc/blocks/gr_streams_to_vector.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Streams to Vector +################################################### + --> +<block> + <name>Streams to Vector</name> + <key>gr_streams_to_vector</key> + <import>from gnuradio import gr</import> + <make>gr.streams_to_vector($type.size*$vlen, $num_streams)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Num Streams</name> + <key>num_streams</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_streams > 0</check> + <check>$vlen >= 1</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_streams</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen*$num_streams</vlen> + </source> +</block> diff --git a/grc/blocks/gr_sub_xx.xml b/grc/blocks/gr_sub_xx.xml new file mode 100644 index 000000000..c677747da --- /dev/null +++ b/grc/blocks/gr_sub_xx.xml @@ -0,0 +1,63 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Subtract Block: +## all types, 1 output, 2 to inf inputs +################################################### + --> +<block> + <name>Subtract</name> + <key>gr_sub_xx</key> + <import>from gnuradio import gr</import> + <make>gr.sub_$(type.fcn)($vlen)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:cc</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Num Inputs</name> + <key>num_inputs</key> + <value>2</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <check>$num_inputs >= 1</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_inputs</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_tag_debug.xml b/grc/blocks/gr_tag_debug.xml new file mode 100644 index 000000000..4af7729be --- /dev/null +++ b/grc/blocks/gr_tag_debug.xml @@ -0,0 +1,82 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Tag Debug +################################################### + --> +<block> + <name>Tag Debug</name> + <key>gr_tag_debug</key> + <import>from gnuradio import gr</import> + <make>gr.tag_debug($type.size*$vlen, $name)</make> + <callback>set_display($display)</callback> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Name</name> + <key>name</key> + <type>string</type> + </param> + <param> + <name>Num Inputs</name> + <key>num_inputs</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Display</name> + <key>display</key> + <value>True</value> + <type>bool</type> + <option> + <name>On</name> + <key>True</key> + </option> + <option> + <name>Off</name> + <key>False</key> + </option> + </param> + <check>$num_inputs >= 1</check> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_inputs</nports> + </sink> +</block> diff --git a/grc/blocks/gr_tagged_stream_to_pdu.xml b/grc/blocks/gr_tagged_stream_to_pdu.xml new file mode 100644 index 000000000..e2f754c9e --- /dev/null +++ b/grc/blocks/gr_tagged_stream_to_pdu.xml @@ -0,0 +1,40 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Tagged Stream to PDU Message +################################################### + --> +<block> + <name>Tagged Stream to PDU</name> + <key>gr_tagged_stream_to_pdu</key> + <import>from gnuradio import gr</import> + <make>gr.tagged_stream_to_pdu($type.tv)</make> + <param> + <name>Item Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Byte</name> + <key>byte</key> + <opt>tv:gr.pdu_byte</opt> + </option> + <option> + <name>Complex</name> + <key>complex</key> + <opt>tv:gr.pdu_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>tv:gr.pdu_float</opt> + </option> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>pdus</name> + <type>message</type> + </source> +</block> diff --git a/grc/blocks/gr_threshold_ff.xml b/grc/blocks/gr_threshold_ff.xml new file mode 100644 index 000000000..740ce5794 --- /dev/null +++ b/grc/blocks/gr_threshold_ff.xml @@ -0,0 +1,40 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Threshold +################################################### + --> +<block> + <name>Threshold</name> + <key>gr_threshold_ff</key> + <import>from gnuradio import gr</import> + <make>gr.threshold_ff($low, $high, $init)</make> + <callback>set_hi($high)</callback> + <callback>set_lo($low)</callback> + <param> + <name>Low</name> + <key>low</key> + <value>-100</value> + <type>real</type> + </param> + <param> + <name>High</name> + <key>high</key> + <value>100</value> + <type>real</type> + </param> + <param> + <name>Initial State</name> + <key>init</key> + <value>0</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/gr_throttle.xml b/grc/blocks/gr_throttle.xml new file mode 100644 index 000000000..e3a5a2ba1 --- /dev/null +++ b/grc/blocks/gr_throttle.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Throttle +################################################### + --> +<block> + <name>Throttle</name> + <key>gr_throttle</key> + <throttle>1</throttle> + <import>from gnuradio import gr</import> + <make>gr.throttle($type.size*$vlen, $samples_per_second)</make> + <callback>set_sample_rate($samples_per_second)</callback> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Sample Rate</name> + <key>samples_per_second</key> + <value>samp_rate</value> + <type>real</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_transcendental.xml b/grc/blocks/gr_transcendental.xml new file mode 100644 index 000000000..eede447f9 --- /dev/null +++ b/grc/blocks/gr_transcendental.xml @@ -0,0 +1,41 @@ +<?xml version="1.0"?> +<!-- +################################################### +##transcendental functions +################################################### + --> +<block> + <name>Transcendental</name> + <key>gr_transcendental</key> + <import>from gnuradio import gr</import> + <make>gr.transcendental($name, "$type")</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex_double</key> + <opt>type:complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>type:float</opt> + </option> + </param> + <param> + <name>Function Name</name> + <key>name</key> + <value>cos</value> + <type>string</type> + </param> + <sink> + <name>in</name> + <type>$type.type</type> + </sink> + <source> + <name>out</name> + <type>$type.type</type> + </source> +</block> diff --git a/grc/blocks/gr_tuntap_pdu.xml b/grc/blocks/gr_tuntap_pdu.xml new file mode 100644 index 000000000..f169345af --- /dev/null +++ b/grc/blocks/gr_tuntap_pdu.xml @@ -0,0 +1,34 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Tuntap PDU Message source/sink +################################################### + --> +<block> + <name>TunTap PDU</name> + <key>gr_tuntap_pdu</key> + <import>from gnuradio import gr</import> + <make>gr.tuntap_pdu($ifn, $mtu)</make> + <param> + <name>Interface Name</name> + <key>ifn</key> + <value>tun0</value> + <type>string</type> + </param> + <param> + <name>MTU</name> + <key>mtu</key> + <value>10000</value> + <type>int</type> + </param> + <sink> + <name>pdus</name> + <type>message</type> + <optional>1</optional> + </sink> + <source> + <name>pdus</name> + <type>message</type> + <optional>1</optional> + </source> +</block> diff --git a/grc/blocks/gr_uchar_to_float.xml b/grc/blocks/gr_uchar_to_float.xml new file mode 100644 index 000000000..0a5f7f96a --- /dev/null +++ b/grc/blocks/gr_uchar_to_float.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Unsigned Char to Float: +################################################### + --> +<block> + <name>UChar To Float</name> + <key>gr_uchar_to_float</key> + <import>from gnuradio import gr</import> + <make>gr.uchar_to_float()</make> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/gr_udp_sink.xml b/grc/blocks/gr_udp_sink.xml new file mode 100644 index 000000000..45f81075f --- /dev/null +++ b/grc/blocks/gr_udp_sink.xml @@ -0,0 +1,77 @@ +<?xml version="1.0"?> +<!-- +################################################### +##UDP Sink +################################################### + --> +<block> + <name>UDP Sink</name> + <key>gr_udp_sink</key> + <import>from gnuradio import gr</import> + <make>gr.udp_sink($type.size*$vlen, $ipaddr, $port, $psize, $eof)</make> + <callback>set_mtu($mtu)</callback> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Destination IP Address</name> + <key>ipaddr</key> + <type>string</type> + </param> + <param> + <name>Destination Port</name> + <key>port</key> + <type>int</type> + </param> + <param> + <name>Payload Size</name> + <key>psize</key> + <value>1472</value> + <type>int</type> + </param> + <param> + <name>Send Null Pkt as EOF</name> + <key>eof</key> + <value>True</value> + <type>bool</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> +</block> diff --git a/grc/blocks/gr_udp_source.xml b/grc/blocks/gr_udp_source.xml new file mode 100644 index 000000000..a1b961651 --- /dev/null +++ b/grc/blocks/gr_udp_source.xml @@ -0,0 +1,85 @@ +<?xml version="1.0"?> +<!-- +################################################### +##UDP Source +################################################### + --> +<block> + <name>UDP Source</name> + <key>gr_udp_source</key> + <import>from gnuradio import gr</import> + <make>gr.udp_source($type.size*$vlen, $ipaddr, $port, $psize, $eof, $wait)</make> + <callback>set_mtu($mtu)</callback> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>IP Address</name> + <key>ipaddr</key> + <value>127.0.0.1</value> + <type>string</type> + </param> + <param> + <name>Port</name> + <key>port</key> + <value>1234</value> + <type>int</type> + </param> + <param> + <name>Payload Size</name> + <key>psize</key> + <value>1472</value> + <type>int</type> + </param> + <param> + <name>Null Pkt is EOF</name> + <key>eof</key> + <value>True</value> + <type>bool</type> + </param> + <param> + <name>Wait for Data</name> + <key>wait</key> + <value>True</value> + <type>bool</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_unpack_k_bits_bb.xml b/grc/blocks/gr_unpack_k_bits_bb.xml new file mode 100644 index 000000000..9917644ab --- /dev/null +++ b/grc/blocks/gr_unpack_k_bits_bb.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Unpack K Bits +################################################### + --> +<block> + <name>Unpack K Bits</name> + <key>gr_unpack_k_bits_bb</key> + <import>from gnuradio import gr</import> + <make>gr.unpack_k_bits_bb($k)</make> + <param> + <name>K</name> + <key>k</key> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/grc/blocks/gr_unpacked_to_packed_xx.xml b/grc/blocks/gr_unpacked_to_packed_xx.xml new file mode 100644 index 000000000..427c80082 --- /dev/null +++ b/grc/blocks/gr_unpacked_to_packed_xx.xml @@ -0,0 +1,68 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Unpacked to Packed +################################################### + --> +<block> + <name>Unpacked to Packed</name> + <key>gr_unpacked_to_packed_xx</key> + <import>from gnuradio import gr</import> + <make>gr.unpacked_to_packed_$(type.fcn)($bits_per_chunk, $endianness)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:bb</opt> + </option> + </param> + <param> + <name>Bits per Chunk</name> + <key>bits_per_chunk</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Endianness</name> + <key>endianness</key> + <type>int</type> + <option> + <name>MSB</name> + <key>gr.GR_MSB_FIRST</key> + </option> + <option> + <name>LSB</name> + <key>gr.GR_LSB_FIRST</key> + </option> + </param> + <param> + <name>Num Ports</name> + <key>num_ports</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_ports > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <nports>$num_ports</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <nports>$num_ports</nports> + </source> +</block> diff --git a/grc/blocks/gr_vco_f.xml b/grc/blocks/gr_vco_f.xml new file mode 100644 index 000000000..e49c53965 --- /dev/null +++ b/grc/blocks/gr_vco_f.xml @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<!-- +################################################### +##VCO +################################################### + --> +<block> + <name>VCO</name> + <key>gr_vco_f</key> + <import>from gnuradio import gr</import> + <make>gr.vco_f($samp_rate, $sensitivity, $amplitude)</make> + <param> + <name>Sample Rate</name> + <key>samp_rate</key> + <type>real</type> + </param> + <param> + <name>Sensitivity</name> + <key>sensitivity</key> + <type>real</type> + </param> + <param> + <name>Amplitude</name> + <key>amplitude</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/gr_vector_insert_x.xml b/grc/blocks/gr_vector_insert_x.xml new file mode 100644 index 000000000..f9ce1f654 --- /dev/null +++ b/grc/blocks/gr_vector_insert_x.xml @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Vector Source +################################################### + --> +<block> + <name>Vector Insert</name> + <key>gr_vector_insert_x</key> + <import>from gnuradio import gr</import> + <make>gr.vector_insert_$(type.fcn)($vector, $period, $offset)</make> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:b</opt> + <opt>vec_type:int_vector</opt> + </option> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:c</opt> + <opt>vec_type:complex_vector</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + <opt>vec_type:real_vector</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:i</opt> + <opt>vec_type:int_vector</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:s</opt> + <opt>vec_type:int_vector</opt> + </option> + </param> + <param> + <name>Vector</name> + <key>vector</key> + <value>0, 0, 0</value> + <type>$type.vec_type</type> + </param> + <param> + <name>Periodicity</name> + <key>period</key> + <value>100</value> + <type>int</type> + </param> + <param> + <name>Offset</name> + <key>offset</key> + <value>0</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> + + <doc> + Periodicity, the length of the periodicity at which the vector should be inserted at the output. + (i.e. one vector for every N output items) + + Offset sepcifies where in the cycle period we should begin at. + </doc> +</block> diff --git a/grc/blocks/gr_vector_sink_x.xml b/grc/blocks/gr_vector_sink_x.xml new file mode 100644 index 000000000..3bd998698 --- /dev/null +++ b/grc/blocks/gr_vector_sink_x.xml @@ -0,0 +1,54 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Vector sink +################################################### + --> +<block> + <name>Vector Sink</name> + <key>gr_vector_sink_x</key> + <import>from gnuradio import gr</import> + <make>gr.vector_sink_$(type.fcn)($vlen)</make> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:c</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:i</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:s</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:b</opt> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> +</block> diff --git a/grc/blocks/gr_vector_source_x.xml b/grc/blocks/gr_vector_source_x.xml new file mode 100644 index 000000000..7a6a3aeff --- /dev/null +++ b/grc/blocks/gr_vector_source_x.xml @@ -0,0 +1,79 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Vector Source +################################################### + --> +<block> + <name>Vector Source</name> + <key>gr_vector_source_x</key> + <import>from gnuradio import gr</import> + <make>gr.vector_source_$(type.fcn)($vector, $repeat, $vlen)</make> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:c</opt> + <opt>vec_type:complex_vector</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + <opt>vec_type:real_vector</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:i</opt> + <opt>vec_type:int_vector</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:s</opt> + <opt>vec_type:int_vector</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:b</opt> + <opt>vec_type:int_vector</opt> + </option> + </param> + <param> + <name>Vector</name> + <key>vector</key> + <value>0, 0, 0</value> + <type>$type.vec_type</type> + </param> + <param> + <name>Repeat</name> + <key>repeat</key> + <value>True</value> + <type>enum</type> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_vector_to_stream.xml b/grc/blocks/gr_vector_to_stream.xml new file mode 100644 index 000000000..d56d34067 --- /dev/null +++ b/grc/blocks/gr_vector_to_stream.xml @@ -0,0 +1,66 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Vector to Stream +################################################### + --> +<block> + <name>Vector to Stream</name> + <key>gr_vector_to_stream</key> + <import>from gnuradio import gr</import> + <make>gr.vector_to_stream($type.size*$vlen, $num_items)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Num Items</name> + <key>num_items</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_items > 0</check> + <check>$vlen >= 1</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen*$num_items</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/grc/blocks/gr_vector_to_streams.xml b/grc/blocks/gr_vector_to_streams.xml new file mode 100644 index 000000000..86cb56813 --- /dev/null +++ b/grc/blocks/gr_vector_to_streams.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Vector to Streams +################################################### + --> +<block> + <name>Vector to Streams</name> + <key>gr_vector_to_streams</key> + <import>from gnuradio import gr</import> + <make>gr.vector_to_streams($type.size*$vlen, $num_streams)</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Num Streams</name> + <key>num_streams</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_streams > 0</check> + <check>$vlen >= 1</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen*$num_streams</vlen> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_streams</nports> + </source> +</block> diff --git a/grc/blocks/gr_wavfile_sink.xml b/grc/blocks/gr_wavfile_sink.xml new file mode 100644 index 000000000..651e16cb6 --- /dev/null +++ b/grc/blocks/gr_wavfile_sink.xml @@ -0,0 +1,43 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Wav File Sink +################################################### + --> +<block> + <name>Wav File Sink</name> + <key>gr_wavfile_sink</key> + <import>from gnuradio import gr</import> + <make>gr.wavfile_sink($file, $nchan, $samp_rate, $bits_per_sample)</make> + <callback>open($file)</callback> + <param> + <name>File</name> + <key>file</key> + <value></value> + <type>file_save</type> + </param> + <param> + <name>N Channels</name> + <key>nchan</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Sample Rate</name> + <key>samp_rate</key> + <value>samp_rate</value> + <type>int</type> + </param> + <param> + <name>Bits per Sample</name> + <key>bits_per_sample</key> + <value>8</value> + <type>int</type> + </param> + <check>1 <= $nchan</check> + <sink> + <name>in</name> + <type>float</type> + <nports>$nchan</nports> + </sink> +</block> diff --git a/grc/blocks/gr_wavfile_source.xml b/grc/blocks/gr_wavfile_source.xml new file mode 100644 index 000000000..433bb0af2 --- /dev/null +++ b/grc/blocks/gr_wavfile_source.xml @@ -0,0 +1,44 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Wav File Source +################################################### + --> +<block> + <name>Wav File Source</name> + <key>gr_wavfile_source</key> + <import>from gnuradio import gr</import> + <make>gr.wavfile_source($file, $repeat)</make> + <param> + <name>File</name> + <key>file</key> + <value></value> + <type>file_open</type> + </param> + <param> + <name>Repeat</name> + <key>repeat</key> + <value>True</value> + <type>enum</type> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + </param> + <param> + <name>N Channels</name> + <key>nchan</key> + <value>1</value> + <type>int</type> + </param> + <check>1 <= $nchan</check> + <source> + <name>out</name> + <type>float</type> + <nports>$nchan</nports> + </source> +</block> diff --git a/grc/blocks/gr_xor_xx.xml b/grc/blocks/gr_xor_xx.xml new file mode 100644 index 000000000..c014cbe57 --- /dev/null +++ b/grc/blocks/gr_xor_xx.xml @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Logical Xor Block +################################################### + --> +<block> + <name>Xor</name> + <key>gr_xor_xx</key> + <import>from gnuradio import gr</import> + <make>gr.xor_$(type.fcn)()</make> + <param> + <name>IO Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:ii</opt> + </option> + <option> + <name>Shxort</name> + <key>short</key> + <opt>fcn:ss</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:bb</opt> + </option> + </param> + <param> + <name>Num Inputs</name> + <key>num_inputs</key> + <value>2</value> + <type>int</type> + </param> + <check>$num_inputs >= 2</check> + <sink> + <name>in</name> + <type>$type</type> + <nports>$num_inputs</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/grc/blocks/high_pass_filter.xml b/grc/blocks/high_pass_filter.xml new file mode 100644 index 000000000..0e29cbb36 --- /dev/null +++ b/grc/blocks/high_pass_filter.xml @@ -0,0 +1,127 @@ +<?xml version="1.0"?> +<!-- +################################################### +##High Pass Filter: Custom wrapper +################################################### + --> +<block> + <name>High Pass Filter</name> + <key>high_pass_filter</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.high_pass( + $gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</make> + <callback>set_taps(firdes.high_pass($gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</callback> + <param> + <name>FIR Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex->Complex (Decimating)</name> + <key>fir_filter_ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + </option> + <option> + <name>Complex->Complex (Interpolating)</name> + <key>interp_fir_filter_ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + </option> + <option> + <name>Float->Float (Decimating)</name> + <key>fir_filter_fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + </option> + <option> + <name>Float->Float (Interpolating)</name> + <key>interp_fir_filter_fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + </option> + </param> + <param> + <name>Decimation</name> + <key>decim</key> + <value>1</value> + <type>int</type> + <hide>#if str($type).startswith('interp') then 'all' else 'none'#</hide> + </param> + <param> + <name>Interpolation</name> + <key>interp</key> + <value>1</value> + <type>int</type> + <hide>#if str($type).startswith('interp') then 'none' else 'all'#</hide> + </param> + <param> + <name>Gain</name> + <key>gain</key> + <value>1</value> + <type>real</type> + </param> + <param> + <name>Sample Rate</name> + <key>samp_rate</key> + <value>samp_rate</value> + <type>real</type> + </param> + <param> + <name>Cutoff Freq</name> + <key>cutoff_freq</key> + <type>real</type> + </param> + <param> + <name>Transition Width</name> + <key>width</key> + <type>real</type> + </param> + <param> + <name>Window</name> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + <type>int</type> + <option> + <name>Hamming</name> + <key>firdes.WIN_HAMMING</key> + </option> + <option> + <name>Hann</name> + <key>firdes.WIN_HANN</key> + </option> + <option> + <name>Blackman</name> + <key>firdes.WIN_BLACKMAN</key> + </option> + <option> + <name>Rectangular</name> + <key>firdes.WIN_RECTANGULAR</key> + </option> + <option> + <name>Kaiser</name> + <key>firdes.WIN_KAISER</key> + </option> + </param> + <param> + <name>Beta</name> + <key>beta</key> + <value>6.76</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> + <doc> +This filter is a convenience wrapper for an fir filter and a firdes taps generating function. + +Sample rate, cutoff frequency, and transition width are in Hertz. + +The beta paramater only applies to the Kaiser window. + </doc> +</block> diff --git a/grc/blocks/import.xml b/grc/blocks/import.xml new file mode 100644 index 000000000..feea052d3 --- /dev/null +++ b/grc/blocks/import.xml @@ -0,0 +1,26 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Import python modules into the namespace +################################################### + --> +<block> + <name>Import</name> + <key>import</key> + <import>$import</import> + <make></make> + <param> + <name>Import</name> + <key>import</key> + <value></value> + <type>import</type> + </param> + <doc> +Import additional python modules into the namespace. + +Examples: +from gnuradio.gr import firdes +import math,cmath +from math import pi + </doc> +</block> diff --git a/grc/blocks/low_pass_filter.xml b/grc/blocks/low_pass_filter.xml new file mode 100644 index 000000000..26435fd4d --- /dev/null +++ b/grc/blocks/low_pass_filter.xml @@ -0,0 +1,127 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Low Pass Filter: Custom wrapper +################################################### + --> +<block> + <name>Low Pass Filter</name> + <key>low_pass_filter</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.low_pass( + $gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</make> + <callback>set_taps(firdes.low_pass($gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</callback> + <param> + <name>FIR Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex->Complex (Decimating)</name> + <key>fir_filter_ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + </option> + <option> + <name>Complex->Complex (Interpolating)</name> + <key>interp_fir_filter_ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + </option> + <option> + <name>Float->Float (Decimating)</name> + <key>fir_filter_fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + </option> + <option> + <name>Float->Float (Interpolating)</name> + <key>interp_fir_filter_fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + </option> + </param> + <param> + <name>Decimation</name> + <key>decim</key> + <value>1</value> + <type>int</type> + <hide>#if str($type).startswith('interp') then 'all' else 'none'#</hide> + </param> + <param> + <name>Interpolation</name> + <key>interp</key> + <value>1</value> + <type>int</type> + <hide>#if str($type).startswith('interp') then 'none' else 'all'#</hide> + </param> + <param> + <name>Gain</name> + <key>gain</key> + <value>1</value> + <type>real</type> + </param> + <param> + <name>Sample Rate</name> + <key>samp_rate</key> + <value>samp_rate</value> + <type>real</type> + </param> + <param> + <name>Cutoff Freq</name> + <key>cutoff_freq</key> + <type>real</type> + </param> + <param> + <name>Transition Width</name> + <key>width</key> + <type>real</type> + </param> + <param> + <name>Window</name> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + <type>int</type> + <option> + <name>Hamming</name> + <key>firdes.WIN_HAMMING</key> + </option> + <option> + <name>Hann</name> + <key>firdes.WIN_HANN</key> + </option> + <option> + <name>Blackman</name> + <key>firdes.WIN_BLACKMAN</key> + </option> + <option> + <name>Rectangular</name> + <key>firdes.WIN_RECTANGULAR</key> + </option> + <option> + <name>Kaiser</name> + <key>firdes.WIN_KAISER</key> + </option> + </param> + <param> + <name>Beta</name> + <key>beta</key> + <value>6.76</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> + <doc> +This filter is a convenience wrapper for an fir filter and a firdes taps generating function. + +Sample rate, cutoff frequency, and transition width are in Hertz. + +The beta paramater only applies to the Kaiser window. + </doc> +</block> diff --git a/grc/blocks/note.xml b/grc/blocks/note.xml new file mode 100644 index 000000000..db6687c03 --- /dev/null +++ b/grc/blocks/note.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Note Block (dummy) +################################################### + --> +<block> + <name>Note</name> + <key>note</key> + <make></make> + <param> + <name>Note</name> + <key>note</key> + <value></value> + <type>string</type> + </param> +</block> diff --git a/grc/blocks/options.xml b/grc/blocks/options.xml new file mode 100644 index 000000000..1cf0b7707 --- /dev/null +++ b/grc/blocks/options.xml @@ -0,0 +1,190 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Options Block: +## options for window size, +## and flow graph building. +################################################### + --> +<block> + <name>Options</name> + <key>options</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <import>#if $generate_options() == 'wx_gui' +from grc_gnuradio import wxgui as grc_wxgui +import wx +#end if +#if $generate_options() == 'qt_gui' +from PyQt4 import Qt +import sys +#end if +#if $generate_options() != 'hb' +from optparse import OptionParser +from gnuradio.eng_option import eng_option +from gnuradio import eng_notation +#end if</import> + <make></make> + <callback>if $run: self.start() +else: self.stop(); self.wait()</callback> + <param> + <name>Title</name> + <key>title</key> + <value></value> + <type>string</type> + <hide>#if $title() then 'none' else 'part'#</hide> + </param> + <param> + <name>Author</name> + <key>author</key> + <value></value> + <type>string</type> + <hide>#if $author() then 'none' else 'part'#</hide> + </param> + <param> + <name>Description</name> + <key>description</key> + <value></value> + <type>string</type> + <hide>#if $description() then 'none' else 'part'#</hide> + </param> + <param> + <name>Window Size</name> + <key>window_size</key> + <value>1280, 1024</value> + <type>int_vector</type> + <hide>part</hide> + </param> + <param> + <name>Generate Options</name> + <key>generate_options</key> + <value>wx_gui</value> + <type>enum</type> + <option> + <name>WX GUI</name> + <key>wx_gui</key> + </option> + <option> + <name>QT GUI</name> + <key>qt_gui</key> + </option> + <option> + <name>No GUI</name> + <key>no_gui</key> + </option> + <option> + <name>Hier Block</name> + <key>hb</key> + </option> + </param> + <param> + <name>Category</name> + <key>category</key> + <value>Custom</value> + <type>string</type> + <hide>#if $generate_options() == 'hb' then 'none' else 'all'#</hide> + </param> + <param> + <name>Run Options</name> + <key>run_options</key> + <value>prompt</value> + <type>enum</type> + <hide>#if $generate_options() == 'no_gui' then 'none' else 'all'#</hide> + <option> + <name>Run to Completion</name> + <key>run</key> + </option> + <option> + <name>Prompt for Exit</name> + <key>prompt</key> + </option> + </param> + <param> + <name>Run</name> + <key>run</key> + <value>True</value> + <type>bool</type> + <hide> +#if $generate_options() in ('qt_gui', 'wx_gui') + #if $run() + part + #else + none + #end if +#else + all +#end if + </hide> + <option> + <name>Autostart</name> + <key>True</key> + </option> + <option> + <name>Off</name> + <key>False</key> + </option> + </param> + <param> + <name>Max Number of Output</name> + <key>max_nouts</key> + <value>0</value> + <type>int</type> + <hide>#if $generate_options() == 'hb' +all#slurp +#elif $max_nouts() +none#slurp +#else +part#slurp +#end if</hide> + </param> + <param> + <name>Realtime Scheduling</name> + <key>realtime_scheduling</key> + <value></value> + <type>enum</type> + <hide>#if $generate_options() == 'hb' +all#slurp +#elif $realtime_scheduling() +none#slurp +#else +part#slurp +#end if</hide> + <option> + <name>Off</name> + <key></key> + </option> + <option> + <name>On</name> + <key>1</key> + </option> + </param> + <check>len($window_size) == 2</check> + <check>300 <= $(window_size)[0] <= 4096</check> + <check>300 <= $(window_size)[1] <= 4096</check> + <doc> +The options block sets special parameters for the flow graph. \ +Only one option block is allowed per flow graph. + +Title, author, and description parameters are for identification purposes. + +The window size controls the dimensions of the flow graph editor. \ +The window size (width, height) must be between (300, 300) and (4096, 4096). + +The generate options controls the type of code generated. \ +Non-graphical flow graphs should avoid using graphical sinks or graphical variable controls. + +In a graphical application, \ +run can be controlled by a variable to start and stop the flowgraph at runtime. + +The id of this block determines the name of the generated file and the name of the class. \ +For example, an id of my_block will generate the file my_block.py and class my_block(gr.... + +The category parameter determines the placement of the block in the block selection window. \ +The category only applies when creating hier blocks. \ +To put hier blocks into the root category, enter / for the category. + +The Max Number of Output is the maximum number of output items allowed for any block \ +in the flowgraph; to disable this set the max_nouts equal to 0.\ +Use this to adjust the maximum latency a flowgraph can exhibit. + </doc> +</block> diff --git a/grc/blocks/pad_sink.xml b/grc/blocks/pad_sink.xml new file mode 100644 index 000000000..f0e10a339 --- /dev/null +++ b/grc/blocks/pad_sink.xml @@ -0,0 +1,91 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Pad Sink: IO Pads +################################################### + --> +<block> + <name>Pad Sink</name> + <key>pad_sink</key> + <make>#if str($type) == "message" +None;self.message_port_register_hier_in($label) +#end if</make> + <param> + <name>Label</name> + <key>label</key> + <value>out</value> + <type>string</type> + </param> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + <option> + <name>Message</name> + <key>message</key> + <opt>size:0</opt> + </option> + <option> + <name>Wildcard</name> + <key></key> + <opt>size:0</opt> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Optional</name> + <key>optional</key> + <value>False</value> + <type>bool</type> + <hide>part</hide> + <option> + <name>Optional</name> + <key>True</key> + </option> + <option> + <name>Required</name> + <key>False</key> + </option> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> + <doc> +The inputs of this block will become the outputs to this flow graph when it is instantiated as a hierarchical block. + +Pad sink will be ordered alphabetically by their ids. The first pad sink will have an index of 0. + </doc> +</block> diff --git a/grc/blocks/pad_source.xml b/grc/blocks/pad_source.xml new file mode 100644 index 000000000..a56a65dcc --- /dev/null +++ b/grc/blocks/pad_source.xml @@ -0,0 +1,91 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Pad Source: IO Pads +################################################### + --> +<block> + <name>Pad Source</name> + <key>pad_source</key> + <make>#if str($type) == "message" +None;self.message_port_register_hier_out($label) +#end if</make> + <param> + <name>Label</name> + <key>label</key> + <value>in</value> + <type>string</type> + </param> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + <option> + <name>Message</name> + <key>message</key> + <opt>size:0</opt> + </option> + <option> + <name>Wildcard</name> + <key></key> + <opt>size:0</opt> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Optional</name> + <key>optional</key> + <value>False</value> + <type>bool</type> + <hide>part</hide> + <option> + <name>Optional</name> + <key>True</key> + </option> + <option> + <name>Required</name> + <key>False</key> + </option> + </param> + <check>$vlen > 0</check> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> + <doc> +The outputs of this block will become the inputs to this flow graph when it is instantiated as a hierarchical block. + +Pad sources will be ordered alphabetically by their ids. The first pad source will have an index of 0. + </doc> +</block> diff --git a/grc/blocks/parameter.xml b/grc/blocks/parameter.xml new file mode 100644 index 000000000..e35b8f4d1 --- /dev/null +++ b/grc/blocks/parameter.xml @@ -0,0 +1,99 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Parameter block: a grc variable with key, value +################################################### + --> +<block> + <name>Parameter</name> + <key>parameter</key> + <var_make>self.$(id) = $(id)</var_make> + <make>$value</make> + <param> + <name>Label</name> + <key>label</key> + <value></value> + <type>string</type> + <hide>#if $label() then 'none' else 'part'#</hide> + </param> + <param> + <name>Value</name> + <key>value</key> + <value>0</value> + <type>$type.type</type> + </param> + <param> + <name>Type</name> + <key>type</key> + <value></value> + <type>enum</type> + <hide>#if $type() then 'none' else 'part'#</hide> + <option> + <name>None</name> + <key></key> + <opt>type:raw</opt> + </option> + <option> + <name>Complex</name> + <key>complex</key> + <opt>type:complex</opt> + </option> + <option> + <name>Float</name> + <key>eng_float</key> + <opt>type:real</opt> + </option> + <option> + <name>Int</name> + <key>intx</key> + <opt>type:int</opt> + </option> + <option> + <name>Long</name> + <key>long</key> + <opt>type:int</opt> + </option> + <option> + <name>String</name> + <key>string</key> + <opt>type:string</opt> + </option> + <!-- not supported yet in tmpl + <option> + <name>Boolean</name> + <key>bool</key> + <opt>type:bool</opt> + </option> + --> + </param> + <param> + <name>Short ID</name> + <key>short_id</key> + <value></value> + <type>string</type> + <hide>#if not $type() +all#slurp +#elif $short_id() +none#slurp +#else +part#slurp +#end if</hide> + </param> + <check>len($short_id) in (0, 1)</check> + <check>$short_id == '' or $(short_id).isalpha()</check> + <doc> +This block represents a parameter to the flow graph. \ +A parameter can be used to pass command line arguments into a top block. \ +Or, parameters can pass arguments into an instantiated hierarchical block. + +The paramater value cannot depend on any variables. + +Leave the label blank to use the parameter id as the label. + +When type is not None, this parameter also becomes a command line option of the form: + +-[short_id] --[id] [value] + +The Short ID field may be left blank. + </doc> +</block> diff --git a/grc/blocks/random_source_x.xml b/grc/blocks/random_source_x.xml new file mode 100644 index 000000000..800bae716 --- /dev/null +++ b/grc/blocks/random_source_x.xml @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Random Source: +## Custom block +################################################### + --> +<block> + <name>Random Source</name> + <key>random_source_x</key> + <import>from gnuradio import gr</import> + <import>import numpy</import> + <make>gr.vector_source_$(type.fcn)(map(int, numpy.random.randint($min, $max, $num_samps)), $repeat)</make> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Int</name> + <key>int</key> + <opt>fcn:i</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>fcn:s</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>fcn:b</opt> + </option> + </param> + <param> + <name>Minimum</name> + <key>min</key> + <value>0</value> + <type>int</type> + </param> + <param> + <name>Maximum</name> + <key>max</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Num Samples</name> + <key>num_samps</key> + <value>1000</value> + <type>int</type> + </param> + <param> + <name>Repeat</name> + <key>repeat</key> + <value>True</value> + <type>enum</type> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + </param> + <source> + <name>out</name> + <type>$type</type> + </source> + <doc> +Generate num samples of random numbers of [min, max). Repeat samples if specified. + +Ex: With min=0 and max=2, the sequence 01110101... will be generated. + </doc> +</block> diff --git a/grc/blocks/root_raised_cosine_filter.xml b/grc/blocks/root_raised_cosine_filter.xml new file mode 100644 index 000000000..81688d297 --- /dev/null +++ b/grc/blocks/root_raised_cosine_filter.xml @@ -0,0 +1,101 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Root Raised Cosine Filter: Custom wrapper +################################################### + --> +<block> + <name>Root Raised Cosine Filter</name> + <key>root_raised_cosine_filter</key> + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.root_raised_cosine( + $gain, $samp_rate, $sym_rate, $alpha, $ntaps))</make> + <callback>set_taps(firdes.root_raised_cosine($gain, $samp_rate, $sym_rate, $alpha, $ntaps))</callback> + <param> + <name>FIR Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex->Complex (Decimating)</name> + <key>fir_filter_ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + </option> + <option> + <name>Complex->Complex (Interpolating)</name> + <key>interp_fir_filter_ccf</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + </option> + <option> + <name>Float->Float (Decimating)</name> + <key>fir_filter_fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + </option> + <option> + <name>Float->Float (Interpolating)</name> + <key>interp_fir_filter_fff</key> + <opt>input:float</opt> + <opt>output:float</opt> + </option> + </param> + <param> + <name>Decimation</name> + <key>decim</key> + <value>1</value> + <type>int</type> + <hide>#if str($type).startswith('interp') then 'all' else 'none'#</hide> + </param> + <param> + <name>Interpolation</name> + <key>interp</key> + <value>1</value> + <type>int</type> + <hide>#if str($type).startswith('interp') then 'none' else 'all'#</hide> + </param> + <param> + <name>Gain</name> + <key>gain</key> + <value>1</value> + <type>real</type> + </param> + <param> + <name>Sample Rate</name> + <key>samp_rate</key> + <value>samp_rate</value> + <type>real</type> + </param> + <param> + <name>Symbol Rate</name> + <key>sym_rate</key> + <value>1.0</value> + <type>real</type> + </param> + <param> + <name>Alpha</name> + <key>alpha</key> + <value>0.35</value> + <type>real</type> + </param> + <param> + <name>Num Taps</name> + <key>ntaps</key> + <value>11*samp_rate</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> + <doc> +This filter is a convenience wrapper for an fir filter and a firdes taps generating function. + +Sample rate in Hertz. + </doc> +</block> diff --git a/grc/blocks/variable.xml b/grc/blocks/variable.xml new file mode 100644 index 000000000..afee0f5d4 --- /dev/null +++ b/grc/blocks/variable.xml @@ -0,0 +1,23 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Variable block: a grc variable with key, value +################################################### + --> +<block> + <name>Variable</name> + <key>variable</key> + <var_make>self.$(id) = $(id) = $value</var_make> + <make></make> + <callback>self.set_$(id)($value)</callback> + <param> + <name>Value</name> + <key>value</key> + <value>0</value> + <type>raw</type> + </param> + <doc> +This block maps a value to a unique variable. \ +This variable block has no graphical representation. + </doc> +</block> diff --git a/grc/blocks/variable_config.xml b/grc/blocks/variable_config.xml new file mode 100644 index 000000000..11bff9edc --- /dev/null +++ b/grc/blocks/variable_config.xml @@ -0,0 +1,88 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Variable Config block: +## a variable that reads and writes to a config file +################################################### + --> +<block> + <name>Variable Config</name> + <key>variable_config</key> + <import>import ConfigParser</import> + <var_make>self._$(id)_config = ConfigParser.ConfigParser() +self._$(id)_config.read($config_file) +try: $(id) = self._$(id)_config.$(type.get)($section, $option) +except: $(id) = $value +self.$(id) = $(id)</var_make> + <make></make> + <callback>self.set_$(id)($value)</callback> + <callback>self._$(id)_config = ConfigParser.ConfigParser() +self._$(id)_config.read($config_file) +if not self._$(id)_config.has_section($section): + self._$(id)_config.add_section($section) +self._$(id)_config.set($section, $option, str($writeback)) +self._$(id)_config.write(open($config_file, 'w'))</callback> + <param> + <name>Default Value</name> + <key>value</key> + <value>0</value> + <type>$type</type> + </param> + <param> + <name>Type</name> + <key>type</key> + <value>real</value> + <type>enum</type> + <option> + <name>Float</name> + <key>real</key> + <opt>get:getfloat</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>get:getint</opt> + </option> + <option> + <name>Bool</name> + <key>bool</key> + <opt>get:getboolean</opt> + </option> + <option> + <name>String</name> + <key>string</key> + <opt>get:get</opt> + </option> + </param> + <param> + <name>Config File</name> + <key>config_file</key> + <value>default</value> + <type>file_open</type> + </param> + <param> + <name>Section</name> + <key>section</key> + <value>main</value> + <type>string</type> + </param> + <param> + <name>Option</name> + <key>option</key> + <value>key</value> + <type>string</type> + </param> + <param> + <name>WriteBack</name> + <key>writeback</key> + <value>None</value> + <type>raw</type> + </param> + <doc> +This block represents a variable that can be read from a config file. + +To save the value back into the config file: \ +enter the name of another variable into the writeback param. \ +When the other variable is changed at runtime, the config file will be re-written. + </doc> +</block> diff --git a/grc/blocks/variable_function_probe.xml b/grc/blocks/variable_function_probe.xml new file mode 100644 index 000000000..269966c70 --- /dev/null +++ b/grc/blocks/variable_function_probe.xml @@ -0,0 +1,70 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Variable function probe +################################################### + --> +<block> + <name>Function Probe</name> + <key>variable_function_probe</key> + <import>import time</import> + <import>import threading</import> + <var_make>self.$(id) = $(id) = $value</var_make> + <make>#slurp +def _$(id)_probe(): + while True: + val = self.$(block_id()).$(function_name())($(function_args())) + try: self.set_$(id)(val) + except AttributeError, e: pass + time.sleep(1.0/($poll_rate)) +_$(id)_thread = threading.Thread(target=_$(id)_probe) +_$(id)_thread.daemon = True +_$(id)_thread.start()</make> + <callback>self.set_$(id)($value)</callback> + <param> + <name>Value</name> + <key>value</key> + <value>0</value> + <type>raw</type> + </param> + <param> + <name>Block ID</name> + <key>block_id</key> + <value>my_block_0</value> + <type>string</type> + </param> + <param> + <name>Function Name</name> + <key>function_name</key> + <value>get_number</value> + <type>string</type> + </param> + <param> + <name>Function Args</name> + <key>function_args</key> + <value></value> + <type>string</type> + <hide>#if $function_args() then 'none' else 'part'#</hide> + </param> + <param> + <name>Poll Rate (Hz)</name> + <key>poll_rate</key> + <value>10</value> + <type>real</type> + </param> + <doc> +Periodically probe a function and set its value to this variable. + +Set the values for block ID, function name, and function args appropriately: \ +Block ID should be the ID of another block in this flow graph. \ +Function name should be the name of a class method on that block. \ +Function args are the parameters passed into that function. \ +For a function with no arguments, leave function args blank. \ +When passing a string for the function arguments, quote the string literal: '"arg"'. + +The values will used literally, and generated into the following form: +self.block_id.function_name(function_args) + +To poll a stream for a level, use this with the probe signal block. + </doc> +</block> diff --git a/grc/blocks/virtual_sink.xml b/grc/blocks/virtual_sink.xml new file mode 100644 index 000000000..35fb27e67 --- /dev/null +++ b/grc/blocks/virtual_sink.xml @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Virtual Sink +################################################### + --> +<block> + <name>Virtual Sink</name> + <key>virtual_sink</key> + <make></make> + <param> + <name>Stream ID</name> + <key>stream_id</key> + <value></value> + <type>stream_id</type> + </param> + <sink> + <name>in</name> + <type></type> + </sink> +</block> diff --git a/grc/blocks/virtual_source.xml b/grc/blocks/virtual_source.xml new file mode 100644 index 000000000..e0c775449 --- /dev/null +++ b/grc/blocks/virtual_source.xml @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Virtual Source +################################################### + --> +<block> + <name>Virtual Source</name> + <key>virtual_source</key> + <make></make> + <param> + <name>Stream ID</name> + <key>stream_id</key> + <value></value> + <type>stream_id</type> + </param> + <source> + <name>out</name> + <type></type> + </source> +</block> diff --git a/grc/blocks/xmlrpc_client.xml b/grc/blocks/xmlrpc_client.xml new file mode 100644 index 000000000..dc4d154d1 --- /dev/null +++ b/grc/blocks/xmlrpc_client.xml @@ -0,0 +1,42 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Simple XMLRPC Client +################################################### + --> +<block> + <name>XMLRPC Client</name> + <key>xmlrpc_client</key> + <import>import xmlrpclib</import> + <make>xmlrpclib.Server('http://$(addr()):$(port)')</make> + <callback>$(callback())($variable)</callback> + <param> + <name>Address</name> + <key>addr</key> + <value>localhost</value> + <type>string</type> + </param> + <param> + <name>Port</name> + <key>port</key> + <value>8080</value> + <type>int</type> + </param> + <param> + <name>Callback</name> + <key>callback</key> + <value>set_</value> + <type>string</type> + </param> + <param> + <name>Variable</name> + <key>variable</key> + <type>raw</type> + </param> + <doc> +This block will create an XMLRPC client. \ +The client will execute the callback on the server when the variable is changed. \ +The callback should be a the name of a function registered on the server. \ +The variable should be an expression containing a the name of a variable in flow graph. + </doc> +</block> diff --git a/grc/blocks/xmlrpc_server.xml b/grc/blocks/xmlrpc_server.xml new file mode 100644 index 000000000..6c31bd1a9 --- /dev/null +++ b/grc/blocks/xmlrpc_server.xml @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Simple XMLRPC Server +################################################### + --> +<block> + <name>XMLRPC Server</name> + <key>xmlrpc_server</key> + <import>import SimpleXMLRPCServer</import> + <import>import threading</import> + <make>SimpleXMLRPCServer.SimpleXMLRPCServer(($addr, $port), allow_none=True) +self.$(id).register_instance(self) +threading.Thread(target=self.$(id).serve_forever).start()</make> + <param> + <name>Address</name> + <key>addr</key> + <value>localhost</value> + <type>string</type> + </param> + <param> + <name>Port</name> + <key>port</key> + <value>8080</value> + <type>int</type> + </param> + <doc> +This block will start an XMLRPC server. \ +The server provides access to the run, start, stop, wait functions of the flow graph. \ +The server also provides access to the variable callbacks in the flow graph. \ +Ex: If the variable is called freq, the function provided by the server will be called set_freq(new_freq). + +Example client in python: + +import xmlrpclib +s = xmlrpclib.Server('http://localhost:8080') +s.set_freq(5000) + </doc> +</block> diff --git a/grc/cpp/README b/grc/cpp/README new file mode 100644 index 000000000..3eccc5dbf --- /dev/null +++ b/grc/cpp/README @@ -0,0 +1,5 @@ +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/CMakeLists.txt b/grc/examples/CMakeLists.txt new file mode 100644 index 000000000..a218dbe50 --- /dev/null +++ b/grc/examples/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright 2011 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. + +# SIMPLE +install( + FILES + simple/variable_config.grc + DESTINATION ${GR_PKG_DATA_DIR}/examples/grc/simple + COMPONENT "grc" +) + +# XMLRPC +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 + COMPONENT "grc" +) diff --git a/grc/examples/simple/variable_config.grc b/grc/examples/simple/variable_config.grc new file mode 100644 index 000000000..95c287cce --- /dev/null +++ b/grc/examples/simple/variable_config.grc @@ -0,0 +1,329 @@ +<?xml version='1.0' encoding='ASCII'?> +<flow_graph> + <timestamp>Thu Jun 25 10:56:04 2009</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>wx_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>autostart</key> + <value>True</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</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>_coordinate</key> + <value>(10, 170)</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>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>_coordinate</key> + <value>(255, 17)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</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>freq_init</value> + </param> + <param> + <key>min</key> + <value>-samp_rate/2</value> + </param> + <param> + <key>max</key> + <value>samp_rate/2</value> + </param> + <param> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(429, 24)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_throttle</key> + <param> + <key>id</key> + <value>gr_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>_coordinate</key> + <value>(392, 233)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_sig_source_x</key> + <param> + <key>id</key> + <value>gr_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>gr.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>_coordinate</key> + <value>(148, 233)</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> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>title</key> + <value>FFT Plot</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>baseband_freq</key> + <value>0</value> + </param> + <param> + <key>y_per_div</key> + <value>10</value> + </param> + <param> + <key>y_divs</key> + <value>10</value> + </param> + <param> + <key>ref_level</key> + <value>50</value> + </param> + <param> + <key>fft_size</key> + <value>1024</value> + </param> + <param> + <key>fft_rate</key> + <value>30</value> + </param> + <param> + <key>peak_hold</key> + <value>False</value> + </param> + <param> + <key>average</key> + <value>False</value> + </param> + <param> + <key>avg_alpha</key> + <value>0</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(671, 233)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>gr_sig_source_x_0</source_block_id> + <sink_block_id>gr_throttle_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_throttle_0</source_block_id> + <sink_block_id>wxgui_fftsink2_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 new file mode 100644 index 000000000..056ad1e82 --- /dev/null +++ b/grc/examples/xmlrpc/readme.txt @@ -0,0 +1,18 @@ +################################################## +# 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 new file mode 100644 index 000000000..3bb4e7ed3 --- /dev/null +++ b/grc/examples/xmlrpc/xmlrpc_client.grc @@ -0,0 +1,312 @@ +<?xml version='1.0' encoding='ASCII'?> +<flow_graph> + <timestamp>Thu Jul 24 14:27:44 2008</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>wx_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</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>_coordinate</key> + <value>(409, 35)</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>_coordinate</key> + <value>(222, 34)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</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>min</key> + <value>0</value> + </param> + <param> + <key>max</key> + <value>5000</value> + </param> + <param> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>slider_type</key> + <value>horizontal</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 0, 1, 2</value> + </param> + <param> + <key>_coordinate</key> + <value>(207, 162)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</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>min</key> + <value>0</value> + </param> + <param> + <key>max</key> + <value>2</value> + </param> + <param> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>slider_type</key> + <value>horizontal</value> + </param> + <param> + <key>grid_pos</key> + <value>1, 0, 1, 2</value> + </param> + <param> + <key>_coordinate</key> + <value>(397, 167)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_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>value_index</key> + <value>1</value> + </param> + <param> + <key>choices</key> + <value>[-1, 0, 1]</value> + </param> + <param> + <key>labels</key> + <value>["neg", "zero", "pos"]</value> + </param> + <param> + <key>chooser_type</key> + <value>radio_buttons_horizontal</value> + </param> + <param> + <key>grid_pos</key> + <value>2, 0, 1, 2</value> + </param> + <param> + <key>_coordinate</key> + <value>(596, 177)</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>_coordinate</key> + <value>(608, 39)</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>_coordinate</key> + <value>(13, 172)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> +</flow_graph>
\ No newline at end of file diff --git a/grc/examples/xmlrpc/xmlrpc_client_script.py b/grc/examples/xmlrpc/xmlrpc_client_script.py new file mode 100644 index 000000000..8f00fa55d --- /dev/null +++ b/grc/examples/xmlrpc/xmlrpc_client_script.py @@ -0,0 +1,23 @@ +#!/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 new file mode 100644 index 000000000..dc539ef1b --- /dev/null +++ b/grc/examples/xmlrpc/xmlrpc_server.grc @@ -0,0 +1,384 @@ +<?xml version='1.0' encoding='ASCII'?> +<flow_graph> + <timestamp>Thu Jul 24 14:27:42 2008</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>wx_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_sig_source_x</key> + <param> + <key>id</key> + <value>gr_sig_source_x</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>gr.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>_coordinate</key> + <value>(162, 200)</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>_coordinate</key> + <value>(12, 390)</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>_coordinate</key> + <value>(395, 240)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_throttle</key> + <param> + <key>id</key> + <value>gr_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>_coordinate</key> + <value>(386, 93)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_scopesink2</key> + <param> + <key>id</key> + <value>wxgui_scopesink2</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>title</key> + <value>Scope Plot</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>frame_decim</key> + <value>15</value> + </param> + <param> + <key>v_scale</key> + <value>0</value> + </param> + <param> + <key>t_scale</key> + <value>.001</value> + </param> + <param> + <key>marker</key> + <value>set_format_line</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 0, 2, 4</value> + </param> + <param> + <key>_coordinate</key> + <value>(623, 28)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_fftsink2</key> + <param> + <key>id</key> + <value>wxgui_fftsink2</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>title</key> + <value>FFT Plot</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>baseband_freq</key> + <value>0</value> + </param> + <param> + <key>y_per_div</key> + <value>10</value> + </param> + <param> + <key>y_divs</key> + <value>8</value> + </param> + <param> + <key>ref_level</key> + <value>50</value> + </param> + <param> + <key>fft_size</key> + <value>512</value> + </param> + <param> + <key>fft_rate</key> + <value>15</value> + </param> + <param> + <key>avg_alpha</key> + <value>0</value> + </param> + <param> + <key>average</key> + <value>False</value> + </param> + <param> + <key>peak_hold</key> + <value>False</value> + </param> + <param> + <key>grid_pos</key> + <value>2, 0, 2, 4</value> + </param> + <param> + <key>_coordinate</key> + <value>(630, 233)</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>_coordinate</key> + <value>(11, 160)</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>_coordinate</key> + <value>(11, 237)</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>_coordinate</key> + <value>(13, 315)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>gr_sig_source_x</source_block_id> + <sink_block_id>gr_throttle</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_throttle</source_block_id> + <sink_block_id>wxgui_scopesink2</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_throttle</source_block_id> + <sink_block_id>wxgui_fftsink2</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph>
\ No newline at end of file diff --git a/grc/freedesktop/CMakeLists.txt b/grc/freedesktop/CMakeLists.txt new file mode 100644 index 000000000..d95fe04ac --- /dev/null +++ b/grc/freedesktop/CMakeLists.txt @@ -0,0 +1,47 @@ +# Copyright 2011-2012 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. + +######################################################################## +set(grc_freedesktop_path ${GR_PKG_DATA_DIR}/grc/freedesktop) + +install(FILES + grc-icon-256.png + grc-icon-128.png + grc-icon-64.png + grc-icon-48.png + grc-icon-32.png + gnuradio-grc.xml + gnuradio-grc.desktop + DESTINATION ${grc_freedesktop_path} + COMPONENT "grc" +) + +find_program(HAVE_XDG_UTILS xdg-desktop-menu) + +if(UNIX AND HAVE_XDG_UTILS) + set(SRCDIR ${CMAKE_INSTALL_PREFIX}/${grc_freedesktop_path}) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/grc_setup_freedesktop.in + ${CMAKE_CURRENT_BINARY_DIR}/grc_setup_freedesktop + @ONLY) + install( + PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/grc_setup_freedesktop + DESTINATION ${GR_PKG_LIBEXEC_DIR} COMPONENT "grc" + ) +endif(UNIX AND HAVE_XDG_UTILS) diff --git a/grc/freedesktop/README b/grc/freedesktop/README new file mode 100644 index 000000000..0857ecc22 --- /dev/null +++ b/grc/freedesktop/README @@ -0,0 +1,20 @@ +################################################## +# Freedesktop Notes +################################################## + +This directory contains icons, a mime type, and menu files for grc. +Installation of these files requires a set of tools called xdg-utils. +xdg-utils will install files in a standard way according to the freedesktop.org standards. + +Desktop enviroments that implement these standards are gnome, kde, xfce, and others. +If you have one of these desktop enviroments, xdg-utils should come installed. +If xdg-utils is not installed, then this directory will be ignored by the build. + +The gtk IconTheme module locates the installed icons for use inside the grc app. +On recent versions of gtk, IconTheme ignores the icons installed into the default theme. +This presents a problem for the gnome file system browser, nautilus, and the grc app. +As a solution, icons are also installed under the gnome theme. + +*.png files - these are the icons of various sizes +*.desktop files - these are the menu items for grc executables +*.xml file - this is the mime type for the saved flow graphs diff --git a/grc/freedesktop/gnuradio-grc.desktop b/grc/freedesktop/gnuradio-grc.desktop new file mode 100644 index 000000000..5fd049780 --- /dev/null +++ b/grc/freedesktop/gnuradio-grc.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=GRC +Exec=gnuradio-companion %F +Categories=Development; +MimeType=application/gnuradio-grc; +Icon=gnuradio-grc diff --git a/grc/freedesktop/gnuradio-grc.xml b/grc/freedesktop/gnuradio-grc.xml new file mode 100644 index 000000000..a5cb95d9f --- /dev/null +++ b/grc/freedesktop/gnuradio-grc.xml @@ -0,0 +1,8 @@ +<?xml version="1.0"?> +<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'> + <mime-type type="application/gnuradio-grc"> + <sub-class-of type="application/xml"/> + <glob pattern="*.grc"/> + <glob pattern="*.grc.xml"/> + </mime-type> +</mime-info> diff --git a/grc/freedesktop/grc-icon-128.png b/grc/freedesktop/grc-icon-128.png Binary files differnew file mode 100644 index 000000000..d94ef35dc --- /dev/null +++ b/grc/freedesktop/grc-icon-128.png diff --git a/grc/freedesktop/grc-icon-256.png b/grc/freedesktop/grc-icon-256.png Binary files differnew file mode 100644 index 000000000..e4e8e54ae --- /dev/null +++ b/grc/freedesktop/grc-icon-256.png diff --git a/grc/freedesktop/grc-icon-256.svg b/grc/freedesktop/grc-icon-256.svg new file mode 100644 index 000000000..87526d46c --- /dev/null +++ b/grc/freedesktop/grc-icon-256.svg @@ -0,0 +1,216 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="256" + height="256" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.44.1" + version="1.0" + sodipodi:docbase="/home/past/src" + sodipodi:docname="grc-icon-v3.svg" + inkscape:export-filename="/home/past/src/grc-icon-v3.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs4"> + <linearGradient + id="linearGradient3661"> + <stop + style="stop-color:#0012dc;stop-opacity:1;" + offset="0" + id="stop3663" /> + <stop + style="stop-color:#8b92ff;stop-opacity:0.55371898;" + offset="1" + id="stop3665" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3661" + id="linearGradient2801" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-162.6648,798.0997)" + x1="17.664845" + y1="132.0565" + x2="157.82524" + y2="132.0565" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2.7382812" + inkscape:cx="126.48791" + inkscape:cy="128.00013" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="true" + gridoriginx="1px" + gridoriginy="1px" + gridspacingx="2px" + gridspacingy="2px" + guidecolor="#00ff0a" + guideopacity="0.49803922" + inkscape:grid-points="true" + inkscape:window-width="1098" + inkscape:window-height="904" + inkscape:window-x="149" + inkscape:window-y="42" + showguides="true" + inkscape:guide-bbox="true" + inkscape:object-points="true" + inkscape:object-nodes="true" + inkscape:object-bbox="true"> + <sodipodi:guide + orientation="vertical" + position="224" + id="guide10639" /> + <sodipodi:guide + orientation="vertical" + position="227.64729" + id="guide10641" /> + <sodipodi:guide + orientation="vertical" + position="220" + id="guide10643" /> + <sodipodi:guide + orientation="horizontal" + position="268.4015" + id="guide10645" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <cc:license + rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" /> + <dc:creator> + <cc:Agent> + <dc:title>Patrick Strasser <patrick.strasser@tugraz.at></dc:title> + </cc:Agent> + </dc:creator> + <dc:description>Icon/Symbol for the GNURadio Companion</dc:description> + <dc:title>grc-icon.svg</dc:title> + <dc:date>2007-02-23</dc:date> + </cc:Work> + <cc:License + rdf:about="http://creativecommons.org/licenses/by-sa/2.5/"> + <cc:permits + rdf:resource="http://web.resource.org/cc/Reproduction" /> + <cc:permits + rdf:resource="http://web.resource.org/cc/Distribution" /> + <cc:requires + rdf:resource="http://web.resource.org/cc/Notice" /> + <cc:requires + rdf:resource="http://web.resource.org/cc/Attribution" /> + <cc:permits + rdf:resource="http://web.resource.org/cc/DerivativeWorks" /> + <cc:requires + rdf:resource="http://web.resource.org/cc/ShareAlike" /> + </cc:License> + </rdf:RDF> + </metadata> + <g + inkscape:label="Ebene 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-796.3622)"> + <g + id="g7451" + transform="matrix(1.025628,0,0,1.030546,-0.101723,-32.00742)"> + <path + id="rect2760" + d="M 4.1981031,916.37787 L 160.00074,916.37787 L 160.00074,1048.3467 L 4.1981031,1048.3467 L 4.1981031,916.37787 z " + style="fill:white;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:7.78145933;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + <g + transform="matrix(0.995753,0,0,1.003897,164.8198,-8.972397)" + id="g2789" + style="stroke-width:8;stroke-miterlimit:4;stroke-dasharray:none"> + <rect + style="fill:url(#linearGradient2801);fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:7.78288651;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect9020" + width="140.1604" + height="16.796082" + x="-145" + y="921.75818" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:7.78288651;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M -161.50649,938.55428 L -4.8395996,938.55428" + id="path9005" /> + </g> + </g> + <g + id="g5503" + transform="matrix(1.028571,0,0,1.172413,-5.14284,-137.9928)"> + <rect + y="800.36212" + x="40" + height="116.00005" + width="140" + id="rect4562" + style="fill:#f3c690;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:7.28504848;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + <g + transform="matrix(0.921053,0,0,1,26.93956,1.859948)" + id="g3694"> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:7.59084845;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 44,820.3622 L 136.35974,820.3622" + id="path4564" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:7.59084749;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 80,811.74976 L 80,828.3622" + id="path5451" /> + </g> + <g + id="g5499"> + <rect + style="fill:white;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:7.28504944;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect7223" + width="140" + height="68.000015" + x="40" + y="848.36218" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:7.28505039;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 57.001362,905.90132 C 88.923615,905.8552 86.182775,867.89142 95.399136,867.52563 C 104.60967,867.16008 113.73233,867.60291 124.38688,868.00066 C 137.23411,868.48027 130.39915,906.48027 162.99863,906.48027" + id="path7225" + sodipodi:nodetypes="czss" /> + </g> + </g> + <rect + style="fill:#b890f3;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:7.99999952;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect14319" + width="79.999992" + height="64.000023" + x="27.999992" + y="960.36249" /> + <rect + style="fill:#f3c690;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:7.99999905;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect15206" + width="24.000004" + height="24.000004" + x="108" + y="980.36218" /> + <path + id="path13320" + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:7.99999666;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" + d="M 220.97574,800.36203 L 220.97574,865.80513 C 236.42474,865.93437 248.49884,861.19996 248.96304,854.45866 C 249.42721,847.71737 237.26568,843.20829 221.81667,846.27676 C 206.36767,849.34522 193.45938,858.02071 192.98843,867.61976 C 192.53101,876.94268 204.68583,884.63729 220.13479,885.43882 C 235.58379,885.69443 248.49884,880.72833 248.96304,873.98703 C 249.42721,867.24575 237.26567,862.73666 221.81666,865.80513 C 206.36766,868.8736 193.45939,877.54909 192.98843,887.14813 C 192.53101,896.47106 204.68582,904.16566 220.13479,904.86701 C 235.5838,905.02246 248.49885,900.05636 248.96305,893.31506 C 249.42722,886.57378 237.26568,882.06469 221.81667,885.13316 C 206.36767,888.20162 193.45939,896.87711 192.98844,906.47616 C 192.53102,915.79909 204.68583,923.49369 220.13479,923.98015 C 235.58379,923.92069 248.49884,918.95459 248.96304,912.21329 C 249.42721,905.47201 237.26567,900.96293 221.81666,904.0314 C 206.36766,907.09986 193.45939,915.77535 192.98843,925.37439 C 192.53101,934.69732 207.20989,943.06708 221.81667,943.00644 L 221.81667,967.97713 C 221.63716,982.45754 209.62079,992.36197 195.88792,992.36199 L 132.42659,992.36199" + sodipodi:nodetypes="cccssscssscssscssccc" /> + </g> +</svg> diff --git a/grc/freedesktop/grc-icon-32.png b/grc/freedesktop/grc-icon-32.png Binary files differnew file mode 100644 index 000000000..1e4f4f6c5 --- /dev/null +++ b/grc/freedesktop/grc-icon-32.png diff --git a/grc/freedesktop/grc-icon-48.png b/grc/freedesktop/grc-icon-48.png Binary files differnew file mode 100644 index 000000000..caddc92ad --- /dev/null +++ b/grc/freedesktop/grc-icon-48.png diff --git a/grc/freedesktop/grc-icon-64.png b/grc/freedesktop/grc-icon-64.png Binary files differnew file mode 100644 index 000000000..fa8e06e28 --- /dev/null +++ b/grc/freedesktop/grc-icon-64.png diff --git a/grc/freedesktop/grc_setup_freedesktop.in b/grc/freedesktop/grc_setup_freedesktop.in new file mode 100644 index 000000000..1e3546197 --- /dev/null +++ b/grc/freedesktop/grc_setup_freedesktop.in @@ -0,0 +1,75 @@ +#!/bin/bash +# +# Copyright 2008-2011 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. +# +################################################## +# setup grc on a freedesktop platform +# $1 should be install or uninstall +# $2 is the optional path to the files +# when $2 is unspecified, the path is: +# @SRCDIR@ +################################################## + +ICON_SIZES="32 48 64 128 256" +if [ -n "$2" ]; then + SRCDIR="$2" +else + SRCDIR="@SRCDIR@" +fi + +case "$1" in +'install') + echo "Begin freedesktop install..." + for size in ${ICON_SIZES}; do \ + echo "Install icon: ${size}x${size}" + xdg-icon-resource install --noupdate --context mimetypes --theme gnome --size ${size} ${SRCDIR}/grc-icon-${size}.png application-gnuradio-grc; \ + xdg-icon-resource install --noupdate --context mimetypes --size ${size} ${SRCDIR}/grc-icon-${size}.png application-gnuradio-grc; \ + xdg-icon-resource install --noupdate --context apps --theme gnome --size ${size} ${SRCDIR}/grc-icon-${size}.png gnuradio-grc; \ + xdg-icon-resource install --noupdate --context apps --size ${size} ${SRCDIR}/grc-icon-${size}.png gnuradio-grc; \ + done + xdg-icon-resource forceupdate + echo "Install mime type" + xdg-mime install ${SRCDIR}/gnuradio-grc.xml + echo "Install menu items" + xdg-desktop-menu install ${SRCDIR}/*.desktop + echo "Done!" + echo "" + ;; +'uninstall') + echo "Begin freedesktop uninstall..." + for size in ${ICON_SIZES}; do \ + echo "Uninstall icon: ${size}x${size}" + xdg-icon-resource uninstall --noupdate --context mimetypes --theme gnome --size ${size} application-gnuradio-grc; \ + xdg-icon-resource uninstall --noupdate --context mimetypes --size ${size} application-gnuradio-grc; \ + xdg-icon-resource uninstall --noupdate --context apps --theme gnome --size ${size} gnuradio-grc; \ + xdg-icon-resource uninstall --noupdate --context apps --size ${size} gnuradio-grc; \ + done + xdg-icon-resource forceupdate + echo "Uninstall mime type" + xdg-mime uninstall ${SRCDIR}/gnuradio-grc.xml + echo "Uninstall menu items" + xdg-desktop-menu uninstall `ls ${SRCDIR}/*.desktop | xargs -n1 basename` + echo "Done!" + echo "" + ;; +*) + echo "Usage: $0 [install|uninstall]" + ;; +esac diff --git a/grc/grc.conf.in b/grc/grc.conf.in new file mode 100644 index 000000000..ace604ace --- /dev/null +++ b/grc/grc.conf.in @@ -0,0 +1,7 @@ +# This file contains system wide configuration data for GNU Radio. +# You may override any setting on a per-user basis by editing +# ~/.gnuradio/config.conf + +[grc] +global_blocks_path = @blocksdir@ +local_blocks_path = diff --git a/grc/grc_gnuradio/CMakeLists.txt b/grc/grc_gnuradio/CMakeLists.txt new file mode 100644 index 000000000..e992a60a3 --- /dev/null +++ b/grc/grc_gnuradio/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright 2011 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. + +######################################################################## +GR_PYTHON_INSTALL( + FILES __init__.py + DESTINATION ${GR_PYTHON_DIR}/grc_gnuradio + COMPONENT "grc" +) + +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" +) diff --git a/grc/grc_gnuradio/README b/grc/grc_gnuradio/README new file mode 100644 index 000000000..897eed65c --- /dev/null +++ b/grc/grc_gnuradio/README @@ -0,0 +1,11 @@ +This is the grc_gnuradio module. +It contains supplemental python modules that grc uses at runtime. +The supplemental modules are meant to mimic modules in gnuradio. +These will be phased-out as new functionaility is merged into gnuradio. + +The blk2s module wraps many blocks in blks2 and gives them streaming outputs. +Will be phased-out by new message passing implementations. +Other blks2 blocks will hopefully make their way into blks2impl. + +The wxgui module contains a top_block + wxgui frame. +Will be phased-out by gui.py in wxgui and a new top block template. diff --git a/grc/grc_gnuradio/__init__.py b/grc/grc_gnuradio/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/grc/grc_gnuradio/__init__.py @@ -0,0 +1 @@ + diff --git a/grc/grc_gnuradio/blks2/__init__.py b/grc/grc_gnuradio/blks2/__init__.py new file mode 100644 index 000000000..fde76f256 --- /dev/null +++ b/grc/grc_gnuradio/blks2/__init__.py @@ -0,0 +1,26 @@ +# Copyright 2008-2011 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 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 diff --git a/grc/grc_gnuradio/blks2/error_rate.py b/grc/grc_gnuradio/blks2/error_rate.py new file mode 100644 index 000000000..9b2df58ef --- /dev/null +++ b/grc/grc_gnuradio/blks2/error_rate.py @@ -0,0 +1,137 @@ +# Copyright 2008 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. +# + +default_win_size = 1000 + +from gnuradio import gr +import gnuradio.gr.gr_threading as _threading +import numpy + +#generate 1s counts array +_1s_counts = [sum([1&(i>>j) for j in range(8)]) for i in range(2**8)] + +class input_watcher(_threading.Thread): + """ + Read samples from the message queue and hand them to the callback. + """ + + def __init__(self, msgq, callback): + self._msgq = msgq + self._callback = callback + _threading.Thread.__init__(self) + self.setDaemon(1) + self.keep_running = True + self.start() + + def run(self): + r = '' + while True: + msg = self._msgq.delete_head() + itemsize = int(msg.arg1()) + nitems = int(msg.arg2()) + s = r + msg.to_string() + i = (nitems-nitems%2)*itemsize + r = s[i:] + s = s[:i] + samples = numpy.fromstring(s, numpy.int8) + self._callback(samples) + +class error_rate(gr.hier_block2): + """ + Sample the incoming data streams (byte) and calculate the bit or symbol error rate. + Write the running rate to the output data stream (float). + """ + + def __init__(self, type='BER', win_size=default_win_size, bits_per_symbol=2): + """ + Error rate constructor. + @param type a string 'BER' or 'SER' + @param win_size the number of samples to calculate over + @param bits_per_symbol the number of information bits per symbol (BER only) + """ + #init + gr.hier_block2.__init__( + self, 'error_rate', + gr.io_signature(2, 2, gr.sizeof_char), + gr.io_signature(1, 1, gr.sizeof_float), + ) + assert type in ('BER', 'SER') + self._max_samples = win_size + self._bits_per_symbol = bits_per_symbol + #setup message queue + msg_source = gr.message_source(gr.sizeof_float, 1) + self._msgq_source = msg_source.msgq() + msgq_sink = gr.msg_queue(2) + msg_sink = gr.message_sink(gr.sizeof_char, msgq_sink, False) #False -> blocking + inter = gr.interleave(gr.sizeof_char) + #start thread + self._num_errs = 0 + self._err_index = 0 + self._num_samps = 0 + self._err_array = numpy.zeros(self._max_samples, numpy.int8) + if type == 'BER': + input_watcher(msgq_sink, self._handler_ber) + elif type == 'SER': + input_watcher(msgq_sink, self._handler_ser) + #connect + self.connect(msg_source, self) + self.connect((self, 0), (inter, 0)) + self.connect((self, 1), (inter, 1)) + self.connect(inter, msg_sink) + + def _handler_ber(self, samples): + num = len(samples)/2 + arr = numpy.zeros(num, numpy.float32) + for i in range(num): + old_err = self._err_array[self._err_index] + #record error + self._err_array[self._err_index] = _1s_counts[samples[i*2] ^ samples[i*2 + 1]] + self._num_errs = self._num_errs + self._err_array[self._err_index] - old_err + #increment index + self._err_index = (self._err_index + 1)%self._max_samples + self._num_samps = min(self._num_samps + 1, self._max_samples) + #write sample + arr[i] = float(self._num_errs)/float(self._num_samps*self._bits_per_symbol) + #write message + msg = gr.message_from_string(arr.tostring(), 0, gr.sizeof_float, num) + self._msgq_source.insert_tail(msg) + + def _handler_ser(self, samples): + num = len(samples)/2 + arr = numpy.zeros(num, numpy.float32) + for i in range(num): + old_err = self._err_array[self._err_index] + #record error + ref = samples[i*2] + res = samples[i*2 + 1] + if ref == res: + self._err_array[self._err_index] = 0 + else: + self._err_array[self._err_index] = 1 + #update number of errors + self._num_errs = self._num_errs + self._err_array[self._err_index] - old_err + #increment index + self._err_index = (self._err_index + 1)%self._max_samples + self._num_samps = min(self._num_samps + 1, self._max_samples) + #write sample + arr[i] = float(self._num_errs)/float(self._num_samps) + #write message + msg = gr.message_from_string(arr.tostring(), 0, gr.sizeof_float, num) + self._msgq_source.insert_tail(msg) diff --git a/grc/grc_gnuradio/blks2/packet.py b/grc/grc_gnuradio/blks2/packet.py new file mode 100644 index 000000000..e39f55c84 --- /dev/null +++ b/grc/grc_gnuradio/blks2/packet.py @@ -0,0 +1,242 @@ +# Copyright 2008, 2009 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, digital +from gnuradio.digital import packet_utils +import gnuradio.gr.gr_threading as _threading + +##payload length in bytes +DEFAULT_PAYLOAD_LEN = 512 + +##how many messages in a queue +DEFAULT_MSGQ_LIMIT = 2 + +##threshold for unmaking packets +DEFAULT_THRESHOLD = 12 + +################################################## +## Options Class for OFDM +################################################## +class options(object): + def __init__(self, **kwargs): + for key, value in kwargs.iteritems(): setattr(self, key, value) + +################################################## +## Packet Encoder +################################################## +class _packet_encoder_thread(_threading.Thread): + + def __init__(self, msgq, payload_length, send): + self._msgq = msgq + self._payload_length = payload_length + self._send = send + _threading.Thread.__init__(self) + self.setDaemon(1) + self.keep_running = True + self.start() + + def run(self): + sample = '' #residual sample + while self.keep_running: + msg = self._msgq.delete_head() #blocking read of message queue + sample = sample + msg.to_string() #get the body of the msg as a string + while len(sample) >= self._payload_length: + payload = sample[:self._payload_length] + sample = sample[self._payload_length:] + self._send(payload) + +class packet_encoder(gr.hier_block2): + """ + Hierarchical block for wrapping packet-based modulators. + """ + + def __init__(self, samples_per_symbol, bits_per_symbol, access_code='', pad_for_usrp=True): + """ + packet_mod constructor. + @param samples_per_symbol number of samples per symbol + @param bits_per_symbol number of bits per symbol + @param access_code AKA sync vector + @param pad_for_usrp If true, packets are padded such that they end up a multiple of 128 samples + @param payload_length number of bytes in a data-stream slice + """ + #setup parameters + self._samples_per_symbol = samples_per_symbol + self._bits_per_symbol = bits_per_symbol + self._pad_for_usrp = pad_for_usrp + if not access_code: #get access code + access_code = packet_utils.default_access_code + if not packet_utils.is_1_0_string(access_code): + raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,) + self._access_code = access_code + self._pad_for_usrp = pad_for_usrp + #create blocks + msg_source = gr.message_source(gr.sizeof_char, DEFAULT_MSGQ_LIMIT) + self._msgq_out = msg_source.msgq() + #initialize hier2 + gr.hier_block2.__init__( + self, + "packet_encoder", + gr.io_signature(0, 0, 0), # Input signature + gr.io_signature(1, 1, gr.sizeof_char) # Output signature + ) + #connect + self.connect(msg_source, self) + + def send_pkt(self, payload): + """ + Wrap the payload in a packet and push onto the message queue. + @param payload string, data to send + """ + packet = packet_utils.make_packet( + payload, + self._samples_per_symbol, + self._bits_per_symbol, + self._access_code, + self._pad_for_usrp + ) + msg = gr.message_from_string(packet) + self._msgq_out.insert_tail(msg) + +################################################## +## Packet Decoder +################################################## +class _packet_decoder_thread(_threading.Thread): + + def __init__(self, msgq, callback): + _threading.Thread.__init__(self) + self.setDaemon(1) + self._msgq = msgq + self.callback = callback + self.keep_running = True + self.start() + + def run(self): + while self.keep_running: + msg = self._msgq.delete_head() + ok, payload = packet_utils.unmake_packet(msg.to_string(), int(msg.arg1())) + if self.callback: + self.callback(ok, payload) + +class packet_decoder(gr.hier_block2): + """ + Hierarchical block for wrapping packet-based demodulators. + """ + + def __init__(self, access_code='', threshold=-1, callback=None): + """ + packet_demod constructor. + @param access_code AKA sync vector + @param threshold detect access_code with up to threshold bits wrong (0 -> use default) + @param callback a function of args: ok, payload + """ + #access code + if not access_code: #get access code + access_code = packet_utils.default_access_code + if not packet_utils.is_1_0_string(access_code): + raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,) + self._access_code = access_code + #threshold + if threshold < 0: threshold = DEFAULT_THRESHOLD + self._threshold = threshold + #blocks + msgq = gr.msg_queue(DEFAULT_MSGQ_LIMIT) #holds packets from the PHY + correlator = digital.correlate_access_code_bb(self._access_code, self._threshold) + framer_sink = gr.framer_sink_1(msgq) + #initialize hier2 + gr.hier_block2.__init__( + self, + "packet_decoder", + gr.io_signature(1, 1, gr.sizeof_char), # Input signature + gr.io_signature(0, 0, 0) # Output signature + ) + #connect + self.connect(self, correlator, framer_sink) + #start thread + _packet_decoder_thread(msgq, callback) + +################################################## +## Packet Mod for OFDM Mod and Packet Encoder +################################################## +class packet_mod_base(gr.hier_block2): + """ + Hierarchical block for wrapping packet source block. + """ + + def __init__(self, packet_source=None, payload_length=0): + if not payload_length: #get payload length + payload_length = DEFAULT_PAYLOAD_LEN + if payload_length%self._item_size_in != 0: #verify that packet length is a multiple of the stream size + raise ValueError, 'The payload length: "%d" is not a mutiple of the stream size: "%d".'%(payload_length, self._item_size_in) + #initialize hier2 + gr.hier_block2.__init__( + self, + "ofdm_mod", + gr.io_signature(1, 1, self._item_size_in), # Input signature + gr.io_signature(1, 1, packet_source._hb.output_signature().sizeof_stream_item(0)) # Output signature + ) + #create blocks + msgq = gr.msg_queue(DEFAULT_MSGQ_LIMIT) + msg_sink = gr.message_sink(self._item_size_in, msgq, False) #False -> blocking + #connect + self.connect(self, msg_sink) + self.connect(packet_source, self) + #start thread + _packet_encoder_thread(msgq, payload_length, packet_source.send_pkt) + +class packet_mod_b(packet_mod_base): _item_size_in = gr.sizeof_char +class packet_mod_s(packet_mod_base): _item_size_in = gr.sizeof_short +class packet_mod_i(packet_mod_base): _item_size_in = gr.sizeof_int +class packet_mod_f(packet_mod_base): _item_size_in = gr.sizeof_float +class packet_mod_c(packet_mod_base): _item_size_in = gr.sizeof_gr_complex + +################################################## +## Packet Demod for OFDM Demod and Packet Decoder +################################################## +class packet_demod_base(gr.hier_block2): + """ + Hierarchical block for wrapping packet sink block. + """ + + def __init__(self, packet_sink=None): + #initialize hier2 + gr.hier_block2.__init__( + self, + "ofdm_mod", + gr.io_signature(1, 1, packet_sink._hb.input_signature().sizeof_stream_item(0)), # Input signature + gr.io_signature(1, 1, self._item_size_out) # Output signature + ) + #create blocks + msg_source = gr.message_source(self._item_size_out, DEFAULT_MSGQ_LIMIT) + self._msgq_out = msg_source.msgq() + #connect + self.connect(self, packet_sink) + self.connect(msg_source, self) + if packet_sink._hb.output_signature().sizeof_stream_item(0): + self.connect(packet_sink, gr.null_sink(packet_sink._hb.output_signature().sizeof_stream_item(0))) + + def recv_pkt(self, ok, payload): + msg = gr.message_from_string(payload, 0, self._item_size_out, len(payload)/self._item_size_out) + if ok: self._msgq_out.insert_tail(msg) + +class packet_demod_b(packet_demod_base): _item_size_out = gr.sizeof_char +class packet_demod_s(packet_demod_base): _item_size_out = gr.sizeof_short +class packet_demod_i(packet_demod_base): _item_size_out = gr.sizeof_int +class packet_demod_f(packet_demod_base): _item_size_out = gr.sizeof_float +class packet_demod_c(packet_demod_base): _item_size_out = gr.sizeof_gr_complex diff --git a/grc/grc_gnuradio/blks2/selector.py b/grc/grc_gnuradio/blks2/selector.py new file mode 100644 index 000000000..f0f6d5dd7 --- /dev/null +++ b/grc/grc_gnuradio/blks2/selector.py @@ -0,0 +1,128 @@ +# +# Copyright 2008 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 + +class selector(gr.hier_block2): + """A hier2 block with N inputs and M outputs, where data is only forwarded through input n to output m.""" + def __init__(self, item_size, num_inputs, num_outputs, input_index, output_index): + """ + Selector constructor. + @param item_size the size of the gr data stream in bytes + @param num_inputs the number of inputs (integer) + @param num_outputs the number of outputs (integer) + @param input_index the index for the source data + @param output_index the index for the destination data + """ + gr.hier_block2.__init__( + self, 'selector', + gr.io_signature(num_inputs, num_inputs, item_size), + gr.io_signature(num_outputs, num_outputs, item_size), + ) + #terminator blocks for unused inputs and outputs + self.input_terminators = [gr.null_sink(item_size) for i in range(num_inputs)] + self.output_terminators = [gr.head(item_size, 0) for i in range(num_outputs)] + self.copy = gr.kludge_copy(item_size) + #connections + for i in range(num_inputs): self.connect((self, i), self.input_terminators[i]) + for i in range(num_outputs): self.connect(gr.null_source(item_size), self.output_terminators[i], (self, i)) + self.item_size = item_size + self.input_index = input_index + self.output_index = output_index + self.num_inputs = num_inputs + self.num_outputs = num_outputs + self._connect_current() + + def _indexes_valid(self): + """ + Are the input and output indexes within range of the number of inputs and outputs? + @return true if input index and output index are in range + """ + return self.input_index in range(self.num_inputs) and self.output_index in range(self.num_outputs) + + def _connect_current(self): + """If the input and output indexes are valid: + disconnect the blocks at the input and output index from their terminators, + and connect them to one another. Then connect the terminators to one another.""" + if self._indexes_valid(): + self.disconnect((self, self.input_index), self.input_terminators[self.input_index]) + self.disconnect(self.output_terminators[self.output_index], (self, self.output_index)) + self.connect((self, self.input_index), self.copy) + self.connect(self.copy, (self, self.output_index)) + self.connect(self.output_terminators[self.output_index], self.input_terminators[self.input_index]) + + def _disconnect_current(self): + """If the input and output indexes are valid: + disconnect the blocks at the input and output index from one another, + and the terminators at the input and output index from one another. + Reconnect the blocks to the terminators.""" + if self._indexes_valid(): + self.disconnect((self, self.input_index), self.copy) + self.disconnect(self.copy, (self, self.output_index)) + self.disconnect(self.output_terminators[self.output_index], self.input_terminators[self.input_index]) + self.connect((self, self.input_index), self.input_terminators[self.input_index]) + self.connect(self.output_terminators[self.output_index], (self, self.output_index)) + + def set_input_index(self, input_index): + """ + Change the block to the new input index if the index changed. + @param input_index the new input index + """ + if self.input_index != input_index: + self.lock() + self._disconnect_current() + self.input_index = input_index + self._connect_current() + self.unlock() + + def set_output_index(self, output_index): + """ + Change the block to the new output index if the index changed. + @param output_index the new output index + """ + if self.output_index != output_index: + self.lock() + self._disconnect_current() + self.output_index = output_index + self._connect_current() + self.unlock() + +class valve(selector): + """Wrapper for selector with 1 input and 1 output.""" + + def __init__(self, item_size, open): + """ + Constructor for valve. + @param item_size the size of the gr data stream in bytes + @param open true if initial valve state is open + """ + if open: output_index = -1 + else: output_index = 0 + selector.__init__(self, item_size, 1, 1, 0, output_index) + + def set_open(self, open): + """ + Callback to set open state. + @param open true to set valve state to open + """ + if open: output_index = -1 + else: output_index = 0 + self.set_output_index(output_index) diff --git a/grc/grc_gnuradio/blks2/tcp.py b/grc/grc_gnuradio/blks2/tcp.py new file mode 100644 index 000000000..c6739b711 --- /dev/null +++ b/grc/grc_gnuradio/blks2/tcp.py @@ -0,0 +1,66 @@ +# +# Copyright 2009 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 +import socket +import os + +def _get_sock_fd(addr, port, server): + """ + Get the file descriptor for the socket. + As a client, block on connect, dup the socket descriptor. + As a server, block on accept, dup the client descriptor. + @param addr the ip address string + @param port the tcp port number + @param server true for server mode, false for client mode + @return the file descriptor number + """ + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + if server: + sock.bind((addr, port)) + sock.listen(1) + clientsock, address = sock.accept() + return os.dup(clientsock.fileno()) + else: + sock.connect((addr, port)) + return os.dup(sock.fileno()) + +class tcp_source(gr.hier_block2): + def __init__(self, itemsize, addr, port, server=True): + #init hier block + gr.hier_block2.__init__( + self, 'tcp_source', + gr.io_signature(0, 0, 0), + gr.io_signature(1, 1, itemsize), + ) + fd = _get_sock_fd(addr, port, server) + self.connect(gr.file_descriptor_source(itemsize, fd), self) + +class tcp_sink(gr.hier_block2): + def __init__(self, itemsize, addr, port, server=False): + #init hier block + gr.hier_block2.__init__( + self, 'tcp_sink', + gr.io_signature(1, 1, itemsize), + gr.io_signature(0, 0, 0), + ) + fd = _get_sock_fd(addr, port, server) + self.connect(self, gr.file_descriptor_sink(itemsize, fd)) diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py new file mode 100644 index 000000000..9fb5e4ebf --- /dev/null +++ b/grc/gui/ActionHandler.py @@ -0,0 +1,530 @@ +""" +Copyright 2007-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 signal +from Constants import IMAGE_FILE_EXTENSION +import Actions +import pygtk +pygtk.require('2.0') +import gtk +import gobject +import Preferences +from threading import Thread +import Messages +from .. base import ParseXML +from MainWindow import MainWindow +from PropsDialog import PropsDialog +import Dialogs +from FileDialogs import OpenFlowGraphFileDialog, SaveFlowGraphFileDialog, SaveImageFileDialog + +gobject.threads_init() + +class ActionHandler: + """ + The action handler will setup all the major window components, + and handle button presses and flow graph operations from the GUI. + """ + + def __init__(self, file_paths, platform): + """ + ActionHandler constructor. + Create the main window, setup the message handler, import the preferences, + and connect all of the action handlers. Finally, enter the gtk main loop and block. + @param file_paths a list of flow graph file passed from command line + @param platform platform module + """ + self.clipboard = None + for action in Actions.get_all_actions(): action.connect('activate', self._handle_action) + #setup the main window + self.platform = platform; + self.main_window = MainWindow(platform) + self.main_window.connect('delete-event', self._quit) + self.main_window.connect('key-press-event', self._handle_key_press) + self.get_page = self.main_window.get_page + self.get_flow_graph = self.main_window.get_flow_graph + self.get_focus_flag = self.main_window.get_focus_flag + #setup the messages + Messages.register_messenger(self.main_window.add_report_line) + Messages.send_init(platform) + #initialize + self.init_file_paths = file_paths + Actions.APPLICATION_INITIALIZE() + #enter the mainloop + gtk.main() + + def _handle_key_press(self, widget, event): + """ + Handle key presses from the keyboard and translate key combinations into actions. + This key press handler is called prior to the gtk key press handler. + This handler bypasses built in accelerator key handling when in focus because + * some keys are ignored by the accelerators like the direction keys, + * some keys are not registered to any accelerators but are still used. + When not in focus, gtk and the accelerators handle the the key press. + @return false to let gtk handle the key action + """ + if not self.get_focus_flag(): return False + return Actions.handle_key_press(event) + + def _quit(self, window, event): + """ + Handle the delete event from the main window. + Generated by pressing X to close, alt+f4, or right click+close. + This method in turns calls the state handler to quit. + @return true + """ + Actions.APPLICATION_QUIT() + return True + + def _handle_action(self, action): + #print action + ################################################## + # Initalize/Quit + ################################################## + if action == Actions.APPLICATION_INITIALIZE: + for action in Actions.get_all_actions(): action.set_sensitive(False) #set all actions disabled + #enable a select few actions + for action in ( + Actions.APPLICATION_QUIT, Actions.FLOW_GRAPH_NEW, + Actions.FLOW_GRAPH_OPEN, Actions.FLOW_GRAPH_SAVE_AS, + Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY, + Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY, + Actions.TYPES_WINDOW_DISPLAY, + ): action.set_sensitive(True) + if not self.init_file_paths: + self.init_file_paths = Preferences.files_open() + if not self.init_file_paths: self.init_file_paths = [''] + for file_path in self.init_file_paths: + if file_path: self.main_window.new_page(file_path) #load pages from file paths + if Preferences.file_open() in self.init_file_paths: + self.main_window.new_page(Preferences.file_open(), show=True) + if not self.get_page(): self.main_window.new_page() #ensure that at least a blank page exists + elif action == Actions.APPLICATION_QUIT: + if self.main_window.close_pages(): + gtk.main_quit() + exit(0) + ################################################## + # Selections + ################################################## + elif action == Actions.ELEMENT_SELECT: + pass #do nothing, update routines below + elif action == Actions.NOTHING_SELECT: + self.get_flow_graph().unselect() + ################################################## + # Enable/Disable + ################################################## + elif action == Actions.BLOCK_ENABLE: + if self.get_flow_graph().enable_selected(True): + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) + elif action == Actions.BLOCK_DISABLE: + if self.get_flow_graph().enable_selected(False): + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) + ################################################## + # Cut/Copy/Paste + ################################################## + elif action == Actions.BLOCK_CUT: + Actions.BLOCK_COPY() + Actions.ELEMENT_DELETE() + elif action == Actions.BLOCK_COPY: + self.clipboard = self.get_flow_graph().copy_to_clipboard() + elif action == Actions.BLOCK_PASTE: + if self.clipboard: + self.get_flow_graph().paste_from_clipboard(self.clipboard) + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) + ################################################## + # Create heir block + ################################################## + elif action == Actions.BLOCK_CREATE_HIER: + + # keeping track of coordinates for pasting later + coords = self.get_flow_graph().get_selected_blocks()[0].get_coordinate() + x,y = coords + x_min = x + y_min = y + + pads = []; + params = []; + + # Save the state of the leaf blocks + for block in self.get_flow_graph().get_selected_blocks(): + + # Check for string variables within the blocks + for param in block.get_params(): + for variable in self.get_flow_graph().get_variables(): + # If a block parameter exists that is a variable, create a parameter for it + if param.get_value() == variable.get_id(): + params.append(param.get_value()) + for flow_param in self.get_flow_graph().get_parameters(): + # If a block parameter exists that is a parameter, create a parameter for it + if param.get_value() == flow_param.get_id(): + params.append(param.get_value()) + + + # keep track of x,y mins for pasting later + (x,y) = block.get_coordinate() + if x < x_min: + x_min = x + if y < y_min: + y_min = y + + for connection in block.get_connections(): + + # Get id of connected blocks + source_id = connection.get_source().get_parent().get_id() + sink_id = connection.get_sink().get_parent().get_id() + + # If connected block is not in the list of selected blocks create a pad for it + if self.get_flow_graph().get_block(source_id) not in self.get_flow_graph().get_selected_blocks(): + pads.append({'key': connection.get_sink().get_key(), 'coord': connection.get_source().get_coordinate(), 'block_id' : block.get_id(), 'direction': 'source'}) + + if self.get_flow_graph().get_block(sink_id) not in self.get_flow_graph().get_selected_blocks(): + pads.append({'key': connection.get_source().get_key(), 'coord': connection.get_sink().get_coordinate(), 'block_id' : block.get_id(), 'direction': 'sink'}) + + + # Copy the selected blocks and paste them into a new page + # then move the flowgraph to a reasonable position + Actions.BLOCK_COPY() + self.main_window.new_page() + Actions.BLOCK_PASTE() + coords = (x_min,y_min) + self.get_flow_graph().move_selected(coords) + + + # Set flow graph to heir block type + top_block = self.get_flow_graph().get_block("top_block") + top_block.get_param('generate_options').set_value('hb') + + # this needs to be a unique name + top_block.get_param('id').set_value('new_heir') + + # Remove the default samp_rate variable block that is created + remove_me = self.get_flow_graph().get_block("samp_rate") + self.get_flow_graph().remove_element(remove_me) + + + # Add the param blocks along the top of the window + x_pos = 150 + for param in params: + param_id = self.get_flow_graph().add_new_block('parameter',(x_pos,10)) + param_block = self.get_flow_graph().get_block(param_id) + param_block.get_param('id').set_value(param) + x_pos = x_pos + 100 + + for pad in pads: + # Add the pad sources and sinks within the new heir block + if pad['direction'] == 'sink': + + # Add new PAD_SINK block to the canvas + pad_id = self.get_flow_graph().add_new_block('pad_sink', pad['coord']) + + # setup the references to the sink and source + pad_block = self.get_flow_graph().get_block(pad_id) + pad_sink = pad_block.get_sinks()[0] + + source_block = self.get_flow_graph().get_block(pad['block_id']) + source = source_block.get_source(pad['key']) + + # Ensure the port types match + while pad_sink.get_type() != source.get_type(): + + # Special case for some blocks that have non-standard type names, e.g. uhd + if pad_sink.get_type() == 'complex' and source.get_type() == 'fc32': + break; + pad_block.type_controller_modify(1) + + # Connect the pad to the proper sinks + new_connection = self.get_flow_graph().connect(source,pad_sink) + + elif pad['direction'] == 'source': + pad_id = self.get_flow_graph().add_new_block('pad_source', pad['coord']) + + # setup the references to the sink and source + pad_block = self.get_flow_graph().get_block(pad_id) + pad_source = pad_block.get_sources()[0] + + sink_block = self.get_flow_graph().get_block(pad['block_id']) + sink = sink_block.get_sink(pad['key']) + + # Ensure the port types match + while sink.get_type() != pad_source.get_type(): + # Special case for some blocks that have non-standard type names, e.g. uhd + if pad_source.get_type() == 'complex' and sink.get_type() == 'fc32': + break; + pad_block.type_controller_modify(1) + + # Connect the pad to the proper sinks + new_connection = self.get_flow_graph().connect(pad_source,sink) + + # update the new heir block flow graph + self.get_flow_graph().update() + + + ################################################## + # Move/Rotate/Delete/Create + ################################################## + elif action == Actions.BLOCK_MOVE: + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) + elif action == Actions.BLOCK_ROTATE_CCW: + if self.get_flow_graph().rotate_selected(90): + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) + elif action == Actions.BLOCK_ROTATE_CW: + if self.get_flow_graph().rotate_selected(-90): + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) + elif action == Actions.ELEMENT_DELETE: + if self.get_flow_graph().remove_selected(): + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + Actions.NOTHING_SELECT() + self.get_page().set_saved(False) + elif action == Actions.ELEMENT_CREATE: + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + Actions.NOTHING_SELECT() + self.get_page().set_saved(False) + elif action == Actions.BLOCK_INC_TYPE: + if self.get_flow_graph().type_controller_modify_selected(1): + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) + elif action == Actions.BLOCK_DEC_TYPE: + if self.get_flow_graph().type_controller_modify_selected(-1): + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) + elif action == Actions.PORT_CONTROLLER_INC: + if self.get_flow_graph().port_controller_modify_selected(1): + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) + elif action == Actions.PORT_CONTROLLER_DEC: + if self.get_flow_graph().port_controller_modify_selected(-1): + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) + ################################################## + # Window stuff + ################################################## + elif action == Actions.ABOUT_WINDOW_DISPLAY: + Dialogs.AboutDialog(self.get_flow_graph().get_parent()) + elif action == Actions.HELP_WINDOW_DISPLAY: + Dialogs.HelpDialog() + elif action == Actions.TYPES_WINDOW_DISPLAY: + Dialogs.TypesDialog(self.get_flow_graph().get_parent()) + elif action == Actions.ERRORS_WINDOW_DISPLAY: + Dialogs.ErrorsDialog(self.get_flow_graph()) + ################################################## + # Param Modifications + ################################################## + elif action == Actions.BLOCK_PARAM_MODIFY: + selected_block = self.get_flow_graph().get_selected_block() + if selected_block: + if PropsDialog(selected_block).run(): + #save the new state + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) + else: + #restore the current state + n = self.get_page().get_state_cache().get_current_state() + self.get_flow_graph().import_data(n) + self.get_flow_graph().update() + ################################################## + # Undo/Redo + ################################################## + elif action == Actions.FLOW_GRAPH_UNDO: + n = self.get_page().get_state_cache().get_prev_state() + if n: + self.get_flow_graph().unselect() + self.get_flow_graph().import_data(n) + self.get_flow_graph().update() + self.get_page().set_saved(False) + elif action == Actions.FLOW_GRAPH_REDO: + n = self.get_page().get_state_cache().get_next_state() + if n: + self.get_flow_graph().unselect() + self.get_flow_graph().import_data(n) + self.get_flow_graph().update() + self.get_page().set_saved(False) + ################################################## + # New/Open/Save/Close + ################################################## + elif action == Actions.FLOW_GRAPH_NEW: + self.main_window.new_page() + elif action == Actions.FLOW_GRAPH_OPEN: + file_paths = OpenFlowGraphFileDialog(self.get_page().get_file_path()).run() + if file_paths: #open a new page for each file, show only the first + for i,file_path in enumerate(file_paths): + self.main_window.new_page(file_path, show=(i==0)) + elif action == Actions.FLOW_GRAPH_CLOSE: + self.main_window.close_page() + elif action == Actions.FLOW_GRAPH_SAVE: + #read-only or undefined file path, do save-as + if self.get_page().get_read_only() or not self.get_page().get_file_path(): + Actions.FLOW_GRAPH_SAVE_AS() + #otherwise try to save + else: + try: + ParseXML.to_file(self.get_flow_graph().export_data(), self.get_page().get_file_path()) + self.get_flow_graph().grc_file_path = self.get_page().get_file_path() + self.get_page().set_saved(True) + except IOError: + Messages.send_fail_save(self.get_page().get_file_path()) + self.get_page().set_saved(False) + elif action == Actions.FLOW_GRAPH_SAVE_AS: + file_path = SaveFlowGraphFileDialog(self.get_page().get_file_path()).run() + if file_path is not None: + self.get_page().set_file_path(file_path) + Actions.FLOW_GRAPH_SAVE() + elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE: + file_path = SaveImageFileDialog(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:]) + ################################################## + # Gen/Exec/Stop + ################################################## + elif action == Actions.FLOW_GRAPH_GEN: + if not self.get_page().get_proc(): + if not self.get_page().get_saved() or not self.get_page().get_file_path(): + Actions.FLOW_GRAPH_SAVE() #only save if file path missing or not saved + if self.get_page().get_saved() and self.get_page().get_file_path(): + generator = self.get_page().get_generator() + try: + Messages.send_start_gen(generator.get_file_path()) + generator.write() + except Exception,e: Messages.send_fail_gen(e) + else: self.generator = None + elif action == Actions.FLOW_GRAPH_EXEC: + if not self.get_page().get_proc(): + Actions.FLOW_GRAPH_GEN() + if self.get_page().get_saved() and self.get_page().get_file_path(): + ExecFlowGraphThread(self) + elif action == Actions.FLOW_GRAPH_KILL: + if self.get_page().get_proc(): + try: self.get_page().get_proc().kill() + except: print "could not kill process: %d"%self.get_page().get_proc().pid + elif action == Actions.PAGE_CHANGE: #pass and run the global actions + pass + elif action == Actions.RELOAD_BLOCKS: + self.platform.loadblocks() + self.main_window.btwin.clear(); + self.platform.load_block_tree(self.main_window.btwin); + elif action == Actions.OPEN_HIER: + bn = []; + for b in self.get_flow_graph().get_selected_blocks(): + if b._grc_source: + self.main_window.new_page(b._grc_source, show=True); + else: print '!!! Action "%s" not handled !!!'%action + ################################################## + # Global Actions for all States + ################################################## + #update general buttons + Actions.ERRORS_WINDOW_DISPLAY.set_sensitive(not self.get_flow_graph().is_valid()) + Actions.ELEMENT_DELETE.set_sensitive(bool(self.get_flow_graph().get_selected_elements())) + Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(self.get_flow_graph().get_selected_block())) + Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_ROTATE_CW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + #update cut/copy/paste + Actions.BLOCK_CUT.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_COPY.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_PASTE.set_sensitive(bool(self.clipboard)) + #update enable/disable + Actions.BLOCK_ENABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_DISABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_CREATE_HIER.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.OPEN_HIER.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.RELOAD_BLOCKS.set_sensitive(True) + #set the exec and stop buttons + self.update_exec_stop() + #saved status + Actions.FLOW_GRAPH_SAVE.set_sensitive(not self.get_page().get_saved()) + 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') + if self.get_flow_graph().get_size() != tuple(new_size): + self.get_flow_graph().set_size(*new_size) + except: pass + #draw the flow graph + self.get_flow_graph().update_selected() + self.get_flow_graph().queue_draw() + return True #action was handled + + def update_exec_stop(self): + """ + Update the exec and stop buttons. + Lock and unlock the mutex for race conditions with exec flow graph threads. + """ + sensitive = self.get_flow_graph().is_valid() and not self.get_page().get_proc() + 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() != 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. + @param 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() + Messages.send_start_exec(self.page.get_generator().get_file_path()) + #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) + gobject.idle_add(self.done) + + def done(self): + """Perform end of execution tasks.""" + Messages.send_end_exec() + self.page.set_proc(None) + self.update_exec_stop() diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py new file mode 100644 index 000000000..fab026c5e --- /dev/null +++ b/grc/gui/Actions.py @@ -0,0 +1,291 @@ +""" +Copyright 2007-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 pygtk +pygtk.require('2.0') +import gtk + +NO_MODS_MASK = 0 + +######################################################################## +# Actions API +######################################################################## +_actions_keypress_dict = dict() +_keymap = gtk.gdk.keymap_get_default() +_used_mods_mask = NO_MODS_MASK +def handle_key_press(event): + """ + Call the action associated with the key press event. + Both the key value and the mask must have a match. + @param event a gtk key press event + @return true if handled + """ + _used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for keyval, mod_mask in _actions_keypress_dict], NO_MODS_MASK) + #extract the key value and the consumed modifiers + keyval, egroup, level, consumed = _keymap.translate_keyboard_state( + event.hardware_keycode, event.state, event.group) + #get the modifier mask and ignore irrelevant modifiers + mod_mask = event.state & ~consumed & _used_mods_mask + #look up the keypress and call the action + try: _actions_keypress_dict[(keyval, mod_mask)]() + except KeyError: return False #not handled + return True #handled here + +_all_actions_list = list() +def get_all_actions(): return _all_actions_list + +_accel_group = gtk.AccelGroup() +def get_accel_group(): return _accel_group + +class Action(gtk.Action): + """ + A custom Action class based on gtk.Action. + Pass additional arguments such as keypresses. + Register actions and keypresses with this module. + """ + + def __init__(self, keypresses=(), name=None, label=None, tooltip=None, stock_id=None): + """ + Create a new Action instance. + @param key_presses a tuple of (keyval1, mod_mask1, keyval2, mod_mask2, ...) + @param the regular gtk.Action parameters (defaults to None) + """ + if name is None: name = label + gtk.Action.__init__(self, + name=name, label=label, + tooltip=tooltip, stock_id=stock_id, + ) + #register this action + _all_actions_list.append(self) + for i in range(len(keypresses)/2): + keyval, mod_mask = keypresses[i*2:(i+1)*2] + #register this keypress + if _actions_keypress_dict.has_key((keyval, mod_mask)): + raise KeyError('keyval/mod_mask pair already registered "%s"'%str((keyval, mod_mask))) + _actions_keypress_dict[(keyval, mod_mask)] = self + #set the accelerator group, and accelerator path + #register the key name and mod mask with the accelerator path + if label is None: continue #dont register accel + accel_path = '<main>/'+self.get_name() + self.set_accel_group(get_accel_group()) + self.set_accel_path(accel_path) + gtk.accel_map_add_entry(accel_path, keyval, mod_mask) + + def __str__(self): + """ + The string representation should be the name of the action id. + Try to find the action id for this action by searching this module. + """ + try: + import Actions + return filter(lambda attr: getattr(Actions, attr) == self, dir(Actions))[0] + except: return self.get_name() + + def __repr__(self): return str(self) + + def __call__(self): + """ + Emit the activate signal when called with (). + """ + self.emit('activate') + +######################################################################## +# Actions +######################################################################## +PAGE_CHANGE = Action() +FLOW_GRAPH_NEW = Action( + label='_New', + tooltip='Create a new flow graph', + stock_id=gtk.STOCK_NEW, + keypresses=(gtk.keysyms.n, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_OPEN = Action( + label='_Open', + tooltip='Open an existing flow graph', + stock_id=gtk.STOCK_OPEN, + keypresses=(gtk.keysyms.o, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_SAVE = Action( + label='_Save', + tooltip='Save the current flow graph', + stock_id=gtk.STOCK_SAVE, + keypresses=(gtk.keysyms.s, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_SAVE_AS = Action( + label='Save _As', + tooltip='Save the current flow graph as...', + stock_id=gtk.STOCK_SAVE_AS, + keypresses=(gtk.keysyms.s, gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK), +) +FLOW_GRAPH_CLOSE = Action( + label='_Close', + tooltip='Close the current flow graph', + stock_id=gtk.STOCK_CLOSE, + keypresses=(gtk.keysyms.w, gtk.gdk.CONTROL_MASK), +) +APPLICATION_INITIALIZE = Action() +APPLICATION_QUIT = Action( + label='_Quit', + tooltip='Quit program', + stock_id=gtk.STOCK_QUIT, + keypresses=(gtk.keysyms.q, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_UNDO = Action( + label='_Undo', + tooltip='Undo a change to the flow graph', + stock_id=gtk.STOCK_UNDO, + keypresses=(gtk.keysyms.z, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_REDO = Action( + label='_Redo', + tooltip='Redo a change to the flow graph', + stock_id=gtk.STOCK_REDO, + keypresses=(gtk.keysyms.y, gtk.gdk.CONTROL_MASK), +) +NOTHING_SELECT = Action() +ELEMENT_SELECT = Action() +ELEMENT_CREATE = Action() +ELEMENT_DELETE = Action( + label='_Delete', + tooltip='Delete the selected blocks', + stock_id=gtk.STOCK_DELETE, + keypresses=(gtk.keysyms.Delete, NO_MODS_MASK), +) +BLOCK_MOVE = Action() +BLOCK_ROTATE_CCW = Action( + label='Rotate Counterclockwise', + tooltip='Rotate the selected blocks 90 degrees to the left', + stock_id=gtk.STOCK_GO_BACK, + keypresses=(gtk.keysyms.Left, NO_MODS_MASK), +) +BLOCK_ROTATE_CW = Action( + label='Rotate Clockwise', + tooltip='Rotate the selected blocks 90 degrees to the right', + stock_id=gtk.STOCK_GO_FORWARD, + keypresses=(gtk.keysyms.Right, NO_MODS_MASK), +) +BLOCK_PARAM_MODIFY = Action( + label='_Properties', + tooltip='Modify params for the selected block', + stock_id=gtk.STOCK_PROPERTIES, + keypresses=(gtk.keysyms.Return, NO_MODS_MASK), +) +BLOCK_ENABLE = Action( + label='E_nable', + tooltip='Enable the selected blocks', + stock_id=gtk.STOCK_CONNECT, + keypresses=(gtk.keysyms.e, NO_MODS_MASK), +) +BLOCK_DISABLE = Action( + label='D_isable', + tooltip='Disable the selected blocks', + stock_id=gtk.STOCK_DISCONNECT, + keypresses=(gtk.keysyms.d, NO_MODS_MASK), +) +BLOCK_CREATE_HIER = Action( + label='C_reate Hier', + tooltip='Create hier block from selected blocks', + stock_id=gtk.STOCK_CONNECT, +# keypresses=(gtk.keysyms.c, NO_MODS_MASK), +) +BLOCK_CUT = Action( + label='Cu_t', + tooltip='Cut', + stock_id=gtk.STOCK_CUT, + keypresses=(gtk.keysyms.x, gtk.gdk.CONTROL_MASK), +) +BLOCK_COPY = Action( + label='_Copy', + tooltip='Copy', + stock_id=gtk.STOCK_COPY, + keypresses=(gtk.keysyms.c, gtk.gdk.CONTROL_MASK), +) +BLOCK_PASTE = Action( + label='_Paste', + tooltip='Paste', + stock_id=gtk.STOCK_PASTE, + keypresses=(gtk.keysyms.v, gtk.gdk.CONTROL_MASK), +) +ERRORS_WINDOW_DISPLAY = Action( + label='_Errors', + tooltip='View flow graph errors', + stock_id=gtk.STOCK_DIALOG_ERROR, +) +ABOUT_WINDOW_DISPLAY = Action( + label='_About', + tooltip='About this program', + stock_id=gtk.STOCK_ABOUT, +) +HELP_WINDOW_DISPLAY = Action( + label='_Help', + tooltip='Usage tips', + stock_id=gtk.STOCK_HELP, + keypresses=(gtk.keysyms.F1, NO_MODS_MASK), +) +TYPES_WINDOW_DISPLAY = Action( + label='_Types', + tooltip='Types color mapping', + stock_id=gtk.STOCK_DIALOG_INFO, +) +FLOW_GRAPH_GEN = Action( + label='_Generate', + tooltip='Generate the flow graph', + stock_id=gtk.STOCK_CONVERT, + keypresses=(gtk.keysyms.F5, NO_MODS_MASK), +) +FLOW_GRAPH_EXEC = Action( + label='_Execute', + tooltip='Execute the flow graph', + stock_id=gtk.STOCK_EXECUTE, + keypresses=(gtk.keysyms.F6, NO_MODS_MASK), +) +FLOW_GRAPH_KILL = Action( + label='_Kill', + tooltip='Kill the flow graph', + stock_id=gtk.STOCK_STOP, + keypresses=(gtk.keysyms.F7, NO_MODS_MASK), +) +FLOW_GRAPH_SCREEN_CAPTURE = Action( + label='S_creen Capture', + tooltip='Create a screen capture of the flow graph', + stock_id=gtk.STOCK_PRINT, + keypresses=(gtk.keysyms.Print, NO_MODS_MASK), +) +PORT_CONTROLLER_DEC = Action( + keypresses=(gtk.keysyms.minus, NO_MODS_MASK, gtk.keysyms.KP_Subtract, NO_MODS_MASK), +) +PORT_CONTROLLER_INC = Action( + keypresses=(gtk.keysyms.plus, NO_MODS_MASK, gtk.keysyms.KP_Add, NO_MODS_MASK), +) +BLOCK_INC_TYPE = Action( + keypresses=(gtk.keysyms.Down, NO_MODS_MASK), +) +BLOCK_DEC_TYPE = Action( + keypresses=(gtk.keysyms.Up, NO_MODS_MASK), +) +RELOAD_BLOCKS = Action( + label='Reload _Blocks', + tooltip='Reload Blocks', + stock_id=gtk.STOCK_REFRESH +) +OPEN_HIER = Action( + label='Open H_ier', + tooltip='Open the source of the selected hierarchical block', + stock_id=gtk.STOCK_JUMP_TO, +) diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py new file mode 100644 index 000000000..d95d23f1f --- /dev/null +++ b/grc/gui/Bars.py @@ -0,0 +1,143 @@ +""" +Copyright 2007, 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 Actions +import pygtk +pygtk.require('2.0') +import gtk + +##The list of actions for the toolbar. +TOOLBAR_LIST = ( + Actions.FLOW_GRAPH_NEW, + Actions.FLOW_GRAPH_OPEN, + Actions.FLOW_GRAPH_SAVE, + Actions.FLOW_GRAPH_CLOSE, + None, + Actions.FLOW_GRAPH_SCREEN_CAPTURE, + None, + Actions.BLOCK_CUT, + Actions.BLOCK_COPY, + Actions.BLOCK_PASTE, + Actions.ELEMENT_DELETE, + None, + Actions.FLOW_GRAPH_UNDO, + Actions.FLOW_GRAPH_REDO, + None, + Actions.ERRORS_WINDOW_DISPLAY, + Actions.FLOW_GRAPH_GEN, + Actions.FLOW_GRAPH_EXEC, + Actions.FLOW_GRAPH_KILL, + None, + Actions.BLOCK_ROTATE_CCW, + Actions.BLOCK_ROTATE_CW, + None, + Actions.BLOCK_ENABLE, + Actions.BLOCK_DISABLE, + None, + Actions.RELOAD_BLOCKS, + Actions.OPEN_HIER, +) + +##The list of actions and categories for the menu bar. +MENU_BAR_LIST = ( + (gtk.Action('File', '_File', None, None), [ + Actions.FLOW_GRAPH_NEW, + Actions.FLOW_GRAPH_OPEN, + None, + Actions.FLOW_GRAPH_SAVE, + Actions.FLOW_GRAPH_SAVE_AS, + None, + Actions.FLOW_GRAPH_SCREEN_CAPTURE, + None, + Actions.FLOW_GRAPH_CLOSE, + Actions.APPLICATION_QUIT, + ]), + (gtk.Action('Edit', '_Edit', None, None), [ + Actions.FLOW_GRAPH_UNDO, + Actions.FLOW_GRAPH_REDO, + None, + Actions.BLOCK_CUT, + Actions.BLOCK_COPY, + Actions.BLOCK_PASTE, + Actions.ELEMENT_DELETE, + None, + Actions.BLOCK_ROTATE_CCW, + Actions.BLOCK_ROTATE_CW, + None, + Actions.BLOCK_ENABLE, + Actions.BLOCK_DISABLE, + None, + Actions.BLOCK_PARAM_MODIFY, + ]), + (gtk.Action('View', '_View', None, None), [ + Actions.ERRORS_WINDOW_DISPLAY, + ]), + (gtk.Action('Build', '_Build', None, None), [ + Actions.FLOW_GRAPH_GEN, + Actions.FLOW_GRAPH_EXEC, + Actions.FLOW_GRAPH_KILL, + ]), + (gtk.Action('Help', '_Help', None, None), [ + Actions.HELP_WINDOW_DISPLAY, + Actions.TYPES_WINDOW_DISPLAY, + None, + Actions.ABOUT_WINDOW_DISPLAY, + ]), +) + +class Toolbar(gtk.Toolbar): + """The gtk toolbar with actions added from the toolbar list.""" + + def __init__(self): + """ + Parse the list of action names in the toolbar list. + Look up the action for each name in the action list and add it to the toolbar. + """ + gtk.Toolbar.__init__(self) + self.set_style(gtk.TOOLBAR_ICONS) + for action in TOOLBAR_LIST: + if action: #add a tool item + self.add(action.create_tool_item()) + #this reset of the tooltip property is required (after creating the tool item) for the tooltip to show + action.set_property('tooltip', action.get_property('tooltip')) + else: self.add(gtk.SeparatorToolItem()) + +class MenuBar(gtk.MenuBar): + """The gtk menu bar with actions added from the menu bar list.""" + + def __init__(self): + """ + Parse the list of submenus from the menubar list. + For each submenu, get a list of action names. + Look up the action for each name in the action list and add it to the submenu. + Add the submenu to the menu bar. + """ + gtk.MenuBar.__init__(self) + for main_action, actions in MENU_BAR_LIST: + #create the main menu item + main_menu_item = main_action.create_menu_item() + self.append(main_menu_item) + #create the menu + main_menu = gtk.Menu() + main_menu_item.set_submenu(main_menu) + for action in actions: + if action: #append a menu item + main_menu.append(action.create_menu_item()) + else: main_menu.append(gtk.SeparatorMenuItem()) + main_menu.show_all() #this show all is required for the separators to show diff --git a/grc/gui/Block.py b/grc/gui/Block.py new file mode 100644 index 000000000..27143e070 --- /dev/null +++ b/grc/gui/Block.py @@ -0,0 +1,201 @@ +""" +Copyright 2007, 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 +""" + +from Element import Element +import Utils +import Colors +from .. base import odict +from Constants import BORDER_PROXIMITY_SENSITIVITY +from Constants import \ + BLOCK_LABEL_PADDING, \ + PORT_SEPARATION, LABEL_SEPARATION, \ + PORT_BORDER_SEPARATION, POSSIBLE_ROTATIONS +import pygtk +pygtk.require('2.0') +import gtk +import pango + +BLOCK_MARKUP_TMPL="""\ +#set $foreground = $block.is_valid() and 'black' or 'red' +<span foreground="$foreground" font_desc="Sans 8"><b>$encode($block.get_name())</b></span>""" + +class Block(Element): + """The graphical signal block.""" + + def __init__(self): + """ + Block contructor. + Add graphics related params to the block. + """ + #add the position param + self.get_params().append(self.get_parent().get_parent().Param( + block=self, + n=odict({ + 'name': 'GUI Coordinate', + 'key': '_coordinate', + 'type': 'raw', + 'value': '(0, 0)', + 'hide': 'all', + }) + )) + self.get_params().append(self.get_parent().get_parent().Param( + block=self, + n=odict({ + 'name': 'GUI Rotation', + 'key': '_rotation', + 'type': 'raw', + 'value': '0', + 'hide': 'all', + }) + )) + Element.__init__(self) + + def get_coordinate(self): + """ + Get the coordinate from the position param. + @return the coordinate tuple (x, y) or (0, 0) if failure + """ + try: #should evaluate to tuple + coor = eval(self.get_param('_coordinate').get_value()) + x, y = map(int, coor) + fgW,fgH = self.get_parent().get_size() + if x <= 0: + x = 0 + elif x >= fgW - BORDER_PROXIMITY_SENSITIVITY: + x = fgW - BORDER_PROXIMITY_SENSITIVITY + if y <= 0: + y = 0 + elif y >= fgH - BORDER_PROXIMITY_SENSITIVITY: + y = fgH - BORDER_PROXIMITY_SENSITIVITY + return (x, y) + except: + self.set_coordinate((0, 0)) + return (0, 0) + + def set_coordinate(self, coor): + """ + Set the coordinate into the position param. + @param coor the coordinate tuple (x, y) + """ + self.get_param('_coordinate').set_value(str(coor)) + + def get_rotation(self): + """ + Get the rotation from the position param. + @return the rotation in degrees or 0 if failure + """ + try: #should evaluate to dict + rotation = eval(self.get_param('_rotation').get_value()) + return int(rotation) + except: + self.set_rotation(POSSIBLE_ROTATIONS[0]) + return POSSIBLE_ROTATIONS[0] + + def set_rotation(self, rot): + """ + Set the rotation into the position param. + @param rot the rotation in degrees + """ + self.get_param('_rotation').set_value(str(rot)) + + def create_shapes(self): + """Update the block, parameters, and ports when a change occurs.""" + Element.create_shapes(self) + if self.is_horizontal(): self.add_area((0, 0), (self.W, self.H)) + elif self.is_vertical(): self.add_area((0, 0), (self.H, self.W)) + + def create_labels(self): + """Create the labels for the signal block.""" + Element.create_labels(self) + self._bg_color = self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR + layouts = list() + #create the main layout + layout = gtk.DrawingArea().create_pango_layout('') + layouts.append(layout) + layout.set_markup(Utils.parse_template(BLOCK_MARKUP_TMPL, block=self)) + self.label_width, self.label_height = layout.get_pixel_size() + #display the params + markups = [param.get_markup() for param in self.get_params() if param.get_hide() not in ('all', 'part')] + if markups: + layout = gtk.DrawingArea().create_pango_layout('') + layout.set_spacing(LABEL_SEPARATION*pango.SCALE) + layout.set_markup('\n'.join(markups)) + layouts.append(layout) + w,h = layout.get_pixel_size() + self.label_width = max(w, self.label_width) + self.label_height += h + LABEL_SEPARATION + width = self.label_width + height = self.label_height + #setup the pixmap + pixmap = self.get_parent().new_pixmap(width, height) + gc = pixmap.new_gc() + gc.set_foreground(self._bg_color) + pixmap.draw_rectangle(gc, True, 0, 0, width, height) + #draw the layouts + h_off = 0 + for i,layout in enumerate(layouts): + w,h = layout.get_pixel_size() + if i == 0: w_off = (width-w)/2 + else: w_off = 0 + pixmap.draw_layout(gc, w_off, h_off, layout) + h_off = h + h_off + LABEL_SEPARATION + #create vertical and horizontal pixmaps + self.horizontal_label = pixmap + if self.is_vertical(): + self.vertical_label = self.get_parent().new_pixmap(height, width) + Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label) + #calculate width and height needed + self.W = self.label_width + 2*BLOCK_LABEL_PADDING + self.H = max(*( + [self.label_height+2*BLOCK_LABEL_PADDING] + [2*PORT_BORDER_SEPARATION + \ + sum([port.H + PORT_SEPARATION for port in ports]) - PORT_SEPARATION + for ports in (self.get_sources(), self.get_sinks())] + )) + + def draw(self, gc, window): + """ + Draw the signal block with label and inputs/outputs. + @param gc the graphics context + @param window the gtk window to draw on + """ + x, y = self.get_coordinate() + #draw main block + Element.draw( + self, gc, window, bg_color=self._bg_color, + border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or Colors.BORDER_COLOR, + ) + #draw label image + if self.is_horizontal(): + window.draw_drawable(gc, self.horizontal_label, 0, 0, x+BLOCK_LABEL_PADDING, y+(self.H-self.label_height)/2, -1, -1) + elif self.is_vertical(): + window.draw_drawable(gc, self.vertical_label, 0, 0, x+(self.H-self.label_height)/2, y+BLOCK_LABEL_PADDING, -1, -1) + #draw ports + for port in self.get_ports(): port.draw(gc, window) + + def what_is_selected(self, coor, coor_m=None): + """ + Get the element that is selected. + @param coor the (x,y) tuple + @param coor_m the (x_m, y_m) tuple + @return this block, a port, or None + """ + for port in self.get_ports(): + port_selected = port.what_is_selected(coor, coor_m) + if port_selected: return port_selected + return Element.what_is_selected(self, coor, coor_m) diff --git a/grc/gui/BlockTreeWindow.py b/grc/gui/BlockTreeWindow.py new file mode 100644 index 000000000..62afb6205 --- /dev/null +++ b/grc/gui/BlockTreeWindow.py @@ -0,0 +1,201 @@ +""" +Copyright 2007, 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 +""" + +from Constants import DEFAULT_BLOCKS_WINDOW_WIDTH, DND_TARGETS +import Utils +import pygtk +pygtk.require('2.0') +import gtk +import gobject + +NAME_INDEX = 0 +KEY_INDEX = 1 +DOC_INDEX = 2 + +DOC_MARKUP_TMPL="""\ +#if $doc +$encode($doc)#slurp +#else +undocumented#slurp +#end if""" + +CAT_MARKUP_TMPL="""Category: $cat""" + +class BlockTreeWindow(gtk.VBox): + """The block selection panel.""" + + def __init__(self, platform, get_flow_graph): + """ + BlockTreeWindow constructor. + Create a tree view of the possible blocks in the platform. + The tree view nodes will be category names, the leaves will be block names. + A mouse double click or button press action will trigger the add block event. + @param platform the particular platform will all block prototypes + @param get_flow_graph get the selected flow graph + """ + gtk.VBox.__init__(self) + self.platform = platform + self.get_flow_graph = get_flow_graph + #make the tree model for holding blocks + self.treestore = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING) + self.treeview = gtk.TreeView(self.treestore) + self.treeview.set_enable_search(False) #disable pop up search box + self.treeview.add_events(gtk.gdk.BUTTON_PRESS_MASK) + self.treeview.connect('button-press-event', self._handle_mouse_button_press) + selection = self.treeview.get_selection() + selection.set_mode('single') + selection.connect('changed', self._handle_selection_change) + renderer = gtk.CellRendererText() + column = gtk.TreeViewColumn('Blocks', renderer, text=NAME_INDEX) + self.treeview.append_column(column) + #setup the search + self.treeview.set_enable_search(True) + self.treeview.set_search_equal_func(self._handle_search) + #try to enable the tooltips (available in pygtk 2.12 and above) + try: self.treeview.set_tooltip_column(DOC_INDEX) + except: pass + #setup drag and drop + self.treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, DND_TARGETS, gtk.gdk.ACTION_COPY) + self.treeview.connect('drag-data-get', self._handle_drag_get_data) + #make the scrolled window to hold the tree view + scrolled_window = gtk.ScrolledWindow() + scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + scrolled_window.add_with_viewport(self.treeview) + scrolled_window.set_size_request(DEFAULT_BLOCKS_WINDOW_WIDTH, -1) + self.pack_start(scrolled_window) + #add button + self.add_button = gtk.Button(None, gtk.STOCK_ADD) + self.add_button.connect('clicked', self._handle_add_button) + self.pack_start(self.add_button, False) + #map categories to iters, automatic mapping for root + self._categories = {tuple(): None} + #add blocks and categories + self.platform.load_block_tree(self) + #initialize + self._update_add_button() + + def clear(self): + self.treestore.clear(); + self._categories = {tuple(): None} + + + ############################################################ + ## Block Tree Methods + ############################################################ + def add_block(self, category, block=None): + """ + Add a block with category to this selection window. + Add only the category when block is None. + @param category the category list or path string + @param block the block object or None + """ + if isinstance(category, str): category = category.split('/') + category = tuple(filter(lambda x: x, category)) #tuple is hashable + #add category and all sub categories + for i, cat_name in enumerate(category): + sub_category = category[:i+1] + if sub_category not in self._categories: + iter = self.treestore.insert_before(self._categories[sub_category[:-1]], None) + self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%cat_name) + self.treestore.set_value(iter, KEY_INDEX, '') + self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(CAT_MARKUP_TMPL, cat=cat_name)) + self._categories[sub_category] = iter + #add block + if block is None: return + iter = self.treestore.insert_before(self._categories[category], None) + self.treestore.set_value(iter, NAME_INDEX, block.get_name()) + self.treestore.set_value(iter, KEY_INDEX, block.get_key()) + self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc())) + + ############################################################ + ## Helper Methods + ############################################################ + def _get_selected_block_key(self): + """ + Get the currently selected block key. + @return the key of the selected block or a empty string + """ + selection = self.treeview.get_selection() + treestore, iter = selection.get_selected() + return iter and treestore.get_value(iter, KEY_INDEX) or '' + + def _update_add_button(self): + """ + Update the add button's sensitivity. + The button should be active only if a block is selected. + """ + key = self._get_selected_block_key() + self.add_button.set_sensitive(bool(key)) + + def _add_selected_block(self): + """ + Add the selected block with the given key to the flow graph. + """ + key = self._get_selected_block_key() + if key: self.get_flow_graph().add_new_block(key) + + ############################################################ + ## Event Handlers + ############################################################ + def _handle_search(self, model, column, key, iter): + #determine which blocks match the search key + blocks = self.get_flow_graph().get_parent().get_blocks() + matching_blocks = filter(lambda b: key in b.get_key() or key in b.get_name().lower(), blocks) + #remove the old search category + try: self.treestore.remove(self._categories.pop((self._search_category, ))) + except (KeyError, AttributeError): pass #nothing to remove + #create a search category + if not matching_blocks: return + self._search_category = 'Search: %s'%key + for block in matching_blocks: self.add_block(self._search_category, block) + #expand the search category + path = self.treestore.get_path(self._categories[(self._search_category, )]) + self.treeview.collapse_all() + self.treeview.expand_row(path, open_all=False) + + def _handle_drag_get_data(self, widget, drag_context, selection_data, info, time): + """ + Handle a drag and drop by setting the key to the selection object. + This will call the destination handler for drag and drop. + Only call set when the key is valid to ignore DND from categories. + """ + key = self._get_selected_block_key() + if key: selection_data.set(selection_data.target, 8, key) + + def _handle_mouse_button_press(self, widget, event): + """ + Handle the mouse button press. + If a left double click is detected, call add selected block. + """ + if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS: + self._add_selected_block() + + def _handle_selection_change(self, selection): + """ + Handle a selection change in the tree view. + If a selection changes, set the add button sensitive. + """ + self._update_add_button() + + def _handle_add_button(self, widget): + """ + Handle the add button clicked signal. + Call add selected block. + """ + self._add_selected_block() diff --git a/grc/gui/CMakeLists.txt b/grc/gui/CMakeLists.txt new file mode 100644 index 000000000..c2eb16e9f --- /dev/null +++ b/grc/gui/CMakeLists.txt @@ -0,0 +1,48 @@ +# Copyright 2011 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. + +######################################################################## +GR_PYTHON_INSTALL(FILES + 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 + PropsDialog.py + Preferences.py + StateCache.py + __init__.py + DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/gui + COMPONENT "grc" +) diff --git a/grc/gui/Colors.py b/grc/gui/Colors.py new file mode 100644 index 000000000..c79dadee3 --- /dev/null +++ b/grc/gui/Colors.py @@ -0,0 +1,40 @@ +""" +Copyright 2008 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 pygtk +pygtk.require('2.0') +import gtk + +_COLORMAP = gtk.gdk.colormap_get_system() #create all of the colors +def get_color(color_code): return _COLORMAP.alloc_color(color_code, True, True) + +HIGHLIGHT_COLOR = get_color('#00FFFF') +BORDER_COLOR = get_color('black') +#param entry boxes +PARAM_ENTRY_TEXT_COLOR = get_color('black') +ENTRYENUM_CUSTOM_COLOR = get_color('#EEEEEE') +#flow graph color constants +FLOWGRAPH_BACKGROUND_COLOR = get_color('#FFF9FF') +#block color constants +BLOCK_ENABLED_COLOR = get_color('#F1ECFF') +BLOCK_DISABLED_COLOR = get_color('#CCCCCC') +#connection color constants +CONNECTION_ENABLED_COLOR = get_color('black') +CONNECTION_DISABLED_COLOR = get_color('#999999') +CONNECTION_ERROR_COLOR = get_color('red') diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py new file mode 100644 index 000000000..fabf34ee7 --- /dev/null +++ b/grc/gui/Connection.py @@ -0,0 +1,143 @@ +""" +Copyright 2007, 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 Utils +from Element import Element +import Colors +from Constants import CONNECTOR_ARROW_BASE, CONNECTOR_ARROW_HEIGHT + +class Connection(Element): + """ + A graphical connection for ports. + The connection has 2 parts, the arrow and the wire. + The coloring of the arrow and wire exposes the status of 3 states: + enabled/disabled, valid/invalid, highlighted/non-highlighted. + The wire coloring exposes the enabled and highlighted states. + The arrow coloring exposes the enabled and valid states. + """ + + def __init__(self): Element.__init__(self) + + def get_coordinate(self): + """ + Get the 0,0 coordinate. + Coordinates are irrelevant in connection. + @return 0, 0 + """ + return (0, 0) + + def get_rotation(self): + """ + Get the 0 degree rotation. + Rotations are irrelevant in connection. + @return 0 + """ + return 0 + + def create_shapes(self): + """Precalculate relative coordinates.""" + Element.create_shapes(self) + self._sink_rot = None + self._source_rot = None + self._sink_coor = None + self._source_coor = None + #get the source coordinate + connector_length = self.get_source().get_connector_length() + self.x1, self.y1 = Utils.get_rotated_coordinate((connector_length, 0), self.get_source().get_rotation()) + #get the sink coordinate + connector_length = self.get_sink().get_connector_length() + CONNECTOR_ARROW_HEIGHT + self.x2, self.y2 = Utils.get_rotated_coordinate((-connector_length, 0), self.get_sink().get_rotation()) + #build the arrow + self.arrow = [(0, 0), + Utils.get_rotated_coordinate((-CONNECTOR_ARROW_HEIGHT, -CONNECTOR_ARROW_BASE/2), self.get_sink().get_rotation()), + Utils.get_rotated_coordinate((-CONNECTOR_ARROW_HEIGHT, CONNECTOR_ARROW_BASE/2), self.get_sink().get_rotation()), + ] + self._update_after_move() + if not self.get_enabled(): self._arrow_color = Colors.CONNECTION_DISABLED_COLOR + elif not self.is_valid(): self._arrow_color = Colors.CONNECTION_ERROR_COLOR + else: self._arrow_color = Colors.CONNECTION_ENABLED_COLOR + + def _update_after_move(self): + """Calculate coordinates.""" + self.clear() #FIXME do i want this here? + #source connector + source = self.get_source() + X, Y = source.get_connector_coordinate() + x1, y1 = self.x1 + X, self.y1 + Y + self.add_line((x1, y1), (X, Y)) + #sink connector + sink = self.get_sink() + X, Y = sink.get_connector_coordinate() + x2, y2 = self.x2 + X, self.y2 + Y + self.add_line((x2, y2), (X, Y)) + #adjust arrow + self._arrow = [(x+X, y+Y) for x,y in self.arrow] + #add the horizontal and vertical lines in this connection + if abs(source.get_connector_direction() - sink.get_connector_direction()) == 180: + #2 possible point sets to create a 3-line connector + mid_x, mid_y = (x1 + x2)/2.0, (y1 + y2)/2.0 + points = [((mid_x, y1), (mid_x, y2)), ((x1, mid_y), (x2, mid_y))] + #source connector -> points[0][0] should be in the direction of source (if possible) + if Utils.get_angle_from_coordinates((x1, y1), points[0][0]) != source.get_connector_direction(): points.reverse() + #points[0][0] -> sink connector should not be in the direction of sink + if Utils.get_angle_from_coordinates(points[0][0], (x2, y2)) == sink.get_connector_direction(): points.reverse() + #points[0][0] -> source connector should not be in the direction of source + if Utils.get_angle_from_coordinates(points[0][0], (x1, y1)) == source.get_connector_direction(): points.reverse() + #create 3-line connector + p1, p2 = map(int, points[0][0]), map(int, points[0][1]) + self.add_line((x1, y1), p1) + self.add_line(p1, p2) + self.add_line((x2, y2), p2) + else: + #2 possible points to create a right-angled connector + points = [(x1, y2), (x2, y1)] + #source connector -> points[0] should be in the direction of source (if possible) + if Utils.get_angle_from_coordinates((x1, y1), points[0]) != source.get_connector_direction(): points.reverse() + #points[0] -> sink connector should not be in the direction of sink + if Utils.get_angle_from_coordinates(points[0], (x2, y2)) == sink.get_connector_direction(): points.reverse() + #points[0] -> source connector should not be in the direction of source + if Utils.get_angle_from_coordinates(points[0], (x1, y1)) == source.get_connector_direction(): points.reverse() + #create right-angled connector + self.add_line((x1, y1), points[0]) + self.add_line((x2, y2), points[0]) + + def draw(self, gc, window): + """ + Draw the connection. + @param gc the graphics context + @param window the gtk window to draw on + """ + sink = self.get_sink() + source = self.get_source() + #check for changes + if self._sink_rot != sink.get_rotation() or self._source_rot != source.get_rotation(): self.create_shapes() + elif self._sink_coor != sink.get_coordinate() or self._source_coor != source.get_coordinate(): self._update_after_move() + #cache values + self._sink_rot = sink.get_rotation() + self._source_rot = source.get_rotation() + self._sink_coor = sink.get_coordinate() + self._source_coor = source.get_coordinate() + #draw + if self.is_highlighted(): border_color = Colors.HIGHLIGHT_COLOR + elif self.get_enabled(): border_color = Colors.CONNECTION_ENABLED_COLOR + else: border_color = Colors.CONNECTION_DISABLED_COLOR + Element.draw(self, gc, window, bg_color=None, border_color=border_color) + #draw arrow on sink port + gc.set_foreground(self._arrow_color) + window.draw_polygon(gc, True, self._arrow) diff --git a/grc/gui/Constants.py b/grc/gui/Constants.py new file mode 100644 index 000000000..7fabcfc0a --- /dev/null +++ b/grc/gui/Constants.py @@ -0,0 +1,83 @@ +""" +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 pygtk +pygtk.require('2.0') +import gtk +import os + +##default path for the open/save dialogs +DEFAULT_FILE_PATH = os.getcwd() + +##file extensions +IMAGE_FILE_EXTENSION = '.png' + +##name for new/unsaved flow graphs +NEW_FLOGRAPH_TITLE = 'untitled' + +##main window constraints +MIN_WINDOW_WIDTH = 600 +MIN_WINDOW_HEIGHT = 400 +##dialog constraints +MIN_DIALOG_WIDTH = 500 +MIN_DIALOG_HEIGHT = 500 +##default sizes +DEFAULT_BLOCKS_WINDOW_WIDTH = 100 +DEFAULT_REPORTS_WINDOW_WIDTH = 100 + +##The size of the state saving cache in the flow graph (for undo/redo functionality) +STATE_CACHE_SIZE = 42 + +##Shared targets for drag and drop of blocks +DND_TARGETS = [('STRING', gtk.TARGET_SAME_APP, 0)] + +#label constraint dimensions +LABEL_SEPARATION = 3 +BLOCK_LABEL_PADDING = 7 +PORT_LABEL_PADDING = 2 + +#port constraint dimensions +PORT_SEPARATION = 17 +PORT_BORDER_SEPARATION = 9 +PORT_MIN_WIDTH = 20 + +#minimal length of connector +CONNECTOR_EXTENSION_MINIMAL = 11 + +#increment length for connector +CONNECTOR_EXTENSION_INCREMENT = 11 + +#connection arrow dimensions +CONNECTOR_ARROW_BASE = 13 +CONNECTOR_ARROW_HEIGHT = 17 + +#possible rotations in degrees +POSSIBLE_ROTATIONS = (0, 90, 180, 270) + +#How close can the mouse get to the window border before mouse events are ignored. +BORDER_PROXIMITY_SENSITIVITY = 50 + +#How close the mouse can get to the edge of the visible window before scrolling is invoked. +SCROLL_PROXIMITY_SENSITIVITY = 30 + +#When the window has to be scrolled, move it this distance in the required direction. +SCROLL_DISTANCE = 15 + +#How close the mouse click can be to a line and register a connection select. +LINE_SELECT_SENSITIVITY = 5 diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py new file mode 100644 index 000000000..473c796af --- /dev/null +++ b/grc/gui/Dialogs.py @@ -0,0 +1,118 @@ +""" +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 pygtk +pygtk.require('2.0') +import gtk +import Utils + +class TextDisplay(gtk.TextView): + """A non editable gtk text view.""" + + def __init__(self, text=''): + """ + TextDisplay constructor. + @param text the text to display (string) + """ + text_buffer = gtk.TextBuffer() + text_buffer.set_text(text) + self.set_text = text_buffer.set_text + self.insert = lambda line: text_buffer.insert(text_buffer.get_end_iter(), line) + gtk.TextView.__init__(self, text_buffer) + self.set_editable(False) + self.set_cursor_visible(False) + self.set_wrap_mode(gtk.WRAP_WORD_CHAR) + +def MessageDialogHelper(type, buttons, title=None, markup=None): + """ + Create a modal message dialog and run it. + @param type the type of message: gtk.MESSAGE_INFO, gtk.MESSAGE_WARNING, gtk.MESSAGE_QUESTION or gtk.MESSAGE_ERROR + @param buttons the predefined set of buttons to use: + gtk.BUTTONS_NONE, gtk.BUTTONS_OK, gtk.BUTTONS_CLOSE, gtk.BUTTONS_CANCEL, gtk.BUTTONS_YES_NO, gtk.BUTTONS_OK_CANCEL + @param tittle the title of the window (string) + @param markup the message text with pango markup + @return the gtk response from run() + """ + message_dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, type, buttons) + if title: message_dialog.set_title(title) + if markup: message_dialog.set_markup(markup) + response = message_dialog.run() + message_dialog.destroy() + return response + + +ERRORS_MARKUP_TMPL="""\ +#for $i, $err_msg in enumerate($errors) +<b>Error $i:</b> +$encode($err_msg.replace('\t', ' ')) + +#end for""" +def ErrorsDialog(flowgraph): MessageDialogHelper( + type=gtk.MESSAGE_ERROR, + buttons=gtk.BUTTONS_CLOSE, + title='Flow Graph Errors', + markup=Utils.parse_template(ERRORS_MARKUP_TMPL, errors=flowgraph.get_error_messages()), +) + +class AboutDialog(gtk.AboutDialog): + """A cute little about dialog.""" + + def __init__(self, platform): + """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.run() + self.destroy() + +def HelpDialog(): MessageDialogHelper( + type=gtk.MESSAGE_INFO, + buttons=gtk.BUTTONS_CLOSE, + title='Help', + markup="""\ +<b>Usage Tips</b> + +<u>Add block</u>: drag and drop or double click a block in the block selection window. +<u>Rotate block</u>: Select a block, press left/right on the keyboard. +<u>Change type</u>: Select a block, press up/down on the keyboard. +<u>Edit parameters</u>: double click on a block in the flow graph. +<u>Make connection</u>: click on the source port of one block, then click on the sink port of another block. +<u>Remove connection</u>: select the connection and press delete, or drag the connection. + +* See the menu for other keyboard shortcuts.""") + +COLORS_DIALOG_MARKUP_TMPL = """\ +<b>Color Mapping</b> + +#if $colors + #set $max_len = max([len(color[0]) for color in $colors]) + 10 + #for $title, $color_spec in $colors +<span background="$color_spec"><tt>$($encode($title).center($max_len))</tt></span> + #end for +#end if +""" + +def TypesDialog(platform): MessageDialogHelper( + type=gtk.MESSAGE_INFO, + buttons=gtk.BUTTONS_CLOSE, + title='Types', + markup=Utils.parse_template(COLORS_DIALOG_MARKUP_TMPL, colors=platform.get_colors())) diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py new file mode 100644 index 000000000..790df7c3f --- /dev/null +++ b/grc/gui/DrawingArea.py @@ -0,0 +1,133 @@ +""" +Copyright 2007, 2008, 2009, 2010 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 pygtk +pygtk.require('2.0') +import gtk +from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT, DND_TARGETS + +class DrawingArea(gtk.DrawingArea): + """ + DrawingArea is the gtk pixel map that graphical elements may draw themselves on. + The drawing area also responds to mouse and key events. + """ + + def __init__(self, flow_graph): + """ + DrawingArea contructor. + Connect event handlers. + @param main_window the main_window containing all flow graphs + """ + self.ctrl_mask = False + self._flow_graph = flow_graph + gtk.DrawingArea.__init__(self) + self.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT) + self.connect('realize', self._handle_window_realize) + self.connect('configure-event', self._handle_window_configure) + self.connect('expose-event', self._handle_window_expose) + self.connect('motion-notify-event', self._handle_mouse_motion) + self.connect('button-press-event', self._handle_mouse_button_press) + self.connect('button-release-event', self._handle_mouse_button_release) + self.add_events( + gtk.gdk.BUTTON_PRESS_MASK | \ + gtk.gdk.POINTER_MOTION_MASK | \ + gtk.gdk.BUTTON_RELEASE_MASK | \ + gtk.gdk.LEAVE_NOTIFY_MASK | \ + gtk.gdk.ENTER_NOTIFY_MASK + ) + #setup drag and drop + self.drag_dest_set(gtk.DEST_DEFAULT_ALL, DND_TARGETS, gtk.gdk.ACTION_COPY) + self.connect('drag-data-received', self._handle_drag_data_received) + #setup the focus flag + self._focus_flag = False + self.get_focus_flag = lambda: self._focus_flag + def _handle_focus_event(widget, event, focus_flag): self._focus_flag = focus_flag + self.connect('leave-notify-event', _handle_focus_event, False) + self.connect('enter-notify-event', _handle_focus_event, True) + + 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) + return pixbuf + + ########################################################################## + ## Handlers + ########################################################################## + def _handle_drag_data_received(self, widget, drag_context, x, y, selection_data, info, time): + """ + Handle a drag and drop by adding a block at the given coordinate. + """ + self._flow_graph.add_new_block(selection_data.data, (x, y)) + + def _handle_mouse_button_press(self, widget, event): + """ + Forward button click information to the flow graph. + """ + self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK + if event.button == 1: self._flow_graph.handle_mouse_selector_press( + double_click=(event.type == gtk.gdk._2BUTTON_PRESS), + coordinate=(event.x, event.y), + ) + if event.button == 3: self._flow_graph.handle_mouse_context_press( + coordinate=(event.x, event.y), + event=event, + ) + + def _handle_mouse_button_release(self, widget, event): + """ + Forward button release information to the flow graph. + """ + self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK + if event.button == 1: self._flow_graph.handle_mouse_selector_release( + coordinate=(event.x, event.y), + ) + + def _handle_mouse_motion(self, widget, event): + """ + Forward mouse motion information to the flow graph. + """ + self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK + self._flow_graph.handle_mouse_motion( + coordinate=(event.x, event.y), + ) + + def _handle_window_realize(self, widget): + """ + Called when the window is realized. + Update the flowgraph, which calls new pixmap. + """ + self._flow_graph.update() + + def _handle_window_configure(self, widget, event): + """ + Called when the window is resized. + Create a new pixmap for background buffer. + """ + self._pixmap = self.new_pixmap(*self.get_size_request()) + + def _handle_window_expose(self, widget, event): + """ + Called when window is exposed, or queue_draw is called. + Double buffering: draw to pixmap, then draw pixmap to window. + """ + 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) diff --git a/grc/gui/Element.py b/grc/gui/Element.py new file mode 100644 index 000000000..e020c5caa --- /dev/null +++ b/grc/gui/Element.py @@ -0,0 +1,228 @@ +""" +Copyright 2007, 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 +""" + +from Constants import LINE_SELECT_SENSITIVITY +from Constants import POSSIBLE_ROTATIONS + +class Element(object): + """ + GraphicalElement is the base class for all graphical elements. + It contains an X,Y coordinate, a list of rectangular areas that the element occupies, + and methods to detect selection of those areas. + """ + + def __init__(self): + """ + Make a new list of rectangular areas and lines, and set the coordinate and the rotation. + """ + self.set_rotation(POSSIBLE_ROTATIONS[0]) + self.set_coordinate((0, 0)) + self.clear() + self.set_highlighted(False) + + def is_horizontal(self, rotation=None): + """ + Is this element horizontal? + If rotation is None, use this element's rotation. + @param rotation the optional rotation + @return true if rotation is horizontal + """ + rotation = rotation or self.get_rotation() + return rotation in (0, 180) + + def is_vertical(self, rotation=None): + """ + Is this element vertical? + If rotation is None, use this element's rotation. + @param rotation the optional rotation + @return true if rotation is vertical + """ + rotation = rotation or self.get_rotation() + return rotation in (90, 270) + + def create_labels(self): + """ + Create labels (if applicable) and call on all children. + Call this base method before creating labels in the element. + """ + for child in self.get_children(): child.create_labels() + + def create_shapes(self): + """ + Create shapes (if applicable) and call on all children. + Call this base method before creating shapes in the element. + """ + self.clear() + for child in self.get_children(): child.create_shapes() + + def draw(self, gc, window, border_color, bg_color): + """ + Draw in the given window. + @param gc the graphics context + @param window the gtk window to draw on + @param border_color the color for lines and rectangle borders + @param bg_color the color for the inside of the rectangle + """ + X,Y = self.get_coordinate() + for (rX,rY),(W,H) in self._areas_list: + aX = X + rX + aY = Y + rY + gc.set_foreground(bg_color) + window.draw_rectangle(gc, True, aX, aY, W, H) + gc.set_foreground(border_color) + window.draw_rectangle(gc, False, aX, aY, W, H) + for (x1, y1),(x2, y2) in self._lines_list: + gc.set_foreground(border_color) + window.draw_line(gc, X+x1, Y+y1, X+x2, Y+y2) + + def rotate(self, rotation): + """ + Rotate all of the areas by 90 degrees. + @param rotation multiple of 90 degrees + """ + self.set_rotation((self.get_rotation() + rotation)%360) + + def clear(self): + """Empty the lines and areas.""" + self._areas_list = list() + self._lines_list = list() + + def set_coordinate(self, coor): + """ + Set the reference coordinate. + @param coor the coordinate tuple (x,y) + """ + self.coor = coor + + def get_parent(self): + """ + Get the parent of this element. + @return the parent + """ + return self.parent + + def set_highlighted(self, highlighted): + """ + Set the highlight status. + @param highlighted true to enable highlighting + """ + self.highlighted = highlighted + + def is_highlighted(self): + """ + Get the highlight status. + @return true if highlighted + """ + return self.highlighted + + def get_coordinate(self): + """Get the coordinate. + @return the coordinate tuple (x,y) + """ + return self.coor + + def move(self, delta_coor): + """ + Move the element by adding the delta_coor to the current coordinate. + @param delta_coor (delta_x,delta_y) tuple + """ + deltaX, deltaY = delta_coor + X, Y = self.get_coordinate() + self.set_coordinate((X+deltaX, Y+deltaY)) + + def add_area(self, rel_coor, area): + """ + Add an area to the area list. + An area is actually a coordinate relative to the main coordinate + with a width/height pair relative to the area coordinate. + A positive width is to the right of the coordinate. + A positive height is above the coordinate. + The area is associated with a rotation. + @param rel_coor (x,y) offset from this element's coordinate + @param area (width,height) tuple + """ + self._areas_list.append((rel_coor, area)) + + def add_line(self, rel_coor1, rel_coor2): + """ + Add a line to the line list. + A line is defined by 2 relative coordinates. + Lines must be horizontal or vertical. + The line is associated with a rotation. + @param rel_coor1 relative (x1,y1) tuple + @param rel_coor2 relative (x2,y2) tuple + """ + self._lines_list.append((rel_coor1, rel_coor2)) + + def what_is_selected(self, coor, coor_m=None): + """ + One coordinate specified: + Is this element selected at given coordinate? + ie: is the coordinate encompassed by one of the areas or lines? + Both coordinates specified: + Is this element within the rectangular region defined by both coordinates? + ie: do any area corners or line endpoints fall within the region? + @param coor the selection coordinate, tuple x, y + @param coor_m an additional selection coordinate. + @return self if one of the areas/lines encompasses coor, else None. + """ + #function to test if p is between a and b (inclusive) + in_between = lambda p, a, b: p >= min(a, b) and p <= max(a, b) + #relative coordinate + x, y = [a-b for a,b in zip(coor, self.get_coordinate())] + if coor_m: + x_m, y_m = [a-b for a,b in zip(coor_m, self.get_coordinate())] + #handle rectangular areas + for (x1,y1), (w,h) in self._areas_list: + if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \ + in_between(x1+w, x, x_m) and in_between(y1, y, y_m) or \ + in_between(x1, x, x_m) and in_between(y1+h, y, y_m) or \ + in_between(x1+w, x, x_m) and in_between(y1+h, y, y_m): + return self + #handle horizontal or vertical lines + for (x1, y1), (x2, y2) in self._lines_list: + if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \ + in_between(x2, x, x_m) and in_between(y2, y, y_m): + return self + return None + else: + #handle rectangular areas + for (x1,y1), (w,h) in self._areas_list: + if in_between(x, x1, x1+w) and in_between(y, y1, y1+h): return self + #handle horizontal or vertical lines + for (x1, y1), (x2, y2) in self._lines_list: + if x1 == x2: x1, x2 = x1-LINE_SELECT_SENSITIVITY, x2+LINE_SELECT_SENSITIVITY + if y1 == y2: y1, y2 = y1-LINE_SELECT_SENSITIVITY, y2+LINE_SELECT_SENSITIVITY + if in_between(x, x1, x2) and in_between(y, y1, y2): return self + return None + + def get_rotation(self): + """ + Get the rotation in degrees. + @return the rotation + """ + return self.rotation + + def set_rotation(self, rotation): + """ + Set the rotation in degrees. + @param rotation the rotation""" + if rotation not in POSSIBLE_ROTATIONS: + raise Exception('"%s" is not one of the possible rotations: (%s)'%(rotation, POSSIBLE_ROTATIONS)) + self.rotation = rotation diff --git a/grc/gui/FileDialogs.py b/grc/gui/FileDialogs.py new file mode 100644 index 000000000..3b210c33f --- /dev/null +++ b/grc/gui/FileDialogs.py @@ -0,0 +1,175 @@ +""" +Copyright 2007 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 pygtk +pygtk.require('2.0') +import gtk +from Dialogs import MessageDialogHelper +from Constants import \ + DEFAULT_FILE_PATH, IMAGE_FILE_EXTENSION, \ + NEW_FLOGRAPH_TITLE +import Preferences +from os import path +import Utils + +################################################## +# Constants +################################################## +OPEN_FLOW_GRAPH = 'open flow graph' +SAVE_FLOW_GRAPH = 'save flow graph' +SAVE_IMAGE = 'save image' + +FILE_OVERWRITE_MARKUP_TMPL="""\ +File <b>$encode($filename)</b> Exists!\nWould you like to overwrite the existing file?""" + +FILE_DNE_MARKUP_TMPL="""\ +File <b>$encode($filename)</b> Does not Exist!""" + +################################################## +# File Filters +################################################## +##the filter for flow graph files +def get_flow_graph_files_filter(): + filter = gtk.FileFilter() + filter.set_name('Flow Graph Files') + filter.add_pattern('*'+Preferences.file_extension()) + return filter + +##the filter for image files +def get_image_files_filter(): + filter = gtk.FileFilter() + filter.set_name('Image Files') + filter.add_pattern('*'+IMAGE_FILE_EXTENSION) + return filter + +##the filter for all files +def get_all_files_filter(): + filter = gtk.FileFilter() + filter.set_name('All Files') + filter.add_pattern('*') + return filter + +################################################## +# File Dialogs +################################################## +class FileDialogHelper(gtk.FileChooserDialog): + """ + A wrapper class for the gtk file chooser dialog. + Implement a file chooser dialog with only necessary parameters. + """ + + def __init__(self, action, title): + """ + FileDialogHelper contructor. + Create a save or open dialog with cancel and ok buttons. + Use standard settings: no multiple selection, local files only, and the * filter. + @param action gtk.FILE_CHOOSER_ACTION_OPEN or gtk.FILE_CHOOSER_ACTION_SAVE + @param title the title of the dialog (string) + """ + ok_stock = {gtk.FILE_CHOOSER_ACTION_OPEN : 'gtk-open', gtk.FILE_CHOOSER_ACTION_SAVE : 'gtk-save'}[action] + gtk.FileChooserDialog.__init__(self, title, None, action, ('gtk-cancel', gtk.RESPONSE_CANCEL, ok_stock, gtk.RESPONSE_OK)) + self.set_select_multiple(False) + self.set_local_only(True) + self.add_filter(get_all_files_filter()) + +class FileDialog(FileDialogHelper): + """A dialog box to save or open flow graph files. This is a base class, do not use.""" + + def __init__(self, current_file_path=''): + """ + FileDialog constructor. + @param current_file_path the current directory or path to the open flow graph + """ + if not current_file_path: current_file_path = path.join(DEFAULT_FILE_PATH, NEW_FLOGRAPH_TITLE + Preferences.file_extension()) + if self.type == OPEN_FLOW_GRAPH: + FileDialogHelper.__init__(self, gtk.FILE_CHOOSER_ACTION_OPEN, 'Open a Flow Graph from a File...') + self.add_and_set_filter(get_flow_graph_files_filter()) + self.set_select_multiple(True) + elif self.type == SAVE_FLOW_GRAPH: + FileDialogHelper.__init__(self, gtk.FILE_CHOOSER_ACTION_SAVE, 'Save a Flow Graph to a File...') + self.add_and_set_filter(get_flow_graph_files_filter()) + self.set_current_name(path.basename(current_file_path)) #show the current filename + elif self.type == SAVE_IMAGE: + FileDialogHelper.__init__(self, gtk.FILE_CHOOSER_ACTION_SAVE, 'Save a Flow Graph Screen Shot...') + self.add_and_set_filter(get_image_files_filter()) + current_file_path = current_file_path + IMAGE_FILE_EXTENSION + self.set_current_name(path.basename(current_file_path)) #show the current filename + self.set_current_folder(path.dirname(current_file_path)) #current directory + + def add_and_set_filter(self, filter): + """ + Add the gtk file filter to the list of filters and set it as the default file filter. + @param filter a gtk file filter. + """ + self.add_filter(filter) + self.set_filter(filter) + + def get_rectified_filename(self): + """ + Run the dialog and get the filename. + If this is a save dialog and the file name is missing the extension, append the file extension. + If the file name with the extension already exists, show a overwrite dialog. + If this is an open dialog, return a list of filenames. + @return the complete file path + """ + if gtk.FileChooserDialog.run(self) != gtk.RESPONSE_OK: return None #response was cancel + ############################################# + # Handle Save Dialogs + ############################################# + if self.type in (SAVE_FLOW_GRAPH, SAVE_IMAGE): + filename = self.get_filename() + extension = { + SAVE_FLOW_GRAPH: Preferences.file_extension(), + SAVE_IMAGE: IMAGE_FILE_EXTENSION, + }[self.type] + #append the missing file extension if the filter matches + if path.splitext(filename)[1].lower() != extension: filename += extension + self.set_current_name(path.basename(filename)) #show the filename with extension + if path.exists(filename): #ask the user to confirm overwrite + if MessageDialogHelper( + gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, 'Confirm Overwrite!', + Utils.parse_template(FILE_OVERWRITE_MARKUP_TMPL, filename=filename), + ) == gtk.RESPONSE_NO: return self.get_rectified_filename() + return filename + ############################################# + # Handle Open Dialogs + ############################################# + elif self.type in (OPEN_FLOW_GRAPH,): + filenames = self.get_filenames() + for filename in filenames: + if not path.exists(filename): #show a warning and re-run + MessageDialogHelper( + gtk.MESSAGE_WARNING, gtk.BUTTONS_CLOSE, 'Cannot Open!', + Utils.parse_template(FILE_DNE_MARKUP_TMPL, filename=filename), + ) + return self.get_rectified_filename() + return filenames + + def run(self): + """ + Get the filename and destroy the dialog. + @return the filename or None if a close/cancel occured. + """ + filename = self.get_rectified_filename() + self.destroy() + return filename + +class OpenFlowGraphFileDialog(FileDialog): type = OPEN_FLOW_GRAPH +class SaveFlowGraphFileDialog(FileDialog): type = SAVE_FLOW_GRAPH +class SaveImageFileDialog(FileDialog): type = SAVE_IMAGE diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py new file mode 100644 index 000000000..6af4bcb62 --- /dev/null +++ b/grc/gui/FlowGraph.py @@ -0,0 +1,524 @@ +""" +Copyright 2007-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 Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE +import Actions +import Colors +import Utils +from Element import Element +import pygtk +pygtk.require('2.0') +import gtk +import random +import Messages + +class FlowGraph(Element): + """ + FlowGraph is the data structure to store graphical signal blocks, + graphical inputs and outputs, + and the connections between inputs and outputs. + """ + + def __init__(self): + """ + FlowGraph contructor. + Create a list for signal blocks and connections. Connect mouse handlers. + """ + Element.__init__(self) + #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.press_coor = (0, 0) + #selected ports + self._old_selected_port = None + self._new_selected_port = None + #context menu + self._context_menu = gtk.Menu() + for action in [ + Actions.BLOCK_CUT, + Actions.BLOCK_COPY, + Actions.BLOCK_PASTE, + Actions.ELEMENT_DELETE, + Actions.BLOCK_ROTATE_CCW, + Actions.BLOCK_ROTATE_CW, + Actions.BLOCK_ENABLE, + Actions.BLOCK_DISABLE, + Actions.BLOCK_PARAM_MODIFY, + Actions.BLOCK_CREATE_HIER, + Actions.OPEN_HIER, + ]: self._context_menu.append(action.create_menu_item()) + + ########################################################################### + # Access Drawing Area + ########################################################################### + def get_drawing_area(self): return self.drawing_area + def queue_draw(self): self.get_drawing_area().queue_draw() + def get_size(self): return self.get_drawing_area().get_size_request() + def set_size(self, *args): self.get_drawing_area().set_size_request(*args) + def get_scroll_pane(self): return self.drawing_area.get_parent() + def get_ctrl_mask(self): return self.drawing_area.ctrl_mask + def new_pixmap(self, *args): return self.get_drawing_area().new_pixmap(*args) + + def add_new_block(self, key, coor=None): + """ + Add a block of the given key to this flow graph. + @param key the block key + @param coor an optional coordinate or None for random + """ + id = self._get_unique_id(key) + #calculate the position coordinate + h_adj = self.get_scroll_pane().get_hadjustment() + v_adj = self.get_scroll_pane().get_vadjustment() + if coor is None: coor = ( + int(random.uniform(.25, .75)*h_adj.page_size + h_adj.get_value()), + int(random.uniform(.25, .75)*v_adj.page_size + v_adj.get_value()), + ) + #get the new block + block = self.get_new_block(key) + block.set_coordinate(coor) + block.set_rotation(0) + block.get_param('id').set_value(id) + Actions.ELEMENT_CREATE() + + return id + + ########################################################################### + # Copy Paste + ########################################################################### + def copy_to_clipboard(self): + """ + Copy the selected blocks and connections into the clipboard. + @return the clipboard + """ + #get selected blocks + blocks = self.get_selected_blocks() + if not blocks: return None + #calc x and y min + x_min, y_min = blocks[0].get_coordinate() + for block in blocks: + x, y = block.get_coordinate() + x_min = min(x, x_min) + y_min = min(y, y_min) + #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(), + ) + clipboard = ( + (x_min, y_min), + [block.export_data() for block in blocks], + [connection.export_data() for connection in connections], + ) + return clipboard + + def paste_from_clipboard(self, clipboard): + """ + Paste the blocks and connections from the clipboard. + @param clipboard the nested data of blocks, connections + """ + selected = set() + (x_min, y_min), blocks_n, connections_n = clipboard + old_id2block = dict() + #recalc the position + h_adj = self.get_scroll_pane().get_hadjustment() + v_adj = self.get_scroll_pane().get_vadjustment() + x_off = h_adj.get_value() - x_min + h_adj.page_size/4 + y_off = v_adj.get_value() - y_min + v_adj.page_size/4 + #create blocks + for block_n in blocks_n: + block_key = block_n.find('key') + if block_key == 'options': continue + block = self.get_new_block(block_key) + selected.add(block) + #set params + params_n = block_n.findall('param') + for param_n in params_n: + param_key = param_n.find('key') + param_value = param_n.find('value') + #setup id parameter + 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 [block.get_id() for block in self.get_blocks()]: + param_value = self._get_unique_id(param_value) + #set value to key + block.get_param(param_key).set_value(param_value) + #move block to offset coordinate + block.move((x_off, y_off)) + #update before creating connections + self.update() + #create connections + for connection_n in connections_n: + source = old_id2block[connection_n.find('source_block_id')].get_source(connection_n.find('source_key')) + sink = old_id2block[connection_n.find('sink_block_id')].get_sink(connection_n.find('sink_key')) + self.connect(source, sink) + #set all pasted elements selected + for block in selected: selected = selected.union(set(block.get_connections())) + self._selected_elements = list(selected) + + ########################################################################### + # Modify Selected + ########################################################################### + def type_controller_modify_selected(self, direction): + """ + Change the registered type controller for the selected signal blocks. + @param direction +1 or -1 + @return true for change + """ + return any([sb.type_controller_modify(direction) for sb in self.get_selected_blocks()]) + + def port_controller_modify_selected(self, direction): + """ + Change port controller for the selected signal blocks. + @param direction +1 or -1 + @return true for changed + """ + return any([sb.port_controller_modify(direction) for sb in self.get_selected_blocks()]) + + def enable_selected(self, enable): + """ + Enable/disable the selected blocks. + @param enable true to enable + @return true if changed + """ + changed = False + for selected_block in self.get_selected_blocks(): + if selected_block.get_enabled() != enable: + selected_block.set_enabled(enable) + changed = True + return changed + + def move_selected(self, delta_coordinate): + """ + Move the element and by the change in coordinates. + @param delta_coordinate the change in coordinates + """ + for selected_block in self.get_selected_blocks(): + selected_block.move(delta_coordinate) + self.element_moved = True + + def rotate_selected(self, rotation): + """ + Rotate the selected blocks by multiples of 90 degrees. + @param rotation the rotation in degrees + @return true if changed, otherwise false. + """ + if not self.get_selected_blocks(): return False + #initialize min and max coordinates + min_x, min_y = self.get_selected_block().get_coordinate() + max_x, max_y = self.get_selected_block().get_coordinate() + #rotate each selected block, and find min/max coordinate + for selected_block in self.get_selected_blocks(): + selected_block.rotate(rotation) + #update the min/max coordinate + x, y = selected_block.get_coordinate() + min_x, min_y = min(min_x, x), min(min_y, y) + max_x, max_y = max(max_x, x), max(max_y, y) + #calculate center point of slected blocks + ctr_x, ctr_y = (max_x + min_x)/2, (max_y + min_y)/2 + #rotate the blocks around the center point + for selected_block in self.get_selected_blocks(): + x, y = selected_block.get_coordinate() + x, y = Utils.get_rotated_coordinate((x - ctr_x, y - ctr_y), rotation) + selected_block.set_coordinate((x + ctr_x, y + ctr_y)) + return True + + def remove_selected(self): + """ + Remove selected elements + @return true if changed. + """ + changed = False + for selected_element in self.get_selected_elements(): + self.remove_element(selected_element) + changed = True + return changed + + def draw(self, gc, window): + """ + Draw the background and grid if enabled. + Draw all of the elements in this flow graph onto the pixmap. + Draw the pixmap to the drawable window of this flow graph. + """ + W,H = self.get_size() + #draw the background + gc.set_foreground(Colors.FLOWGRAPH_BACKGROUND_COLOR) + window.draw_rectangle(gc, True, 0, 0, W, H) + #draw multi select rectangle + if self.mouse_pressed and (not self.get_selected_elements() or self.get_ctrl_mask()): + #coordinates + x1, y1 = self.press_coor + x2, y2 = self.get_coordinate() + #calculate top-left coordinate and width/height + x, y = int(min(x1, x2)), int(min(y1, y2)) + w, h = int(abs(x1 - x2)), int(abs(y1 - y2)) + #draw + gc.set_foreground(Colors.HIGHLIGHT_COLOR) + window.draw_rectangle(gc, True, x, y, w, h) + gc.set_foreground(Colors.BORDER_COLOR) + window.draw_rectangle(gc, False, x, y, w, h) + #draw blocks on top of connections + for element in self.get_connections() + self.get_blocks(): + element.draw(gc, window) + #draw selected blocks on top of selected connections + for selected_element in self.get_selected_connections() + self.get_selected_blocks(): + selected_element.draw(gc, window) + + def update_selected(self): + """ + Remove deleted elements from the selected elements list. + Update highlighting so only the selected are highlighted. + """ + selected_elements = self.get_selected_elements() + elements = self.get_elements() + #remove deleted elements + for selected in selected_elements: + if selected in elements: continue + selected_elements.remove(selected) + if self._old_selected_port and self._old_selected_port.get_parent() not in elements: + self._old_selected_port = None + if self._new_selected_port and self._new_selected_port.get_parent() not in elements: + self._new_selected_port = None + #update highlighting + for element in elements: + element.set_highlighted(element in selected_elements) + + def update(self): + """ + Call the top level rewrite and validate. + Call the top level create labels and shapes. + """ + self.rewrite() + self.validate() + self.create_labels() + self.create_shapes() + + ########################################################################## + ## Get Selected + ########################################################################## + def unselect(self): + """ + Set selected elements to an empty set. + """ + self._selected_elements = [] + + def what_is_selected(self, coor, coor_m=None): + """ + What is selected? + At the given coordinate, return the elements found to be selected. + If coor_m is unspecified, return a list of only the first element found to be selected: + Iterate though the elements backwards since top elements are at the end of the list. + If an element is selected, place it at the end of the list so that is is drawn last, + and hence on top. Update the selected port information. + @param coor the coordinate of the mouse click + @param coor_m the coordinate for multi select + @return the selected blocks and connections or an empty list + """ + selected_port = None + selected = set() + #check the elements + for element in reversed(self.get_elements()): + selected_element = element.what_is_selected(coor, coor_m) + if not selected_element: continue + #update the selected port information + if selected_element.is_port(): + if not coor_m: selected_port = selected_element + selected_element = selected_element.get_parent() + selected.add(selected_element) + #place at the end of the list + self.get_elements().remove(element) + self.get_elements().append(element) + #single select mode, break + if not coor_m: break + #update selected ports + self._old_selected_port = self._new_selected_port + self._new_selected_port = selected_port + return list(selected) + + def get_selected_connections(self): + """ + Get a group of selected connections. + @return sub set of connections in this flow graph + """ + selected = set() + for selected_element in self.get_selected_elements(): + if selected_element.is_connection(): selected.add(selected_element) + return list(selected) + + def get_selected_blocks(self): + """ + Get a group of selected blocks. + @return sub set of blocks in this flow graph + """ + selected = set() + for selected_element in self.get_selected_elements(): + if selected_element.is_block(): selected.add(selected_element) + return list(selected) + + def get_selected_block(self): + """ + Get the selected block when a block or port is selected. + @return a block or None + """ + return self.get_selected_blocks() and self.get_selected_blocks()[0] or None + + def get_selected_elements(self): + """ + Get the group of selected elements. + @return sub set of elements in this flow graph + """ + return self._selected_elements + + def get_selected_element(self): + """ + Get the selected element. + @return a block, port, or connection or None + """ + return self.get_selected_elements() and self.get_selected_elements()[0] or None + + def update_selected_elements(self): + """ + Update the selected elements. + The update behavior depends on the state of the mouse button. + When the mouse button pressed the selection will change when + the control mask is set or the new selection is not in the current group. + When the mouse button is released the selection will change when + the mouse has moved and the control mask is set or the current group is empty. + Attempt to make a new connection if the old and ports are filled. + If the control mask is set, merge with the current elements. + """ + selected_elements = None + if self.mouse_pressed: + new_selections = self.what_is_selected(self.get_coordinate()) + #update the selections if the new selection is not in the current selections + #allows us to move entire selected groups of elements + if self.get_ctrl_mask() or not ( + new_selections and new_selections[0] in self.get_selected_elements() + ): selected_elements = new_selections + else: #called from a mouse release + if not self.element_moved and (not self.get_selected_elements() or self.get_ctrl_mask()): + selected_elements = self.what_is_selected(self.get_coordinate(), self.press_coor) + #this selection and the last were ports, try to connect them + if self._old_selected_port and self._new_selected_port and \ + self._old_selected_port is not self._new_selected_port: + try: + self.connect(self._old_selected_port, self._new_selected_port) + Actions.ELEMENT_CREATE() + except: Messages.send_fail_connection() + self._old_selected_port = None + self._new_selected_port = None + return + #update selected elements + if selected_elements is None: return + old_elements = set(self.get_selected_elements()) + self._selected_elements = list(set(selected_elements)) + new_elements = set(self.get_selected_elements()) + #if ctrl, set the selected elements to the union - intersection of old and new + if self.get_ctrl_mask(): + self._selected_elements = list( + set.union(old_elements, new_elements) - set.intersection(old_elements, new_elements) + ) + Actions.ELEMENT_SELECT() + + ########################################################################## + ## Event Handlers + ########################################################################## + def handle_mouse_context_press(self, coordinate, event): + """ + The context mouse button was pressed: + If no elements were selected, perform re-selection at this coordinate. + Then, show the context menu at the mouse click location. + """ + selections = self.what_is_selected(coordinate) + if not set(selections).intersection(self.get_selected_elements()): + self.set_coordinate(coordinate) + self.mouse_pressed = True + self.update_selected_elements() + self.mouse_pressed = False + self._context_menu.popup(None, None, None, event.button, event.time) + + def handle_mouse_selector_press(self, double_click, coordinate): + """ + The selector mouse button was pressed: + Find the selected element. Attempt a new connection if possible. + Open the block params window on a double click. + Update the selection state of the flow graph. + """ + self.press_coor = coordinate + self.set_coordinate(coordinate) + self.time = 0 + self.mouse_pressed = True + if double_click: self.unselect() + self.update_selected_elements() + #double click detected, bring up params dialog if possible + if double_click and self.get_selected_block(): + self.mouse_pressed = False + Actions.BLOCK_PARAM_MODIFY() + + def handle_mouse_selector_release(self, coordinate): + """ + The selector mouse button was released: + Update the state, handle motion (dragging). + And update the selected flowgraph elements. + """ + self.set_coordinate(coordinate) + self.time = 0 + self.mouse_pressed = False + if self.element_moved: + Actions.BLOCK_MOVE() + self.element_moved = False + self.update_selected_elements() + + def handle_mouse_motion(self, coordinate): + """ + The mouse has moved, respond to mouse dragging. + Move a selected element to the new coordinate. + Auto-scroll the scroll bars at the boundaries. + """ + #to perform a movement, the mouse must be pressed + # (no longer checking pending events via gtk.events_pending() - always true in Windows) + if not self.mouse_pressed: return + #perform autoscrolling + width, height = self.get_size() + x, y = coordinate + h_adj = self.get_scroll_pane().get_hadjustment() + v_adj = self.get_scroll_pane().get_vadjustment() + for pos, length, adj, adj_val, adj_len in ( + (x, width, h_adj, h_adj.get_value(), h_adj.page_size), + (y, height, v_adj, v_adj.get_value(), v_adj.page_size), + ): + #scroll if we moved near the border + if pos-adj_val > adj_len-SCROLL_PROXIMITY_SENSITIVITY and adj_val+SCROLL_DISTANCE < length-adj_len: + adj.set_value(adj_val+SCROLL_DISTANCE) + adj.emit('changed') + elif pos-adj_val < SCROLL_PROXIMITY_SENSITIVITY: + 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(): + Actions.ELEMENT_DELETE() + #move the selected elements and record the new coordinate + X, Y = self.get_coordinate() + if not self.get_ctrl_mask(): self.move_selected((int(x - X), int(y - Y))) + self.set_coordinate((x, y)) + #queue draw for animation + self.queue_draw() diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py new file mode 100644 index 000000000..1dc02dabb --- /dev/null +++ b/grc/gui/MainWindow.py @@ -0,0 +1,327 @@ +""" +Copyright 2008, 2009, 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 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 + +MAIN_WINDOW_TITLE_TMPL = """\ +#if not $saved +*#slurp +#end if +#if $basename +$basename#slurp +#else +$new_flowgraph_title#slurp +#end if +#if $read_only + (read only)#slurp +#end if +#if $dirname + - $dirname#slurp +#end if + - $platform_name#slurp +""" + +PAGE_TITLE_MARKUP_TMPL = """\ +#set $foreground = $saved and 'black' or 'red' +<span foreground="$foreground">$encode($title or $new_flowgraph_title)</span>#slurp +#if $read_only + (ro)#slurp +#end if +""" + +############################################################ +# Main window +############################################################ + +class MainWindow(gtk.Window): + """The topmost window with menus, the tool bar, and other major windows.""" + + def __init__(self, platform): + """ + MainWindow contructor + Setup the menu, toolbar, flowgraph editor notebook, block selection window... + """ + self._platform = platform + #setup window + gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) + vbox = gtk.VBox() + self.hpaned = gtk.HPaned() + self.add(vbox) + #create the menu bar and toolbar + self.add_accel_group(Actions.get_accel_group()) + vbox.pack_start(Bars.MenuBar(), False) + vbox.pack_start(Bars.Toolbar(), False) + vbox.pack_start(self.hpaned) + #create the notebook + self.notebook = gtk.Notebook() + self.page_to_be_closed = None + self.current_page = None + self.notebook.set_show_border(False) + self.notebook.set_scrollable(True) #scroll arrows for page tabs + self.notebook.connect('switch-page', self._handle_page_change) + #setup containers + self.flow_graph_vpaned = gtk.VPaned() + #flow_graph_box.pack_start(self.scrolled_window) + self.flow_graph_vpaned.pack1(self.notebook) + self.hpaned.pack1(self.flow_graph_vpaned) + self.btwin = BlockTreeWindow(platform, self.get_flow_graph); + self.hpaned.pack2(self.btwin, False) #dont allow resize + #create the reports window + self.text_display = TextDisplay() + #house the reports in a scrolled window + self.reports_scrolled_window = gtk.ScrolledWindow() + self.reports_scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + self.reports_scrolled_window.add_with_viewport(self.text_display) + self.reports_scrolled_window.set_size_request(-1, DEFAULT_REPORTS_WINDOW_WIDTH) + self.flow_graph_vpaned.pack2(self.reports_scrolled_window, False) #dont allow resize + #load preferences and show the main window + Preferences.load(platform) + self.resize(*Preferences.main_window_size()) + self.flow_graph_vpaned.set_position(Preferences.reports_window_position()) + self.hpaned.set_position(Preferences.blocks_window_position()) + self.show_all() + + ############################################################ + # Event Handlers + ############################################################ + + def _quit(self, window, event): + """ + Handle the delete event from the main window. + Generated by pressing X to close, alt+f4, or right click+close. + This method in turns calls the state handler to quit. + @return true + """ + Actions.APPLICATION_QUIT() + return True + + def _handle_page_change(self, notebook, page, page_num): + """ + Handle a page change. When the user clicks on a new tab, + reload the flow graph to update the vars window and + call handle states (select nothing) to update the buttons. + @param notebook the notebook + @param page new page + @param page_num new page number + """ + self.current_page = self.notebook.get_nth_page(page_num) + Messages.send_page_switch(self.current_page.get_file_path()) + Actions.PAGE_CHANGE() + + ############################################################ + # Report Window + ############################################################ + + def add_report_line(self, line): + """ + Place line at the end of the text buffer, then scroll its window all the way down. + @param line the new text + """ + self.text_display.insert(line) + vadj = self.reports_scrolled_window.get_vadjustment() + vadj.set_value(vadj.upper) + vadj.emit('changed') + + ############################################################ + # Pages: create and close + ############################################################ + + def new_page(self, file_path='', show=False): + """ + Create a new notebook page. + Set the tab to be selected. + @param file_path optional file to load into the flow graph + @param show true if the page should be shown after loading + """ + #if the file is already open, show the open page and return + if file_path and file_path in self._get_files(): #already open + page = self.notebook.get_nth_page(self._get_files().index(file_path)) + self._set_page(page) + return + try: #try to load from file + if file_path: Messages.send_start_load(file_path) + flow_graph = self._platform.get_new_flow_graph() + flow_graph.grc_file_path = file_path; + #print flow_graph + page = NotebookPage( + self, + flow_graph=flow_graph, + file_path=file_path, + ) + if file_path: Messages.send_end_load() + except Exception, e: #return on failure + Messages.send_fail_load(e) + if isinstance(e, KeyError) and str(e) == "'options'": + # This error is unrecoverable, so crash gracefully + exit(-1) + return + #add this page to the notebook + self.notebook.append_page(page, page.get_tab()) + try: self.notebook.set_tab_reorderable(page, True) + except: pass #gtk too old + self.notebook.set_tab_label_packing(page, False, False, gtk.PACK_START) + #only show if blank or manual + if not file_path or show: self._set_page(page) + + def close_pages(self): + """ + Close all the pages in this notebook. + @return true if all closed + """ + open_files = filter(lambda file: file, self._get_files()) #filter blank files + open_file = self.get_page().get_file_path() + #close each page + for page in self._get_pages(): + self.page_to_be_closed = page + self.close_page(False) + if self.notebook.get_n_pages(): return False + #save state before closing + Preferences.files_open(open_files) + Preferences.file_open(open_file) + Preferences.main_window_size(self.get_size()) + Preferences.reports_window_position(self.flow_graph_vpaned.get_position()) + Preferences.blocks_window_position(self.hpaned.get_position()) + Preferences.save() + return True + + def close_page(self, ensure=True): + """ + Close the current page. + If the notebook becomes empty, and ensure is true, + call new page upon exit to ensure that at least one page exists. + @param ensure boolean + """ + if not self.page_to_be_closed: self.page_to_be_closed = self.get_page() + #show the page if it has an executing flow graph or is unsaved + if self.page_to_be_closed.get_proc() or not self.page_to_be_closed.get_saved(): + self._set_page(self.page_to_be_closed) + #unsaved? ask the user + if not self.page_to_be_closed.get_saved() and self._save_changes(): + Actions.FLOW_GRAPH_SAVE() #try to save + if not self.page_to_be_closed.get_saved(): #still unsaved? + self.page_to_be_closed = None #set the page to be closed back to None + return + #stop the flow graph if executing + if self.page_to_be_closed.get_proc(): Actions.FLOW_GRAPH_KILL() + #remove the page + self.notebook.remove_page(self.notebook.page_num(self.page_to_be_closed)) + if ensure and self.notebook.get_n_pages() == 0: self.new_page() #no pages, make a new one + self.page_to_be_closed = None #set the page to be closed back to None + + ############################################################ + # Misc + ############################################################ + + def update(self): + """ + Set the title of the main window. + Set the titles on the page tabs. + Show/hide the reports window. + @param title the window title + """ + gtk.Window.set_title(self, Utils.parse_template(MAIN_WINDOW_TITLE_TMPL, + basename=os.path.basename(self.get_page().get_file_path()), + dirname=os.path.dirname(self.get_page().get_file_path()), + 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(), + ) + ) + #set tab titles + for page in self._get_pages(): page.set_markup( + Utils.parse_template(PAGE_TITLE_MARKUP_TMPL, + #get filename and strip out file extension + title=os.path.splitext(os.path.basename(page.get_file_path()))[0], + read_only=page.get_read_only(), saved=page.get_saved(), + new_flowgraph_title=NEW_FLOGRAPH_TITLE, + ) + ) + #show/hide notebook tabs + self.notebook.set_show_tabs(len(self._get_pages()) > 1) + + def get_page(self): + """ + Get the selected page. + @return the selected page + """ + return self.current_page + + def get_flow_graph(self): + """ + Get the selected flow graph. + @return the selected flow graph + """ + return self.get_page().get_flow_graph() + + def get_focus_flag(self): + """ + Get the focus flag from the current page. + @return the focus flag + """ + return self.get_page().get_drawing_area().get_focus_flag() + + ############################################################ + # Helpers + ############################################################ + + def _set_page(self, page): + """ + Set the current page. + @param page the page widget + """ + self.current_page = page + self.notebook.set_current_page(self.notebook.page_num(self.current_page)) + + def _save_changes(self): + """ + Save changes to flow graph? + @return true if yes + """ + return MessageDialogHelper( + gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, 'Unsaved Changes!', + 'Would you like to save changes before closing?' + ) == gtk.RESPONSE_YES + + def _get_files(self): + """ + Get the file names for all the pages, in order. + @return list of file paths + """ + return map(lambda page: page.get_file_path(), self._get_pages()) + + def _get_pages(self): + """ + Get a list of all pages in the notebook. + @return list of pages + """ + return [self.notebook.get_nth_page(page_num) for page_num in range(self.notebook.get_n_pages())] diff --git a/grc/gui/Messages.py b/grc/gui/Messages.py new file mode 100644 index 000000000..e98e897aa --- /dev/null +++ b/grc/gui/Messages.py @@ -0,0 +1,104 @@ +""" +Copyright 2007 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 traceback +import sys + +## A list of functions that can receive a message. +MESSENGERS_LIST = list() + +def register_messenger(messenger): + """ + Append the given messenger to the list of messengers. + @param messenger a method thats takes a string + """ + MESSENGERS_LIST.append(messenger) + +def send(message): + """ + Give the message to each of the messengers. + @param message a message string + """ + for messenger in MESSENGERS_LIST: messenger(message) + +#register stdout by default +register_messenger(sys.stdout.write) + +########################################################################### +# Special functions for specific program functionalities +########################################################################### +def send_init(platform): + send("""<<< Welcome to %s %s >>>\n"""%(platform.get_name(), platform.get_version())) + +def send_page_switch(file_path): + send('\nShowing: "%s"\n'%file_path) + +################# functions for loading flow graphs ######################################## +def send_start_load(file_path): + send('\nLoading: "%s"'%file_path + '\n') + +def send_error_load(error): + send('>>> Error: %s\n'%error) + traceback.print_exc() + +def send_end_load(): + send('>>> Done\n') + +def send_fail_load(error): + send('Error: %s\n'%error) + send('>>> Failure\n') + traceback.print_exc() + +################# functions for generating flow graphs ######################################## +def send_start_gen(file_path): + send('\nGenerating: "%s"'%file_path + '\n') + +def send_fail_gen(error): + send('Generate Error: %s\n'%error) + send('>>> Failure\n') + traceback.print_exc() + +################# functions for executing flow graphs ######################################## +def send_start_exec(file_path): + send('\nExecuting: "%s"'%file_path + '\n') + +def send_verbose_exec(verbose): + send(verbose) + +def send_end_exec(): + send('\n>>> Done\n') + +################# functions for saving flow graphs ######################################## +def send_fail_save(file_path): + send('>>> Error: Cannot save: %s\n'%file_path) + +################# functions for connections ######################################## +def send_fail_connection(): + send('>>> Error: Cannot create connection.\n') + +################# functions for preferences ######################################## +def send_fail_load_preferences(prefs_file_path): + send('>>> Error: Cannot load preferences file: "%s"\n'%prefs_file_path) + +def send_fail_save_preferences(prefs_file_path): + send('>>> Error: Cannot save preferences file: "%s"\n'%prefs_file_path) + +################# functions for warning ######################################## +def send_warning(warning): + send('>>> Warning: %s\n'%warning) diff --git a/grc/gui/NotebookPage.py b/grc/gui/NotebookPage.py new file mode 100644 index 000000000..86b6f1513 --- /dev/null +++ b/grc/gui/NotebookPage.py @@ -0,0 +1,187 @@ +""" +Copyright 2008, 2009, 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 pygtk +pygtk.require('2.0') +import gtk +import Actions +from StateCache import StateCache +from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT +from DrawingArea import DrawingArea +import os + +############################################################ +## Notebook Page +############################################################ + +class NotebookPage(gtk.HBox): + """A page in the notebook.""" + + def __init__(self, main_window, flow_graph, file_path=''): + """ + Page constructor. + @param main_window main window + @param file_path path to a flow graph file + """ + self._flow_graph = flow_graph + self.set_proc(None) + #import the file + self.main_window = main_window + self.set_file_path(file_path) + initial_state = flow_graph.get_parent().parse_flow_graph(file_path) + self.state_cache = StateCache(initial_state) + self.set_saved(True) + #import the data to the flow graph + self.get_flow_graph().import_data(initial_state) + #initialize page gui + gtk.HBox.__init__(self, False, 0) + self.show() + #tab box to hold label and close button + self.tab = gtk.HBox(False, 0) + #setup tab label + self.label = gtk.Label() + self.tab.pack_start(self.label, False) + #setup button image + image = gtk.Image() + image.set_from_stock('gtk-close', gtk.ICON_SIZE_MENU) + #setup image box + image_box = gtk.HBox(False, 0) + image_box.pack_start(image, True, False, 0) + #setup the button + button = gtk.Button() + button.connect("clicked", self._handle_button) + button.set_relief(gtk.RELIEF_NONE) + button.add(image_box) + #button size + w, h = gtk.icon_size_lookup_for_settings(button.get_settings(), gtk.ICON_SIZE_MENU) + button.set_size_request(w+6, h+6) + self.tab.pack_start(button, False) + self.tab.show_all() + #setup scroll window and drawing area + self.scrolled_window = gtk.ScrolledWindow() + self.scrolled_window.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT) + self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + self.drawing_area = DrawingArea(self.get_flow_graph()) + self.scrolled_window.add_with_viewport(self.get_drawing_area()) + self.pack_start(self.scrolled_window) + #inject drawing area into flow graph + self.get_flow_graph().drawing_area = self.get_drawing_area() + self.show_all() + + def get_drawing_area(self): return self.drawing_area + + def get_generator(self): + """ + Get the generator object for this flow graph. + @return generator + """ + return self.get_flow_graph().get_parent().get_generator()( + self.get_flow_graph(), + self.get_file_path(), + ) + + def _handle_button(self, button): + """ + The button was clicked. + Make the current page selected, then close. + @param the button + """ + self.main_window.page_to_be_closed = self + Actions.FLOW_GRAPH_CLOSE() + + def set_markup(self, markup): + """ + Set the markup in this label. + @param markup the new markup text + """ + self.label.set_markup(markup) + + def get_tab(self): + """ + Get the gtk widget for this page's tab. + @return gtk widget + """ + return self.tab + + def get_proc(self): + """ + Get the subprocess for the flow graph. + @return the subprocess object + """ + return self.process + + def set_proc(self, process): + """ + Set the subprocess object. + @param process the new subprocess + """ + self.process = process + + def get_flow_graph(self): + """ + Get the flow graph. + @return the flow graph + """ + return self._flow_graph + + def get_read_only(self): + """ + Get the read-only state of the file. + Always false for empty path. + @return true for read-only + """ + if not self.get_file_path(): return False + return os.path.exists(self.get_file_path()) and \ + not os.access(self.get_file_path(), os.W_OK) + + def get_file_path(self): + """ + Get the file path for the flow graph. + @return the file path or '' + """ + return self.file_path + + def set_file_path(self, file_path=''): + """ + Set the file path, '' for no file path. + @param file_path file path string + """ + if file_path: self.file_path = os.path.abspath(file_path) + else: self.file_path = '' + + def get_saved(self): + """ + Get the saved status for the flow graph. + @return true if saved + """ + return self.saved + + def set_saved(self, saved=True): + """ + Set the saved status. + @param saved boolean status + """ + self.saved = saved + + def get_state_cache(self): + """ + Get the state cache for the flow graph. + @return the state cache + """ + return self.state_cache diff --git a/grc/gui/Param.py b/grc/gui/Param.py new file mode 100644 index 000000000..cb6c663e3 --- /dev/null +++ b/grc/gui/Param.py @@ -0,0 +1,189 @@ +""" +Copyright 2007-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 Utils +from Element import Element +import pygtk +pygtk.require('2.0') +import gtk +import Colors + +class InputParam(gtk.HBox): + """The base class for an input parameter inside the input parameters dialog.""" + + def __init__(self, param, callback=None): + gtk.HBox.__init__(self) + self.param = param + self._callback = callback + self.label = gtk.Label() #no label, markup is added by set_markup + self.label.set_size_request(150, -1) + self.pack_start(self.label, False) + self.set_markup = lambda m: self.label.set_markup(m) + self.tp = None + #connect events + self.connect('show', self._update_gui) + def set_color(self, color): pass + def set_tooltip_text(self, text): pass + + def _update_gui(self, *args): + """ + Set the markup, color, tooltip, show/hide. + """ + #set the markup + has_cb = \ + hasattr(self.param.get_parent(), 'get_callbacks') and \ + filter(lambda c: self.param.get_key() in c, self.param.get_parent()._callbacks) + self.set_markup(Utils.parse_template(PARAM_LABEL_MARKUP_TMPL, param=self.param, has_cb=has_cb)) + #set the color + self.set_color(self.param.get_color()) + #set the tooltip + self.set_tooltip_text( + Utils.parse_template(TIP_MARKUP_TMPL, param=self.param).strip(), + ) + #show/hide + if self.param.get_hide() == 'all': self.hide_all() + else: self.show_all() + + def _handle_changed(self, *args): + """ + Handle a gui change by setting the new param value, + calling the callback (if applicable), and updating. + """ + #set the new value + self.param.set_value(self.get_text()) + #call the callback + if self._callback: self._callback(*args) + else: self.param.validate() + #gui update + self._update_gui() + +class EntryParam(InputParam): + """Provide an entry box for strings and numbers.""" + + def __init__(self, *args, **kwargs): + InputParam.__init__(self, *args, **kwargs) + self._input = gtk.Entry() + self._input.set_text(self.param.get_value()) + self._input.connect('changed', self._handle_changed) + self.pack_start(self._input, True) + def get_text(self): return self._input.get_text() + def set_color(self, color): + self._input.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) + self._input.modify_text(gtk.STATE_NORMAL, Colors.PARAM_ENTRY_TEXT_COLOR) + def set_tooltip_text(self, text): self._input.set_tooltip_text(text) + +class EnumParam(InputParam): + """Provide an entry box for Enum types with a drop down menu.""" + + def __init__(self, *args, **kwargs): + InputParam.__init__(self, *args, **kwargs) + self._input = gtk.combo_box_new_text() + for option in self.param.get_options(): self._input.append_text(option.get_name()) + self._input.set_active(self.param.get_option_keys().index(self.param.get_value())) + self._input.connect('changed', self._handle_changed) + self.pack_start(self._input, False) + def get_text(self): return self.param.get_option_keys()[self._input.get_active()] + def set_tooltip_text(self, text): self._input.set_tooltip_text(text) + +class EnumEntryParam(InputParam): + """Provide an entry box and drop down menu for Raw Enum types.""" + + def __init__(self, *args, **kwargs): + InputParam.__init__(self, *args, **kwargs) + self._input = gtk.combo_box_entry_new_text() + for option in self.param.get_options(): self._input.append_text(option.get_name()) + try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value())) + except: + self._input.set_active(-1) + self._input.get_child().set_text(self.param.get_value()) + self._input.connect('changed', self._handle_changed) + self._input.get_child().connect('changed', self._handle_changed) + self.pack_start(self._input, False) + def get_text(self): + if self._input.get_active() == -1: return self._input.get_child().get_text() + return self.param.get_option_keys()[self._input.get_active()] + def set_tooltip_text(self, text): + if self._input.get_active() == -1: #custom entry + self._input.get_child().set_tooltip_text(text) + else: self._input.set_tooltip_text(text) + def set_color(self, color): + if self._input.get_active() == -1: #custom entry, use color + self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) + self._input.get_child().modify_text(gtk.STATE_NORMAL, Colors.PARAM_ENTRY_TEXT_COLOR) + else: #from enum, make pale background + self._input.get_child().modify_base(gtk.STATE_NORMAL, Colors.ENTRYENUM_CUSTOM_COLOR) + self._input.get_child().modify_text(gtk.STATE_NORMAL, Colors.PARAM_ENTRY_TEXT_COLOR) + +PARAM_MARKUP_TMPL="""\ +#set $foreground = $param.is_valid() and 'black' or 'red' +<span foreground="$foreground" font_desc="Sans 7.5"><b>$encode($param.get_name()): </b>$encode(repr($param))</span>""" + +PARAM_LABEL_MARKUP_TMPL="""\ +#set $foreground = $param.is_valid() and 'black' or 'red' +#set $underline = $has_cb and 'low' or 'none' +<span underline="$underline" foreground="$foreground" font_desc="Sans 9">$encode($param.get_name())</span>""" + +TIP_MARKUP_TMPL="""\ +######################################## +#def truncate(string) + #set $max_len = 100 + #set $string = str($string) + #if len($string) > $max_len +$('%s...%s'%($string[:$max_len/2], $string[-$max_len/2:]))#slurp + #else +$string#slurp + #end if +#end def +######################################## +Key: $param.get_key() +Type: $param.get_type() +#if $param.is_valid() +Value: $truncate($param.get_evaluated()) +#elif len($param.get_error_messages()) == 1 +Error: $(param.get_error_messages()[0]) +#else +Error: + #for $error_msg in $param.get_error_messages() + * $error_msg + #end for +#end if""" + +class Param(Element): + """The graphical parameter.""" + + def __init__(self): Element.__init__(self) + + def get_input(self, *args, **kwargs): + """ + Get the graphical gtk class to represent this parameter. + An enum requires and combo parameter. + A non-enum with options gets a combined entry/combo parameter. + All others get a standard entry parameter. + @return gtk input class + """ + if self.is_enum(): return EnumParam(self, *args, **kwargs) + if self.get_options(): return EnumEntryParam(self, *args, **kwargs) + return EntryParam(self, *args, **kwargs) + + def get_markup(self): + """ + Get the markup for this param. + @return a pango markup string + """ + return Utils.parse_template(PARAM_MARKUP_TMPL, param=self) diff --git a/grc/gui/Platform.py b/grc/gui/Platform.py new file mode 100644 index 000000000..8bbfaca23 --- /dev/null +++ b/grc/gui/Platform.py @@ -0,0 +1,23 @@ +""" +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 +""" + +from Element import Element + +class Platform(Element): + def __init__(self): Element.__init__(self) diff --git a/grc/gui/Port.py b/grc/gui/Port.py new file mode 100644 index 000000000..2896d04c1 --- /dev/null +++ b/grc/gui/Port.py @@ -0,0 +1,190 @@ +""" +Copyright 2007, 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 +""" + +from Element import Element +from Constants import \ + PORT_SEPARATION, CONNECTOR_EXTENSION_MINIMAL, \ + CONNECTOR_EXTENSION_INCREMENT, \ + PORT_LABEL_PADDING, PORT_MIN_WIDTH +import Utils +import Colors +import pygtk +pygtk.require('2.0') +import gtk + +PORT_MARKUP_TMPL="""\ +<span foreground="black" font_desc="Sans 7.5">$encode($port.get_name())</span>""" + +class Port(Element): + """The graphical port.""" + + def __init__(self): + """ + Port contructor. + Create list of connector coordinates. + """ + Element.__init__(self) + self.connector_coordinates = dict() + + def create_shapes(self): + """Create new areas and labels for the port.""" + Element.create_shapes(self) + #get current rotation + rotation = self.get_rotation() + #get all sibling ports + if self.is_source(): ports = self.get_parent().get_sources() + elif self.is_sink(): ports = self.get_parent().get_sinks() + #get the max width + self.W = max([port.W for port in ports] + [PORT_MIN_WIDTH]) + #get a numeric index for this port relative to its sibling ports + index = ports.index(self) + length = len(ports) + #reverse the order of ports for these rotations + if rotation in (180, 270): index = length-index-1 + offset = (self.get_parent().H - length*self.H - (length-1)*PORT_SEPARATION)/2 + #create areas and connector coordinates + if (self.is_sink() and rotation == 0) or (self.is_source() and rotation == 180): + x = -1*self.W + y = (PORT_SEPARATION+self.H)*index+offset + self.add_area((x, y), (self.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): + x = self.get_parent().W + y = (PORT_SEPARATION+self.H)*index+offset + self.add_area((x, y), (self.W, self.H)) + self._connector_coordinate = (x+1+self.W, y+self.H/2) + elif (self.is_source() and rotation == 90) or (self.is_sink() and rotation == 270): + y = -1*self.W + x = (PORT_SEPARATION+self.H)*index+offset + self.add_area((x, y), (self.H, self.W)) + self._connector_coordinate = (x+self.H/2, y-1) + elif (self.is_sink() and rotation == 90) or (self.is_source() and rotation == 270): + y = self.get_parent().W + x = (PORT_SEPARATION+self.H)*index+offset + self.add_area((x, y), (self.H, self.W)) + self._connector_coordinate = (x+self.H/2, y+1+self.W) + #the connector length + self._connector_length = CONNECTOR_EXTENSION_MINIMAL + CONNECTOR_EXTENSION_INCREMENT*index + + def create_labels(self): + """Create the labels for the socket.""" + Element.create_labels(self) + self._bg_color = Colors.get_color(self.get_color()) + #create the layout + layout = gtk.DrawingArea().create_pango_layout('') + layout.set_markup(Utils.parse_template(PORT_MARKUP_TMPL, port=self)) + self.w, self.h = layout.get_pixel_size() + self.W, self.H = 2*PORT_LABEL_PADDING+self.w, 2*PORT_LABEL_PADDING+self.h + #create the pixmap + pixmap = self.get_parent().get_parent().new_pixmap(self.w, self.h) + gc = pixmap.new_gc() + gc.set_foreground(self._bg_color) + pixmap.draw_rectangle(gc, True, 0, 0, self.w, self.h) + pixmap.draw_layout(gc, 0, 0, layout) + #create vertical and horizontal pixmaps + self.horizontal_label = pixmap + if self.is_vertical(): + self.vertical_label = self.get_parent().get_parent().new_pixmap(self.h, self.w) + Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label) + + def draw(self, gc, window): + """ + Draw the socket with a label. + @param gc the graphics context + @param window the gtk window to draw on + """ + Element.draw( + self, gc, window, bg_color=self._bg_color, + border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or Colors.BORDER_COLOR, + ) + X,Y = self.get_coordinate() + (x,y),(w,h) = self._areas_list[0] #use the first area's sizes to place the labels + if self.is_horizontal(): + window.draw_drawable(gc, self.horizontal_label, 0, 0, x+X+(self.W-self.w)/2, y+Y+(self.H-self.h)/2, -1, -1) + elif self.is_vertical(): + window.draw_drawable(gc, self.vertical_label, 0, 0, x+X+(self.H-self.h)/2, y+Y+(self.W-self.w)/2, -1, -1) + + def get_connector_coordinate(self): + """ + Get the coordinate where connections may attach to. + @return the connector coordinate (x, y) tuple + """ + x,y = self._connector_coordinate + X,Y = self.get_coordinate() + return (x+X, y+Y) + + def get_connector_direction(self): + """ + Get the direction that the socket points: 0,90,180,270. + This is the rotation degree if the socket is an output or + the rotation degree + 180 if the socket is an input. + @return the direction in degrees + """ + if self.is_source(): return self.get_rotation() + elif self.is_sink(): return (self.get_rotation() + 180)%360 + + def get_connector_length(self): + """ + Get the length of the connector. + The connector length increases as the port index changes. + @return the length in pixels + """ + return self._connector_length + + def get_rotation(self): + """ + Get the parent's rotation rather than self. + @return the parent's rotation + """ + return self.get_parent().get_rotation() + + def move(self, delta_coor): + """ + Move the parent rather than self. + @param delta_corr the (delta_x, delta_y) tuple + """ + self.get_parent().move(delta_coor) + + def rotate(self, direction): + """ + Rotate the parent rather than self. + @param direction degrees to rotate + """ + self.get_parent().rotate(direction) + + def get_coordinate(self): + """ + Get the parent's coordinate rather than self. + @return the parents coordinate + """ + return self.get_parent().get_coordinate() + + def set_highlighted(self, highlight): + """ + Set the parent highlight rather than self. + @param highlight true to enable highlighting + """ + self.get_parent().set_highlighted(highlight) + + def is_highlighted(self): + """ + Get the parent's is highlight rather than self. + @return the parent's highlighting status + """ + return self.get_parent().is_highlighted() diff --git a/grc/gui/Preferences.py b/grc/gui/Preferences.py new file mode 100644 index 000000000..1d89920dd --- /dev/null +++ b/grc/gui/Preferences.py @@ -0,0 +1,86 @@ +""" +Copyright 2008 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 ConfigParser +import os + +_platform = None +_config_parser = ConfigParser.ConfigParser() + +def file_extension(): return '.'+_platform.get_key() +def _prefs_file(): return os.path.join(os.path.expanduser('~'), file_extension()) + +def load(platform): + global _platform + _platform = platform + #create sections + _config_parser.add_section('main') + _config_parser.add_section('files_open') + try: _config_parser.read(_prefs_file()) + except: pass +def save(): + try: _config_parser.write(open(_prefs_file(), 'w')) + except: pass + +########################################################################### +# Special methods for specific program functionalities +########################################################################### + +def main_window_size(size=None): + if size is not None: + _config_parser.set('main', 'main_window_width', size[0]) + _config_parser.set('main', 'main_window_height', size[1]) + else: + try: return ( + _config_parser.getint('main', 'main_window_width'), + _config_parser.getint('main', 'main_window_height'), + ) + except: return (1, 1) + +def file_open(file=None): + if file is not None: _config_parser.set('main', 'file_open', file) + else: + try: return _config_parser.get('main', 'file_open') + except: return '' + +def files_open(files=None): + if files is not None: + _config_parser.remove_section('files_open') #clear section + _config_parser.add_section('files_open') + for i, file in enumerate(files): + _config_parser.set('files_open', 'file_open_%d'%i, file) + else: + files = list() + i = 0 + while True: + try: files.append(_config_parser.get('files_open', 'file_open_%d'%i)) + except: return files + i = i + 1 + +def reports_window_position(pos=None): + if pos is not None: _config_parser.set('main', 'reports_window_position', pos) + else: + try: return _config_parser.getint('main', 'reports_window_position') or 1 #greater than 0 + except: return -1 + +def blocks_window_position(pos=None): + if pos is not None: _config_parser.set('main', 'blocks_window_position', pos) + else: + try: return _config_parser.getint('main', 'blocks_window_position') or 1 #greater than 0 + except: return -1 diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py new file mode 100644 index 000000000..cc84fd088 --- /dev/null +++ b/grc/gui/PropsDialog.py @@ -0,0 +1,170 @@ +""" +Copyright 2007, 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 pygtk +pygtk.require('2.0') +import gtk + +from Dialogs import TextDisplay +from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT + +def get_title_label(title): + """ + Get a title label for the params window. + The title will be bold, underlined, and left justified. + @param title the text of the title + @return a gtk object + """ + label = gtk.Label() + label.set_markup('\n<b><span underline="low">%s</span>:</b>\n'%title) + hbox = gtk.HBox() + hbox.pack_start(label, False, False, padding=11) + return hbox + +class PropsDialog(gtk.Dialog): + """ + A dialog to set block parameters, view errors, and view documentation. + """ + + def __init__(self, block): + """ + Properties dialog contructor. + @param block a block instance + """ + self._hash = 0 + LABEL_SPACING = 7 + gtk.Dialog.__init__(self, + title='Properties: %s'%block.get_name(), + buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT), + ) + self._block = block + self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT) + vbox = gtk.VBox() + #Create the scrolled window to hold all the parameters + scrolled_window = gtk.ScrolledWindow() + scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + scrolled_window.add_with_viewport(vbox) + self.vbox.pack_start(scrolled_window, True) + #Params box for block parameters + self._params_box = gtk.VBox() + self._params_box.pack_start(get_title_label('Parameters'), False) + self._input_object_params = list() + #Error Messages for the block + self._error_box = gtk.VBox() + self._error_messages_text_display = TextDisplay() + self._error_box.pack_start(gtk.Label(), False, False, LABEL_SPACING) + self._error_box.pack_start(get_title_label('Error Messages'), False) + self._error_box.pack_start(self._error_messages_text_display, False) + #Docs for the block + self._docs_box = err_box = gtk.VBox() + self._docs_text_display = TextDisplay() + self._docs_box.pack_start(gtk.Label(), False, False, LABEL_SPACING) + self._docs_box.pack_start(get_title_label('Documentation'), False) + self._docs_box.pack_start(self._docs_text_display, False) + #Add the boxes + vbox.pack_start(self._params_box, False) + vbox.pack_start(self._error_box, False) + vbox.pack_start(self._docs_box, False) + #connect events + self.connect('key-press-event', self._handle_key_press) + self.connect('show', self._update_gui) + #show all (performs initial gui update) + self.show_all() + + def _params_changed(self): + """ + Have the params in this dialog changed? + Ex: Added, removed, type change, hide change... + To the props dialog, the hide setting of 'none' and 'part' are identical. + Therfore, the props dialog only cares if the hide setting is/not 'all'. + Make a hash that uniquely represents the params' state. + @return true if changed + """ + old_hash = self._hash + #create a tuple of things from each param that affects the params box + self._hash = hash(tuple([( + hash(param), param.get_type(), param.get_hide() == 'all', + ) for param in self._block.get_params()])) + return self._hash != old_hash + + def _handle_changed(self, *args): + """ + A change occured within a param: + Rewrite/validate the block and update the gui. + """ + #update for the block + self._block.rewrite() + self._block.validate() + self._update_gui() + + def _update_gui(self, *args): + """ + Repopulate the parameters box (if changed). + Update all the input parameters. + Update the error messages box. + Hide the box if there are no errors. + Update the documentation block. + Hide the box if there are no docs. + """ + #update the params box + if self._params_changed(): + #hide params box before changing + self._params_box.hide_all() + #empty the params box + for io_param in list(self._input_object_params): + self._params_box.remove(io_param) + self._input_object_params.remove(io_param) + io_param.destroy() + #repopulate the params box + for param in self._block.get_params(): + if param.get_hide() == 'all': continue + io_param = param.get_input(self._handle_changed) + self._input_object_params.append(io_param) + self._params_box.pack_start(io_param, False) + #show params box with new params + self._params_box.show_all() + #update the errors box + if self._block.is_valid(): self._error_box.hide() + else: self._error_box.show() + messages = '\n\n'.join(self._block.get_error_messages()) + self._error_messages_text_display.set_text(messages) + #update the docs box + if self._block.get_doc(): self._docs_box.show() + else: self._docs_box.hide() + self._docs_text_display.set_text(self._block.get_doc()) + + def _handle_key_press(self, widget, event): + """ + Handle key presses from the keyboard. + Call the ok response when enter is pressed. + @return false to forward the keypress + """ + if event.keyval == gtk.keysyms.Return: + self.response(gtk.RESPONSE_ACCEPT) + return True #handled here + return False #forward the keypress + + def run(self): + """ + Run the dialog and get its response. + @return true if the response was accept + """ + response = gtk.Dialog.run(self) + self.destroy() + return response == gtk.RESPONSE_ACCEPT diff --git a/grc/gui/StateCache.py b/grc/gui/StateCache.py new file mode 100644 index 000000000..3f6b79224 --- /dev/null +++ b/grc/gui/StateCache.py @@ -0,0 +1,92 @@ +""" +Copyright 2007 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 Actions +from Constants import STATE_CACHE_SIZE + +class StateCache(object): + """ + The state cache is an interface to a list to record data/states and to revert to previous states. + States are recorded into the list in a circular fassion by using an index for the current state, + and counters for the range where states are stored. + """ + + def __init__(self, initial_state): + """ + StateCache constructor. + @param initial_state the intial state (nested data) + """ + self.states = [None] * STATE_CACHE_SIZE #fill states + self.current_state_index = 0 + self.num_prev_states = 0 + self.num_next_states = 0 + self.states[0] = initial_state + self.update_actions() + + def save_new_state(self, state): + """ + Save a new state. + Place the new state at the next index and add one to the number of previous states. + @param state the new state + """ + self.current_state_index = (self.current_state_index + 1)%STATE_CACHE_SIZE + self.states[self.current_state_index] = state + self.num_prev_states = self.num_prev_states + 1 + if self.num_prev_states == STATE_CACHE_SIZE: self.num_prev_states = STATE_CACHE_SIZE - 1 + self.num_next_states = 0 + self.update_actions() + + def get_current_state(self): + """ + Get the state at the current index. + @return the current state (nested data) + """ + self.update_actions() + return self.states[self.current_state_index] + + def get_prev_state(self): + """ + Get the previous state and decrement the current index. + @return the previous state or None + """ + if self.num_prev_states > 0: + self.current_state_index = (self.current_state_index + STATE_CACHE_SIZE -1)%STATE_CACHE_SIZE + self.num_next_states = self.num_next_states + 1 + self.num_prev_states = self.num_prev_states - 1 + return self.get_current_state() + return None + + def get_next_state(self): + """ + Get the nest state and increment the current index. + @return the next state or None + """ + if self.num_next_states > 0: + self.current_state_index = (self.current_state_index + 1)%STATE_CACHE_SIZE + self.num_next_states = self.num_next_states - 1 + self.num_prev_states = self.num_prev_states + 1 + return self.get_current_state() + return None + + def update_actions(self): + """ + Update the undo and redo actions based on the number of next and prev states. + """ + Actions.FLOW_GRAPH_REDO.set_sensitive(self.num_next_states != 0) + Actions.FLOW_GRAPH_UNDO.set_sensitive(self.num_prev_states != 0) diff --git a/grc/gui/Utils.py b/grc/gui/Utils.py new file mode 100644 index 000000000..bb19ed3d9 --- /dev/null +++ b/grc/gui/Utils.py @@ -0,0 +1,90 @@ +""" +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 Constants import POSSIBLE_ROTATIONS +from Cheetah.Template import Template +import pygtk +pygtk.require('2.0') +import gtk +import gobject + +def rotate_pixmap(gc, src_pixmap, dst_pixmap, angle=gtk.gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE): + """ + Load the destination pixmap with a rotated version of the source pixmap. + The source pixmap will be loaded into a pixbuf, rotated, and drawn to the destination pixmap. + The pixbuf is a client-side drawable, where a pixmap is a server-side drawable. + @param gc the graphics context + @param src_pixmap the source pixmap + @param dst_pixmap the destination pixmap + @param angle the angle to rotate by + """ + width, height = src_pixmap.get_size() + pixbuf = gtk.gdk.Pixbuf( + colorspace=gtk.gdk.COLORSPACE_RGB, + has_alpha=False, bits_per_sample=8, + width=width, height=height, + ) + pixbuf.get_from_drawable(src_pixmap, src_pixmap.get_colormap(), 0, 0, 0, 0, -1, -1) + pixbuf = pixbuf.rotate_simple(angle) + dst_pixmap.draw_pixbuf(gc, pixbuf, 0, 0, 0, 0) + +def get_rotated_coordinate(coor, rotation): + """ + Rotate the coordinate by the given rotation. + @param coor the coordinate x, y tuple + @param rotation the angle in degrees + @return the rotated coordinates + """ + #handles negative angles + rotation = (rotation + 360)%360 + if rotation not in POSSIBLE_ROTATIONS: + raise ValueError('unusable rotation angle "%s"'%str(rotation)) + #determine the number of degrees to rotate + cos_r, sin_r = { + 0: (1, 0), + 90: (0, 1), + 180: (-1, 0), + 270: (0, -1), + }[rotation] + x, y = coor + return (x*cos_r + y*sin_r, -x*sin_r + y*cos_r) + +def get_angle_from_coordinates((x1,y1), (x2,y2)): + """ + Given two points, calculate the vector direction from point1 to point2, directions are multiples of 90 degrees. + @param (x1,y1) the coordinate of point 1 + @param (x2,y2) the coordinate of point 2 + @return the direction in degrees + """ + if y1 == y2:#0 or 180 + if x2 > x1: return 0 + else: return 180 + else:#90 or 270 + if y2 > y1: return 270 + else: return 90 + +def parse_template(tmpl_str, **kwargs): + """ + Parse the template string with the given args. + Pass in the xml encode method for pango escape chars. + @param tmpl_str the template as a string + @return a string of the parsed template + """ + kwargs['encode'] = gobject.markup_escape_text + return str(Template(tmpl_str, kwargs)) diff --git a/grc/gui/__init__.py b/grc/gui/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/grc/gui/__init__.py @@ -0,0 +1 @@ + diff --git a/grc/python/Block.py b/grc/python/Block.py new file mode 100644 index 000000000..2c334dfc2 --- /dev/null +++ b/grc/python/Block.py @@ -0,0 +1,180 @@ +""" +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 .. base.Block import Block as _Block +from .. gui.Block import Block as _GUIBlock +import extract_docs + +class Block(_Block, _GUIBlock): + + def is_virtual_sink(self): return self.get_key() == 'virtual_sink' + def is_virtual_source(self): return self.get_key() == 'virtual_source' + + ##for make source to keep track of indexes + _source_count = 0 + ##for make sink to keep track of indexes + _sink_count = 0 + + def __init__(self, flow_graph, n): + """ + Make a new block from nested data. + @param flow graph the parent element + @param n the nested odict + @return block a new block + """ + #grab the data + self._doc = n.find('doc') or '' + 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._throttle = n.find('throttle') or '' + #build the block + _Block.__init__( + self, + flow_graph=flow_graph, + n=n, + ) + _GUIBlock.__init__(self) + + def throttle(self): return bool(self._throttle) + + 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) + + def rewrite(self): + """ + Add and remove ports to adjust for the nports. + """ + _Block.rewrite(self) + + def rectify(ports): + #restore integer contiguity after insertion + #rectify the port names with the index + for i, port in enumerate(ports): + port._key = str(i) + port._name = port._n['name'] + if len(ports) > 1: port._name += str(i) + + def insert_port(get_ports, get_port, key): + prev_port = get_port(str(int(key)-1)) + get_ports().insert( + get_ports().index(prev_port)+1, + prev_port.copy(new_key=key), + ) + rectify(get_ports()) + + def remove_port(get_ports, get_port, key): + port = get_port(key) + for connection in port.get_connections(): + self.get_parent().remove_element(connection) + get_ports().remove(port) + rectify(get_ports()) + + #adjust nports + for get_ports, get_port in ( + (self.get_sources, self.get_source), + (self.get_sinks, self.get_sink), + ): + master_ports = filter(lambda p: p.get_nports(), get_ports()) + for i, master_port in enumerate(master_ports): + nports = master_port.get_nports() + index_first = get_ports().index(master_port) + try: index_last = get_ports().index(master_ports[i+1]) + except IndexError: index_last = len(get_ports()) + num_ports = index_last - index_first + #do nothing if nports is already num ports + if nports == num_ports: continue + #remove excess ports and connections + if nports < num_ports: + for key in reversed(map(str, range(index_first+nports, index_first+num_ports))): + remove_port(get_ports, get_port, key) + continue + #add more ports + if nports > num_ports: + for key in map(str, range(index_first+num_ports, index_first+nports)): + insert_port(get_ports, get_port, key) + continue + + def port_controller_modify(self, direction): + """ + Change the port controller. + @param direction +1 or -1 + @return 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): + doc = self._doc.strip('\n').replace('\\\n', '') + #merge custom doc with doxygen docs + return '\n'.join([doc, extract_docs.extract(self.get_key())]).strip('\n') + + def get_category(self): + return _Block.get_category(self) + + def get_imports(self): + """ + Resolve all import statements. + Split each import statement at newlines. + Combine all import statments into a list. + Filter empty imports. + @return a list of import statements + """ + return filter(lambda i: i, sum(map(lambda i: self.resolve_dependencies(i).split('\n'), self._imports), [])) + + def get_make(self): return self.resolve_dependencies(self._make) + def get_var_make(self): return self.resolve_dependencies(self._var_make) + + def get_callbacks(self): + """ + Get a list of function callbacks for this block. + @return 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) diff --git a/grc/python/CMakeLists.txt b/grc/python/CMakeLists.txt new file mode 100644 index 000000000..4832dd897 --- /dev/null +++ b/grc/python/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright 2011 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. + +######################################################################## +GR_PYTHON_INSTALL(FILES + convert_hier.py + expr_utils.py + extract_docs.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 + COMPONENT "grc" +) + +install(FILES + block.dtd + default_flow_graph.grc + flow_graph.tmpl + DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/python + COMPONENT "grc" +) diff --git a/grc/python/Connection.py b/grc/python/Connection.py new file mode 100644 index 000000000..341dd2d82 --- /dev/null +++ b/grc/python/Connection.py @@ -0,0 +1,46 @@ +""" +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.Element import Element +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_message(self): + return self.get_source().get_type() == self.get_sink().get_type() == 'message' + + def validate(self): + """ + Validate the connections. + The ports must match in io size. + """ + Element.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/Constants.py b/grc/python/Constants.py new file mode 100644 index 000000000..b8dc9a96a --- /dev/null +++ b/grc/python/Constants.py @@ -0,0 +1,95 @@ +""" +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 stat +from gnuradio import gr + +_gr_prefs = gr.prefs() + +#setup paths +PATH_SEP = {'/':':', '\\':';'}[os.path.sep] +HIER_BLOCKS_LIB_DIR = os.path.join(os.path.expanduser('~'), '.grc_gnuradio') +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] + +#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_DIR = os.path.dirname(__file__) +FLOW_GRAPH_TEMPLATE = os.path.join(DATA_DIR, 'flow_graph.tmpl') +BLOCK_DTD = os.path.join(DATA_DIR, 'block.dtd') +DEFAULT_FLOW_GRAPH = os.path.join(DATA_DIR, 'default_flow_graph.grc') + +CORE_TYPES = ( #name, key, sizeof, color + ('Complex Float 64', 'fc64', 16, '#CC8C69'), + ('Complex Float 32', 'fc32', 8, '#3399FF'), + ('Complex Integer 64', 'sc64', 16, '#66CC00'), + ('Complex Integer 32', 'sc32', 8, '#33cc66'), + ('Complex Integer 16', 'sc16', 4, '#cccc00'), + ('Complex Integer 8', 'sc8', 2, '#cc00cc'), + ('Float 64', 'f64', 8, '#66CCCC'), + ('Float 32', 'f32', 4, '#FF8C69'), + ('Integer 64', 's64', 8, '#99FF33'), + ('Integer 32', 's32', 4, '#00FF99'), + ('Integer 16', 's16', 2, '#FFFF66'), + ('Integer 8', 's8', 1, '#FF66FF'), + ('Message Queue', 'msg', 0, '#777777'), + ('Async Message', 'message', 0, '#C0C0C0'), + ('Wildcard', '', 0, '#FFFFFF'), +) + +ALIAS_TYPES = { + 'complex' : (8, '#3399FF'), + 'float' : (4, '#FF8C69'), + 'int' : (4, '#00FF99'), + 'short' : (2, '#FFFF66'), + 'byte' : (1, '#FF66FF'), +} + +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 +COMPLEX_COLOR_SPEC = '#3399FF' +FLOAT_COLOR_SPEC = '#FF8C69' +INT_COLOR_SPEC = '#00FF99' +SHORT_COLOR_SPEC = '#FFFF66' +BYTE_COLOR_SPEC = '#FF66FF' +COMPLEX_VECTOR_COLOR_SPEC = '#3399AA' +FLOAT_VECTOR_COLOR_SPEC = '#CC8C69' +INT_VECTOR_COLOR_SPEC = '#00CC99' +SHORT_VECTOR_COLOR_SPEC = '#CCCC33' +BYTE_VECTOR_COLOR_SPEC = '#CC66CC' +ID_COLOR_SPEC = '#DDDDDD' +WILDCARD_COLOR_SPEC = '#FFFFFF' +MSG_COLOR_SPEC = '#777777' diff --git a/grc/python/FlowGraph.py b/grc/python/FlowGraph.py new file mode 100644 index 000000000..376c2e337 --- /dev/null +++ b/grc/python/FlowGraph.py @@ -0,0 +1,163 @@ +""" +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 expr_utils +from .. base.FlowGraph import FlowGraph as _FlowGraph +from .. gui.FlowGraph import FlowGraph as _GUIFlowGraph +import re + +_variable_matcher = re.compile('^(variable\w*)$') +_parameter_matcher = re.compile('^(parameter)$') + +class FlowGraph(_FlowGraph, _GUIFlowGraph): + + def __init__(self, **kwargs): + _FlowGraph.__init__(self, **kwargs) + _GUIFlowGraph.__init__(self) + self._eval_cache = dict() + + def _eval(self, code, namespace, namespace_hash): + """ + Evaluate the code with the given namespace. + @param code a string with python code + @param namespace a dict representing the namespace + @param namespace_hash a unique hash for the namespace + @return 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_io_signaturev(self, direction): + """ + Get a list of io signatures for this flow graph. + @param direction a string of 'in' or 'out' + @return a list of dicts with: type, label, vlen, size + """ + sorted_pads = { + 'in': self.get_pad_sources(), + 'out': self.get_pad_sinks(), + }[direction] + # we only want stream ports + sorted_pads = filter(lambda b: b.get_param('type').get_evaluated() != 'message', sorted_pads); + #load io signature + return [{ + 'label': str(pad.get_param('label').get_evaluated()), + 'type': str(pad.get_param('type').get_evaluated()), + 'vlen': str(pad.get_param('vlen').get_evaluated()), + 'size': pad.get_param('type').get_opt('size'), + 'optional': bool(pad.get_param('optional').get_evaluated()), + } for pad in sorted_pads] + + def get_pad_sources(self): + """ + Get a list of pad source blocks sorted by id order. + @return 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. + @return 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_msg_pad_sources(self): + ps = self.get_pad_sources(); + return filter(lambda b: b.get_param('type').get_evaluated() == 'message', ps); + + def get_msg_pad_sinks(self): + ps = self.get_pad_sinks(); + return filter(lambda b: b.get_param('type').get_evaluated() == 'message', ps); + + def get_imports(self): + """ + Get a set of all import statments in this flow graph namespace. + @return 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. + @return a sorted list of variable blocks in order of dependency (indep -> dep) + """ + variables = filter(lambda b: _variable_matcher.match(b.get_key()), self.get_enabled_blocks()) + return expr_utils.sort_objects(variables, lambda v: v.get_id(), lambda v: v.get_var_make()) + + def get_parameters(self): + """ + Get a list of all paramterized variables in this flow graph namespace. + @return a list of paramterized variables + """ + parameters = filter(lambda b: _parameter_matcher.match(b.get_key()), self.get_enabled_blocks()) + return parameters + + def rewrite(self): + """ + Flag the namespace to be renewed. + """ + self._renew_eval_ns = True + _FlowGraph.rewrite(self) + + def evaluate(self, expr): + """ + Evaluate the expression. + @param expr the string expression + @throw Exception bad expression + @return the evaluated data + """ + if self._renew_eval_ns: + self._renew_eval_ns = False + #reload namespace + n = dict() + #load imports + for imp in self.get_imports(): + try: exec imp in n + 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_param('value').to_code(), 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 diff --git a/grc/python/Generator.py b/grc/python/Generator.py new file mode 100644 index 000000000..616ea00fc --- /dev/null +++ b/grc/python/Generator.py @@ -0,0 +1,152 @@ +""" +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 +import subprocess +import tempfile +from Cheetah.Template import Template +import expr_utils +from Constants import \ + TOP_BLOCK_FILE_MODE, HIER_BLOCK_FILE_MODE, \ + HIER_BLOCKS_LIB_DIR, FLOW_GRAPH_TEMPLATE +import convert_hier +from .. gui import Messages + +class Generator(object): + + def __init__(self, flow_graph, file_path): + """ + Initialize the generator object. + Determine the file to generate. + @param flow_graph the flow graph object + @param file_path the path to write the file to + """ + self._flow_graph = flow_graph + self._generate_options = self._flow_graph.get_option('generate_options') + if self._generate_options == 'hb': + self._mode = HIER_BLOCK_FILE_MODE + dirname = HIER_BLOCKS_LIB_DIR + else: + self._mode = TOP_BLOCK_FILE_MODE + dirname = os.path.dirname(file_path) + #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) + + def get_file_path(self): return self._file_path + + def write(self): + #do throttle warning + throttled = any(map(lambda b: b.throttle(), self._flow_graph.get_enabled_blocks())) + if not throttled and self._generate_options != 'hb': + Messages.send_warning('''\ +This flow graph may not have flow control: no audio or usrp blocks found. \ +Add a Misc->Throttle block to your flow graph to avoid CPU congestion.''') + #generate + open(self.get_file_path(), 'w').write(str(self)) + if self._generate_options == 'hb': + #convert hier block to xml wrapper + convert_hier.convert_hier(self._flow_graph, self.get_file_path()) + os.chmod(self.get_file_path(), self._mode) + + def get_popen(self): + """ + Execute this python flow graph. + @return a popen object + """ + #extract the path to the python executable + python_exe = sys.executable + + #when using wx gui on mac os, execute with pythonw + #using pythonw is not necessary anymore, disabled below + #if self._generate_options == 'wx_gui' and 'darwin' in sys.platform.lower(): + # python_exe = 'pythonw' + + #setup the command args to run + cmds = [python_exe, '-u', self.get_file_path()] #-u is unbuffered stdio + + #when in no gui mode on linux, use an xterm (looks nice) + if self._generate_options == 'no_gui' and 'linux' in sys.platform.lower(): + cmds = ['xterm', '-e'] + cmds + + p = subprocess.Popen(args=cmds, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False, universal_newlines=True) + return p + + def __str__(self): + """ + Convert the flow graph to python code. + @return a string of python code + """ + title = self._flow_graph.get_option('title') or self._flow_graph.get_option('id').replace('_', ' ').title() + imports = self._flow_graph.get_imports() + variables = self._flow_graph.get_variables() + parameters = self._flow_graph.get_parameters() + #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 + except: pass + try: code += block.get_param('gui_hint').get_value() #newer gui markup w/ qtgui + except: pass + return code + blocks = expr_utils.sort_objects( + self._flow_graph.get_enabled_blocks(), + lambda b: b.get_id(), _get_block_sort_text + ) + #list of regular blocks (all blocks minus the special ones) + blocks = filter(lambda b: b not in (imports + parameters), blocks) + #list of connections where each endpoint is enabled + connections = filter(lambda c: not (c.is_msg() or c.is_message()), self._flow_graph.get_enabled_connections()) + messages = filter(lambda c: c.is_msg(), self._flow_graph.get_enabled_connections()) + messages2 = filter(lambda c: c.is_message(), self._flow_graph.get_enabled_connections()) + #list of variable names + var_ids = [var.get_id() for var in parameters + variables] + #prepend self. + replace_dict = dict([(var_id, 'self.%s'%var_id) for var_id in var_ids]) + #list of callbacks + callbacks = [ + expr_utils.expr_replace(cb, replace_dict) + for cb in sum([block.get_callbacks() for block in self._flow_graph.get_enabled_blocks()], []) + ] + #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 + namespace = { + 'title': title, + 'imports': imports, + 'flow_graph': self._flow_graph, + 'variables': variables, + 'parameters': parameters, + 'blocks': blocks, + 'connections': connections, + 'messages': messages, + 'messages2': messages2, + 'generate_options': self._generate_options, + 'var_id2cbs': var_id2cbs, + } + #build the template + t = Template(open(FLOW_GRAPH_TEMPLATE, 'r').read(), namespace) + return str(t) diff --git a/grc/python/Param.py b/grc/python/Param.py new file mode 100644 index 000000000..2caca4802 --- /dev/null +++ b/grc/python/Param.py @@ -0,0 +1,458 @@ +""" +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 .. base.Param import Param as _Param +from .. gui.Param import Param as _GUIParam +from .. gui.Param import EntryParam +import Constants +import numpy +import os +import pygtk +pygtk.require('2.0') +import gtk +from gnuradio import eng_notation +import re +from gnuradio import gr + +_check_id_matcher = re.compile('^[a-z|A-Z]\w*$') +_show_id_matcher = re.compile('^(variable\w*|parameter|options|notebook)$') + +class FileParam(EntryParam): + """Provide an entry box for filename and a button to browse for a file.""" + + def __init__(self, *args, **kwargs): + EntryParam.__init__(self, *args, **kwargs) + input = gtk.Button('...') + input.connect('clicked', self._handle_clicked) + self.pack_start(input, False) + + def _handle_clicked(self, widget=None): + """ + If the button was clicked, open a file dialog in open/save format. + Replace the text in the entry with the new filename from the file dialog. + """ + #get the paths + file_path = self.param.is_valid() and self.param.get_evaluated() or '' + (dirname, basename) = os.path.isfile(file_path) and os.path.split(file_path) or (file_path, '') + if not os.path.exists(dirname): dirname = os.getcwd() #fix bad paths + #build the dialog + if self.param.get_type() == 'file_open': + file_dialog = gtk.FileChooserDialog('Open a Data File...', None, + gtk.FILE_CHOOSER_ACTION_OPEN, ('gtk-cancel',gtk.RESPONSE_CANCEL,'gtk-open',gtk.RESPONSE_OK)) + elif self.param.get_type() == 'file_save': + file_dialog = gtk.FileChooserDialog('Save a Data File...', None, + gtk.FILE_CHOOSER_ACTION_SAVE, ('gtk-cancel',gtk.RESPONSE_CANCEL, 'gtk-save',gtk.RESPONSE_OK)) + file_dialog.set_do_overwrite_confirmation(True) + file_dialog.set_current_name(basename) #show the current filename + file_dialog.set_current_folder(dirname) #current directory + file_dialog.set_select_multiple(False) + file_dialog.set_local_only(True) + if gtk.RESPONSE_OK == file_dialog.run(): #run the dialog + file_path = file_dialog.get_filename() #get the file path + self._input.set_text(file_path) + self._handle_changed() + file_dialog.destroy() #destroy the dialog + +#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__) +#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 +COMPLEX_TYPES = tuple(COMPLEX_TYPES + REAL_TYPES + INT_TYPES) +REAL_TYPES = tuple(REAL_TYPES + INT_TYPES) +INT_TYPES = tuple(INT_TYPES) + +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', 'int', + 'complex_vector', 'real_vector', 'int_vector', + 'hex', 'string', 'bool', + 'file_open', 'file_save', + 'id', 'stream_id', + 'grid_pos', 'notebook', 'gui_hint', + 'import', + ) + + def __repr__(self): + """ + Get the repr (nice string format) for this param. + @return 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() + ################################################## + # display logic for numbers + ################################################## + def num_to_str(num): + 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) + ################################################## + # 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_input(self, *args, **kwargs): + if self.get_type() in ('file_open', 'file_save'): return FileParam(self, *args, **kwargs) + return _GUIParam.get_input(self, *args, **kwargs) + + def get_color(self): + """ + Get the color that represents this param's type. + @return a hex color code. + """ + try: + return { + #number types + 'complex': Constants.COMPLEX_COLOR_SPEC, + 'real': 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, + '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. + @return 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. + @return evaluated type + """ + self._init = True + self._lisitify_flag = False + self._stringify_flag = False + self._hostage_cells = list() + def eval_string(v): + try: + e = self.get_parent().get_parent().evaluate(v) + if isinstance(e, str): return e + raise Exception #want to stringify + except: + self._stringify_flag = True + return v + t = self.get_type() + v = self.get_value() + ######################### + # Enum Type + ######################### + if self.is_enum(): return v + ######################### + # Numeric Types + ######################### + elif t in ('raw', 'complex', 'real', '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': + if not isinstance(e, REAL_TYPES): + raise Exception, 'Expression "%s" is invalid for type real.'%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', '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': + 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 real 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'): + #do not check if file/directory exists, that is a runtime issue + e = eval_string(v) + return str(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} + + def gui_hint(ws, w): + if 'layout' in w: ws = ws.replace('addWidget', 'addLayout') + return ws%w + + return lambda w: gui_hint(widget_str, w) + ######################### + # 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. + @return a string representing the code + """ + v = self.get_value() + t = self.get_type() + if t in ('string', 'file_open', 'file_save'): #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', '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. + @param type the specified type + @return 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 new file mode 100644 index 000000000..e036361ff --- /dev/null +++ b/grc/python/Platform.py @@ -0,0 +1,70 @@ +__doc__ = """ +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 +from gnuradio import gr +from .. base.Platform import Platform as _Platform +from .. gui.Platform import Platform as _GUIPlatform +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 +import Constants + +COLORS = [(name, color) for name, key, sizeof, color in Constants.CORE_TYPES] + +class Platform(_Platform, _GUIPlatform): + + def __init__(self): + """ + Make a platform for gnuradio. + """ + #ensure hier dir + if not os.path.exists(HIER_BLOCKS_LIB_DIR): os.mkdir(HIER_BLOCKS_LIB_DIR) + #convert block paths to absolute paths + block_paths = set(map(os.path.abspath, BLOCKS_DIRS)) + #init + _Platform.__init__( + self, + name='GNU Radio Companion', + version=gr.version(), + key='grc', + license=__doc__.strip(), + website='http://gnuradio.org/redmine/wiki/gnuradio/GNURadioCompanion', + block_paths=block_paths, + block_dtd=BLOCK_DTD, + default_flow_graph=DEFAULT_FLOW_GRAPH, + generator=Generator, + colors=COLORS, + ) + _GUIPlatform.__init__(self) + + ############################################## + # Constructors + ############################################## + FlowGraph = _FlowGraph + Connection = _Connection + Block = _Block + Port = _Port + Param = _Param diff --git a/grc/python/Port.py b/grc/python/Port.py new file mode 100644 index 000000000..8cc9e9ad0 --- /dev/null +++ b/grc/python/Port.py @@ -0,0 +1,217 @@ +""" +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 .. 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. + @param block the parent element + @param n the nested odict + @param dir the direction + """ + self._n = n + if n['type'] == 'msg': n['key'] = 'msg' + if n['type'] == 'message': n['key'] = n['name'] + if dir == 'source' and not n.find('key'): + n['key'] = str(block._source_count) + block._source_count += 1 + if dir == 'sink' and not n.find('key'): + n['key'] = str(block._sink_count) + block._sink_count += 1 + #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')) + + 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.') + is_msg = (not self.get_type()) or (self.get_type() == "message") + if not self.is_source() and (not is_msg) and len(self.get_enabled_connections()) > 1: + self.add_error_message('Port has too many connections.') + #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. + """ + _Port.rewrite(self) + 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 = '' + + 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. + @return 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 an integer, return 1. + @return the number of ports or 1 + """ + nports = self.get_parent().resolve_dependencies(self._nports) + #return blank if nports is blank + if not nports: return '' + try: + nports = int(self.get_parent().get_parent().evaluate(nports)) + if 0 < nports: return 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. + @return 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 copy(self, new_key=None): + n = self._n.copy() + #remove nports from the key so the copy cannot be a duplicator + if n.has_key('nports'): n.pop('nports') + if new_key: n['key'] = new_key + return self.__class__(self.get_parent(), n, self._dir) diff --git a/grc/python/__init__.py b/grc/python/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/grc/python/__init__.py @@ -0,0 +1 @@ + diff --git a/grc/python/block.dtd b/grc/python/block.dtd new file mode 100644 index 000000000..292ea06cb --- /dev/null +++ b/grc/python/block.dtd @@ -0,0 +1,57 @@ +<!-- +Copyright 2008 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 +--> +<!-- + gnuradio_python.blocks.dtd + Josh Blum + The document type definition for blocks. + --> +<!-- + Top level element. + A block contains a name, ...parameters list, and list of IO ports. + --> +<!ELEMENT block (name, key, category?, throttle?, import*, var_make?, make, callback*, param*, check*, sink*, source*, doc?, grc_source?)> +<!-- + Sub level elements. + --> +<!ELEMENT param (name, key, value?, type, hide?, option*)> +<!ELEMENT option (name, key, opt*)> +<!ELEMENT sink (name, type, vlen?, nports?, optional?)> +<!ELEMENT source (name, type, vlen?, nports?, optional?)> +<!-- + Bottom level elements. + Character data only. + --> +<!ELEMENT category (#PCDATA)> +<!ELEMENT import (#PCDATA)> +<!ELEMENT doc (#PCDATA)> +<!ELEMENT grc_source (#PCDATA)> +<!ELEMENT name (#PCDATA)> +<!ELEMENT key (#PCDATA)> +<!ELEMENT check (#PCDATA)> +<!ELEMENT opt (#PCDATA)> +<!ELEMENT type (#PCDATA)> +<!ELEMENT hide (#PCDATA)> +<!ELEMENT vlen (#PCDATA)> +<!ELEMENT nports (#PCDATA)> +<!ELEMENT var_make (#PCDATA)> +<!ELEMENT make (#PCDATA)> +<!ELEMENT value (#PCDATA)> +<!ELEMENT callback (#PCDATA)> +<!ELEMENT optional (#PCDATA)> +<!ELEMENT throttle (#PCDATA)> diff --git a/grc/python/convert_hier.py b/grc/python/convert_hier.py new file mode 100644 index 000000000..508ec63b2 --- /dev/null +++ b/grc/python/convert_hier.py @@ -0,0 +1,98 @@ +""" +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 Constants import BLOCK_DTD +from .. base import ParseXML +from .. base import odict + +def convert_hier(flow_graph, python_file): + #extract info from the flow graph + input_sigs = flow_graph.get_io_signaturev('in') + output_sigs = flow_graph.get_io_signaturev('out') + input_msgp = flow_graph.get_msg_pad_sources(); + output_msgp = flow_graph.get_msg_pad_sinks(); + parameters = flow_graph.get_parameters() + block_key = flow_graph.get_option('id') + block_name = flow_graph.get_option('title') or flow_graph.get_option('id').replace('_', ' ').title() + block_category = flow_graph.get_option('category') + block_desc = flow_graph.get_option('description') + block_author = flow_graph.get_option('author') + #build the nested data + block_n = odict() + block_n['name'] = block_name + block_n['key'] = block_key + block_n['category'] = block_category + block_n['import'] = 'execfile("%s")'%python_file + #make data + if parameters: block_n['make'] = '%s(\n\t%s,\n)'%( + block_key, + ',\n\t'.join(['%s=$%s'%(param.get_id(), param.get_id()) for param in parameters]), + ) + else: block_n['make'] = '%s()'%block_key + #callback data + block_n['callback'] = ['set_%s($%s)'%(param.get_id(), param.get_id()) for param in parameters] + #param data + params_n = list() + for param in parameters: + param_n = odict() + param_n['name'] = param.get_param('label').get_value() or param.get_id() + param_n['key'] = param.get_id() + param_n['value'] = param.get_param('value').get_value() + param_n['type'] = 'raw' + params_n.append(param_n) + block_n['param'] = params_n + #sink data stream ports + block_n['sink'] = list() + for input_sig in input_sigs: + sink_n = odict() + sink_n['name'] = input_sig['label'] + sink_n['type'] = input_sig['type'] + sink_n['vlen'] = input_sig['vlen'] + if input_sig['optional']: sink_n['optional'] = '1' + block_n['sink'].append(sink_n) + #sink data msg ports + for input_sig in input_msgp: + sink_n = odict() + sink_n['name'] = input_sig.get_param("label").get_value(); + sink_n['type'] = "message" + sink_n['optional'] = input_sig.get_param("optional").get_value(); + block_n['sink'].append(sink_n) + #source data stream ports + block_n['source'] = list() + for output_sig in output_sigs: + source_n = odict() + source_n['name'] = output_sig['label'] + source_n['type'] = output_sig['type'] + source_n['vlen'] = output_sig['vlen'] + if output_sig['optional']: source_n['optional'] = '1' + block_n['source'].append(source_n) + #source data msg ports + for output_sig in output_msgp: + source_n = odict() + source_n['name'] = output_sig.get_param("label").get_value(); + source_n['type'] = "message" + source_n['optional'] = output_sig.get_param("optional").get_value(); + block_n['source'].append(source_n) + #doc data + block_n['doc'] = "%s\n%s\n%s"%(block_author, block_desc, python_file) + block_n['grc_source'] = "%s"%(flow_graph.grc_file_path) + #write the block_n to file + xml_file = python_file + '.xml' + ParseXML.to_file({'block': block_n}, xml_file) + ParseXML.validate_dtd(xml_file, BLOCK_DTD) diff --git a/grc/python/default_flow_graph.grc b/grc/python/default_flow_graph.grc new file mode 100644 index 000000000..dea26f3a5 --- /dev/null +++ b/grc/python/default_flow_graph.grc @@ -0,0 +1,43 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Default Flow Graph: +## include an options block and a variable for sample rate +################################################### + --> +<flow_graph> + <block> + <key>options</key> + <param> + <key>id</key> + <value>top_block</value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</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>value</key> + <value>32000</value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 170)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> +</flow_graph> diff --git a/grc/python/expr_utils.py b/grc/python/expr_utils.py new file mode 100644 index 000000000..a2e56eedf --- /dev/null +++ b/grc/python/expr_utils.py @@ -0,0 +1,153 @@ +""" +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 string +VAR_CHARS = string.letters + string.digits + '_' + +class graph(object): + """ + Simple graph structure held in a dictionary. + """ + + def __init__(self): self._graph = dict() + + def __str__(self): return str(self._graph) + + def add_node(self, node_key): + if self._graph.has_key(node_key): return + self._graph[node_key] = set() + + def remove_node(self, node_key): + if not self._graph.has_key(node_key): return + for edges in self._graph.values(): + if node_key in edges: edges.remove(node_key) + self._graph.pop(node_key) + + def add_edge(self, src_node_key, dest_node_key): + self._graph[src_node_key].add(dest_node_key) + + 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_edges(self, node_key): return self._graph[node_key] + +def expr_split(expr): + """ + Split up an expression by non alphanumeric characters, including underscore. + Leave strings in-tact. + #TODO ignore escaped quotes, use raw strings. + @param expr an expression string + @return a list of string tokens that form expr + """ + toks = list() + tok = '' + quote = '' + for char in expr: + if quote or char in VAR_CHARS: + if char == quote: quote = '' + tok += char + elif char in ("'", '"'): + toks.append(tok) + tok = char + quote = char + else: + toks.append(tok) + toks.append(char) + tok = '' + 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. + @param expr an expression string + @param replace_dict a dict of find:replace + @return a new expression with the prepend + """ + expr_splits = expr_split(expr) + for i, es in enumerate(expr_splits): + if es in replace_dict.keys(): + 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. + @param expr an expression string + @param vars a list of variable names + @return a subset of vars used in the expression + """ + 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 + @param exprs a mapping of variable name to expression + @return a graph of variable deps + """ + vars = exprs.keys() + #get dependencies for each expression, load into graph + var_graph = graph() + 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) + return var_graph + +def sort_variables(exprs): + """ + Get a list of variables in order of dependencies. + @param exprs a mapping of variable name to expression + @return a list of variable names + @throws Exception circular dependencies + """ + var_graph = get_graph(exprs) + sorted_vars = list() + #determine dependency order + while var_graph.get_nodes(): + #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 + sorted_vars.extend(sorted(indep_vars)) + #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. + @param objects the list of objects to sort + @param get_id the function to extract an id from the object + @param get_expr the function to extract an expression from the object + @return a list of sorted objects + """ + id2obj = dict([(get_id(obj), obj) for obj in objects]) + #map obj id to expression code + id2expr = dict([(get_id(obj), get_expr(obj)) for obj in objects]) + #sort according to dependency + sorted_ids = sort_variables(id2expr) + #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 diff --git a/grc/python/extract_docs.py b/grc/python/extract_docs.py new file mode 100644 index 000000000..33c404362 --- /dev/null +++ b/grc/python/extract_docs.py @@ -0,0 +1,66 @@ +""" +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 + +def _extract(key): + """ + Extract the documentation from the python __doc__ strings. + If multiple modules match, combine the docs. + @param key the block key + @return a string with documentation + """ + #extract matches + try: + module_name, constructor_name = key.split('_', 1) + module = __import__('gnuradio.'+module_name) + module = getattr(module, module_name) + except ImportError: + try: + module_name, constructor_name = key.split('_', 1) + module = __import__(module_name) + except: return '' + except: + return '' + pattern = constructor_name.replace('_', '_*').replace('x', '\w') + pattern_matcher = re.compile('^%s\w*$'%pattern) + matches = filter(lambda x: pattern_matcher.match(x), dir(module)) + #combine all matches + doc_strs = list() + for match in matches: + try: + title = ' --- ' + match + ' --- ' + doc_strs.append('\n\n'.join([title, getattr(module, match).__doc__]).strip()) + except: pass + return '\n\n'.join(doc_strs) + +_docs_cache = dict() +def extract(key): + """ + Call the private extract and cache the result. + @param key the block key + @return a string with documentation + """ + if not _docs_cache.has_key(key): + _docs_cache[key] = _extract(key) + return _docs_cache[key] + +if __name__ == '__main__': + import sys + print extract(sys.argv[1]) diff --git a/grc/python/flow_graph.tmpl b/grc/python/flow_graph.tmpl new file mode 100644 index 000000000..163e7f76a --- /dev/null +++ b/grc/python/flow_graph.tmpl @@ -0,0 +1,311 @@ +#!/usr/bin/env python +######################################################## +##Cheetah template - gnuradio_python +## +##@param imports the import statements +##@param flow_graph the flow_graph +##@param variables the variable blocks +##@param parameters the paramater blocks +##@param blocks the signal blocks +##@param connections the connections +##@param messages the msg type connections +##@param generate_options the type of flow graph +##@param var_id2cbs variable id map to callback strings +######################################################## +#def indent($code) +#set $code = '\n\t\t'.join(str($code).splitlines()) +$code#slurp +#end def +#import time +#set $DIVIDER = '#'*50 +$DIVIDER +# Gnuradio Python Flow Graph +# Title: $title +#if $flow_graph.get_option('author') +# Author: $flow_graph.get_option('author') +#end if +#if $flow_graph.get_option('description') +# Description: $flow_graph.get_option('description') +#end if +# Generated: $time.ctime() +$DIVIDER + +######################################################## +##Create Imports +######################################################## +#for $imp in $imports +$imp +#end for + +######################################################## +##Create Class +## Write the class declaration for a top or hier block. +## The parameter names are the arguments to __init__. +## Determine the absolute icon path (wx gui only). +## Setup the IO signature (hier block only). +######################################################## +#set $class_name = $flow_graph.get_option('id') +#set $param_str = ', '.join(['self'] + ['%s=%s'%(param.get_id(), param.get_make()) for param in $parameters]) +#if $generate_options == 'wx_gui' + #import gtk + #set $icon = gtk.IconTheme().lookup_icon('gnuradio-grc', 32, 0) +class $(class_name)(grc_wxgui.top_block_gui): + + def __init__($param_str): + grc_wxgui.top_block_gui.__init__(self, title="$title") + #if $icon + _icon_path = "$icon.get_filename()" + self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY)) + #end if +#elif $generate_options == 'qt_gui' +class $(class_name)(gr.top_block, Qt.QWidget): + + def __init__($param_str): + gr.top_block.__init__(self, "$title") + Qt.QWidget.__init__(self) + self.setWindowTitle("$title") + self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) + self.top_scroll_layout = Qt.QVBoxLayout() + self.setLayout(self.top_scroll_layout) + self.top_scroll = Qt.QScrollArea() + self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame) + self.top_scroll_layout.addWidget(self.top_scroll) + self.top_scroll.setWidgetResizable(True) + self.top_widget = Qt.QWidget() + self.top_scroll.setWidget(self.top_widget) + self.top_layout = Qt.QVBoxLayout(self.top_widget) + self.top_grid_layout = Qt.QGridLayout() + self.top_layout.addLayout(self.top_grid_layout) + +#elif $generate_options == 'no_gui' +class $(class_name)(gr.top_block): + + def __init__($param_str): + gr.top_block.__init__(self, "$title") +#elif $generate_options == 'hb' + #set $in_sigs = $flow_graph.get_io_signaturev('in') + #set $out_sigs = $flow_graph.get_io_signaturev('out') +class $(class_name)(gr.hier_block2): +#def make_io_sig($io_sigs) + #set $size_strs = ['%s*%s'%(io_sig['size'], io_sig['vlen']) for io_sig in $io_sigs] + #if len($io_sigs) == 0 +gr.io_signature(0, 0, 0)#slurp + #elif len($io_sigs) == 1 +gr.io_signature(1, 1, $size_strs[0])#slurp + #else +gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))])#slurp + #end if +#end def + + def __init__($param_str): + gr.hier_block2.__init__( + self, "$title", + $make_io_sig($in_sigs), + $make_io_sig($out_sigs), + ) +#end if +######################################################## +##Create Parameters +## Set the parameter to a property of self. +######################################################## +#if $parameters + + $DIVIDER + # Parameters + $DIVIDER +#end if +#for $param in $parameters + $indent($param.get_var_make()) +#end for +######################################################## +##Create Variables +######################################################## +#if $variables + + $DIVIDER + # Variables + $DIVIDER +#end if +#for $var in $variables + $indent($var.get_var_make()) +#end for +######################################################## +##Create Message Queues +######################################################## +#if $messages + + $DIVIDER + # Message Queues + $DIVIDER +#end if +#for $msg in $messages + $(msg.get_source().get_parent().get_id())_msgq_out = $(msg.get_sink().get_parent().get_id())_msgq_in = gr.msg_queue(2) +#end for +######################################################## +##Create Blocks +######################################################## +#if $blocks + + $DIVIDER + # Blocks + $DIVIDER +#end if +#for $blk in filter(lambda b: b.get_make(), $blocks) + #if $blk in $variables + $indent($blk.get_make()) + #else + self.$blk.get_id() = $indent($blk.get_make()) + #end if +#end for +######################################################## +##Create Connections +## The port name should be the id of the parent block. +## However, port names for IO pads should be self. +######################################################## +#def make_port_sig($port) + #if $port.get_parent().get_key() == 'pad_source' +(self, $flow_graph.get_pad_sources().index($port.get_parent()))#slurp + #elif $port.get_parent().get_key() == 'pad_sink' +(self, $flow_graph.get_pad_sinks().index($port.get_parent()))#slurp + #else +(self.$port.get_parent().get_id(), $port.get_key())#slurp + #end if +#end def +#if $connections + + $DIVIDER + # Connections + $DIVIDER +#end if +#for $con in $connections + #set $source = $con.get_source() + #set $sink = $con.get_sink() + ##resolve virtual sources to the actual sources + #if $source.get_parent().is_virtual_source() + #set $source = $source.resolve_virtual_source() + #end if + ##do not generate connections with virtual sinks + #if not $sink.get_parent().is_virtual_sink() + self.connect($make_port_sig($source), $make_port_sig($sink)) + #end if +#end for + +######################################################## +##Create Asynch Message Connections +######################################################## +#if $messages2 + $DIVIDER + # Asynch Message Connections + $DIVIDER +#end if +#for $msg in $messages2 + #set $sr = $msg.get_source() + #set $source = "self.%s"%($sr.get_parent().get_id()) + #set $source_port = $sr.get_name(); + #if $sr.get_parent().get_key() == "pad_source" + #set $source = "self" + #set $source_port = $sr.get_parent().get_param("label").get_value(); + #end if + #set $sk = $msg.get_sink() + #set $sink = "self.%s"%($sk.get_parent().get_id()) + #set $sink_port = $sk.get_name(); + #if $sk.get_parent().get_key() == "pad_sink" + #set $sink = "self" + #set $sink_port = $sk.get_parent().get_param("label").get_value(); + #end if + self.msg_connect($source, "$source_port", $sink, "$sink_port") +#end for + +######################################################## +##Create Callbacks +## Write a set method for this variable that calls the callbacks +######################################################## +#for $var in $parameters + $variables + #set $id = $var.get_id() + def get_$(id)(self): + return self.$id + + def set_$(id)(self, $id): + self.$id = $id + #for $callback in $var_id2cbs[$id] + $indent($callback) + #end for + +#end for +######################################################## +##Create Main +## For top block code, generate a main routine. +## Instantiate the top block and run as gui or cli. +######################################################## +#def make_default($type, $param) + #if $type == 'eng_float' +eng_notation.num_to_str($param.get_make())#slurp + #else +$param.get_make()#slurp + #end if +#end def +#def make_short_id($param) + #set $short_id = $param.get_param('short_id').get_evaluated() + #if $short_id + #set $short_id = '-' + $short_id + #end if +$short_id#slurp +#end def +#if $generate_options != 'hb' +if __name__ == '__main__': + parser = OptionParser(option_class=eng_option, usage="%prog: [options]") + #set $params_eq_list = list() + #for $param in $parameters + #set $type = $param.get_param('type').get_value() + #if $type + #silent $params_eq_list.append('%s=options.%s'%($param.get_id(), $param.get_id())) + parser.add_option("$make_short_id($param)", "--$param.get_id().replace('_', '-')", dest="$param.get_id()", type="$type", default=$make_default($type, $param), + help="Set $($param.get_param('label').get_evaluated() or $param.get_id()) [default=%default]") + #end if + #end for + (options, args) = parser.parse_args() + #if $flow_graph.get_option('realtime_scheduling') + if gr.enable_realtime_scheduling() != gr.RT_OK: + print "Error: failed to enable realtime scheduling." + #end if + #if $generate_options == 'wx_gui' + tb = $(class_name)($(', '.join($params_eq_list))) + #if $flow_graph.get_option('max_nouts') + tb.Run($flow_graph.get_option('run'), $flow_graph.get_option('max_nouts')) + #else + tb.Run($flow_graph.get_option('run')) + #end if + #elif $generate_options == 'qt_gui' + qapp = Qt.QApplication(sys.argv) + tb = $(class_name)($(', '.join($params_eq_list))) + #if $flow_graph.get_option('run') + #if $flow_graph.get_option('max_nouts') + tb.start($flow_graph.get_option('max_nouts')) + #else + tb.start() + #end if + #end if + tb.show() + qapp.exec_() + tb.stop() + #elif $generate_options == 'no_gui' + tb = $(class_name)($(', '.join($params_eq_list))) + #set $run_options = $flow_graph.get_option('run_options') + #if $run_options == 'prompt' + #if $flow_graph.get_option('max_nouts') + tb.start($flow_graph.get_option('max_nouts')) + #else + tb.start() + #end if + raw_input('Press Enter to quit: ') + tb.stop() + #elif $run_options == 'run' + #if $flow_graph.get_option('max_nouts') + tb.run($flow_graph.get_option('max_nouts')) + #else + tb.run() + #end if + #end if + #end if +#end if + diff --git a/grc/scripts/CMakeLists.txt b/grc/scripts/CMakeLists.txt new file mode 100644 index 000000000..e90589230 --- /dev/null +++ b/grc/scripts/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright 2011 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. + +######################################################################## +GR_PYTHON_INSTALL( + PROGRAMS gnuradio-companion + DESTINATION ${GR_RUNTIME_DIR} + COMPONENT "grc" +) diff --git a/grc/scripts/gnuradio-companion b/grc/scripts/gnuradio-companion new file mode 100755 index 000000000..dabca3028 --- /dev/null +++ b/grc/scripts/gnuradio-companion @@ -0,0 +1,72 @@ +#!/usr/bin/env python +""" +Copyright 2009-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 +""" + +import pygtk +pygtk.require('2.0') +import gtk + +try: from gnuradio import gr +except ImportError, e: + d = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_CLOSE, message_format=""" +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 +""") + d.set_title(str(e)) + d.run() + exit(-1) + +from optparse import OptionParser +import os + +if __name__ == "__main__": + if ('GR_DONT_LOAD_PREFS' in os.environ.keys() and + (not 'GRC_BLOCKS_PATH' in os.environ.keys() or len(os.environ['GRC_BLOCKS_PATH']) == 0)): + d = gtk.MessageDialog( + type=gtk.MESSAGE_ERROR, + buttons=gtk.BUTTONS_CLOSE, + message_format="""Can't find block definitions. Use config.conf or GRC_BLOCKS_PATH. """) + d.set_title("No block definitions available.") + d.run() + exit(-1) + usage = 'usage: %prog [options] [saved flow graphs]' + version = """ +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. +"""%gr.version() + parser = OptionParser(usage=usage, version=version) + (options, args) = parser.parse_args() + from gnuradio.grc.python.Platform import Platform + from gnuradio.grc.gui.ActionHandler import ActionHandler + #setup icon using icon theme + try: gtk.window_set_default_icon(gtk.IconTheme().load_icon('gnuradio-grc', 256, 0)) + except: pass + ActionHandler(args, Platform()) + diff --git a/grc/todo.txt b/grc/todo.txt new file mode 100644 index 000000000..1205b3ff6 --- /dev/null +++ b/grc/todo.txt @@ -0,0 +1,74 @@ +################################################## +# 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 +* ofdm + * gr_ofdm_bpsk_demapper + * gr_ofdm_demapper_vcb + * gr_ofdm_frame_sink + * gr_ofdm_mapper_bcv +* 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 |