2 Copyright 2008, 2009 Free Software Foundation, Inc.
3 This file is part of GNU Radio
5 GNU Radio Companion is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 GNU Radio Companion is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21 from Element import Element
23 from Cheetah.Template import Template
24 from UserDict import UserDict
26 class TemplateArg(UserDict):
28 A cheetah template argument created from a param.
29 The str of this class evaluates to the param's to code method.
30 The use of this class as a dictionary (enum only) will reveal the enum opts.
31 The __call__ or () method can return the param evaluated to a raw python data type.
34 def __init__(self, param):
35 UserDict.__init__(self)
38 for key in param.get_opt_keys():
39 self[key] = str(param.get_opt(key))
42 return str(self._param.to_code())
45 return self._param.get_evaluated()
47 def _get_keys(lst): return [elem.get_key() for elem in lst]
48 def _get_elem(lst, key):
49 try: return lst[_get_keys(lst).index(key)]
50 except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
54 def __init__(self, flow_graph, n):
56 Make a new block from nested data.
57 @param flow graph the parent element
58 @param n the nested odict
59 @return block a new block
62 Element.__init__(self, flow_graph)
64 params = n.findall('param')
65 sources = n.findall('source')
66 sinks = n.findall('sink')
67 self._name = n.find('name')
68 self._key = n.find('key')
69 self._category = n.find('category') or ''
70 self._block_wrapper_path = n.find('block_wrapper_path')
71 #create the param objects
74 self.get_params().append(self.get_parent().get_parent().Param(
82 self.get_params().append(self.get_parent().get_parent().Param(
92 for param in map(lambda n: self.get_parent().get_parent().Param(block=self, n=n), params):
94 #test against repeated keys
95 try: assert key not in self.get_param_keys()
96 except AssertionError: raise Exception, 'Key "%s" already exists in params'%key
98 self.get_params().append(param)
99 #create the source objects
100 self._sources = list()
101 for source in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='source'), sources):
102 key = source.get_key()
103 #test against repeated keys
104 try: assert key not in self.get_source_keys()
105 except AssertionError: raise Exception, 'Key "%s" already exists in sources'%key
107 self.get_sources().append(source)
108 #create the sink objects
110 for sink in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='sink'), sinks):
112 #test against repeated keys
113 try: assert key not in self.get_sink_keys()
114 except AssertionError: raise Exception, 'Key "%s" already exists in sinks'%key
116 self.get_sinks().append(sink)
118 def get_enabled(self):
120 Get the enabled state of the block.
121 @return true for enabled
123 try: return eval(self.get_param('_enabled').get_value())
126 def set_enabled(self, enabled):
128 Set the enabled state of the block.
129 @param enabled true for enabled
131 self.get_param('_enabled').set_value(str(enabled))
133 def __str__(self): return 'Block - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key())
135 def get_id(self): return self.get_param('id').get_value()
136 def is_block(self): return True
137 def get_name(self): return self._name
138 def get_key(self): return self._key
139 def get_category(self): return self._category
140 def get_doc(self): return ''
141 def get_ports(self): return self.get_sources() + self.get_sinks()
142 def get_children(self): return self.get_ports() + self.get_params()
143 def get_block_wrapper_path(self): return self._block_wrapper_path
145 ##############################################
147 ##############################################
148 def get_param_keys(self): return _get_keys(self._params)
149 def get_param(self, key): return _get_elem(self._params, key)
150 def get_params(self): return self._params
152 ##############################################
154 ##############################################
155 def get_sink_keys(self): return _get_keys(self._sinks)
156 def get_sink(self, key): return _get_elem(self._sinks, key)
157 def get_sinks(self): return self._sinks
159 ##############################################
161 ##############################################
162 def get_source_keys(self): return _get_keys(self._sources)
163 def get_source(self, key): return _get_elem(self._sources, key)
164 def get_sources(self): return self._sources
166 def get_connections(self):
167 return sum([port.get_connections() for port in self.get_ports()], [])
169 def resolve_dependencies(self, tmpl):
171 Resolve a paramater dependency with cheetah templates.
172 @param tmpl the string with dependencies
173 @return the resolved value
176 if '$' not in tmpl: return tmpl
177 n = dict((p.get_key(), TemplateArg(p)) for p in self.get_params())
178 try: return str(Template(tmpl, n))
179 except Exception, e: return "-------->\n%s: %s\n<--------"%(e, tmpl)
181 ##############################################
183 ##############################################
184 def type_controller_modify(self, direction):
186 Change the type controller.
187 @param direction +1 or -1
188 @return true for change
192 for param in filter(lambda p: p.is_enum(), self.get_params()):
193 children = self.get_ports() + self.get_params()
194 #priority to the type controller
195 if param.get_key() in ' '.join(map(lambda p: p._type, children)): type_param = param
196 #use param if type param is unset
197 if not type_param: type_param = param
199 #try to increment the enum by direction
201 keys = type_param.get_option_keys()
202 old_index = keys.index(type_param.get_value())
203 new_index = (old_index + direction + len(keys))%len(keys)
204 type_param.set_value(keys[new_index])
209 def port_controller_modify(self, direction):
211 Change the port controller.
212 @param direction +1 or -1
213 @return true for change
217 ##############################################
218 ## Import/Export Methods
219 ##############################################
220 def export_data(self):
222 Export this block's params to nested data.
223 @return a nested data odict
226 n['key'] = self.get_key()
227 n['param'] = map(lambda p: p.export_data(), self.get_params())
230 def import_data(self, n):
232 Import this block's params from nested data.
233 Any param keys that do not exist will be ignored.
234 Since params can be dynamically created based another param,
235 call rewrite, and repeat the load until the params stick.
236 This call to rewrite will also create any dynamic ports
237 that are needed for the connections creation phase.
238 @param n the nested data odict
240 get_hash = lambda: hash(tuple(map(hash, self.get_params())))
242 while get_hash() != my_hash:
243 params_n = n.findall('param')
244 for param_n in params_n:
245 key = param_n.find('key')
246 value = param_n.find('value')
247 #the key must exist in this block's params
248 if key in self.get_param_keys():
249 self.get_param(key).set_value(value)
250 #store hash and call rewrite