2 Copyright 2008 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
20 from .. platforms.base.Constants import FLOW_GRAPH_DTD
23 from .. utils import odict
24 from lxml import etree
28 def _make_param(key, value):
30 Make a paramater dict from the key/value pair.
32 @param value the value
33 @return a dictionary object
37 param['value'] = value
40 def _get_blocks(blocks, tag):
42 Get a list of blocks with the tag.
43 @param blocks the old block list
44 @param tag the tag name
45 @retun a list of matching blocks
47 return filter(lambda b: b['tag'] == tag, blocks)
49 def _get_params(block):
52 @param block the old block
53 @retun a list of params
55 params = utils.exists_or_else(block, 'params', {}) or {}
56 params = utils.listify(params, 'param')
61 Convert an old id to a new safe id.
62 Replace spaces with underscores.
63 Lower case the odl id.
64 @return the reformatted id
66 return id.lower().replace(' ', '_')
68 def convert(file_path, platform):
70 Convert the flow graph to the new format.
71 Make a backup of the old file.
72 Save a reformated flow graph to the file path.
73 If this is a new format flow graph, do nothing.
74 @param file_path the path to the saved flow graph
75 @param platform the grc gnuradio platform
77 try: #return if file passes validation
78 ParseXML.validate_dtd(file_path, FLOW_GRAPH_DTD)
81 #convert instances of gui_coordinate and gui_rotation
82 xml = etree.parse(file_path)
83 for find, replace in (
84 ('gr_add_vxx', 'gr_add_xx'),
85 ('gr_multiply_vxx', 'gr_multiply_xx'),
87 keys = xml.xpath('/flow_graph/block[key="%s"]/key'%find)
91 if not changed: return
92 #backup after successful conversion
93 os.rename(file_path, file_path+'.bak')
94 #save new flow graph to file path
95 xml.write(file_path, xml_declaration=True, pretty_print=True)
96 except Exception, e: print e
99 ############################################################
100 # extract window size, variables, blocks, and connections
101 ############################################################
102 old_n = ParseXML.from_file(file_path)['flow_graph']
103 try: window_width = min(3*int(old_n['window_width'])/2, 2048)
104 except: window_width = 2048
105 try: window_height = min(3*int(old_n['window_height'])/2, 2048)
106 except: window_height = 2048
107 window_size = '%d, %d'%(window_width, window_height)
108 variables = utils.exists_or_else(old_n, 'vars', {}) or {}
109 variables = utils.listify(variables, 'var')
110 blocks = utils.exists_or_else(old_n, 'signal_blocks', {}) or {}
111 blocks = utils.listify(blocks, 'signal_block')
112 connections = utils.exists_or_else(old_n, 'connections', {}) or {}
113 connections = utils.listify(connections, 'connection')
114 #initialize new nested data
116 new_n['block'] = list()
117 new_n['connection'] = list()
118 ############################################################
119 # conversion - options block
120 ############################################################
122 about_blocks = _get_blocks(blocks, 'About')
123 if about_blocks: title = _get_params(about_blocks[0])[0]
124 else: title = 'Untitled'
126 if about_blocks: author = _get_params(about_blocks[0])[1]
129 note_blocks = _get_blocks(blocks, 'Note')
130 if note_blocks: desc = _get_params(note_blocks[0])[0]
132 #create options block
133 options_block = odict()
134 options_block['key'] = 'options'
135 options_block['param'] = [
136 _make_param('id', 'top_block'),
137 _make_param('title', title),
138 _make_param('author', author),
139 _make_param('description', desc),
140 _make_param('window_size', window_size),
141 _make_param('_coordinate', '(10, 10)'),
143 #append options block
144 new_n['block'].append(options_block)
145 ############################################################
146 # conversion - variables
147 ############################################################
149 for variable in variables:
150 key = variable['key']
151 value = variable['value']
152 minimum = utils.exists_or_else(variable, 'min', '')
153 maximum = utils.exists_or_else(variable, 'max', '')
154 step = utils.exists_or_else(variable, 'step', '')
156 coor = '(%d, %d)'%(x, 10)
158 if minimum and maximum: #slider varible
160 try: num_steps = str(int((float(maximum) - float(minimum))/float(step)))
161 except: num_steps = '100'
162 var_block['key'] = 'variable_slider'
163 var_block['param'] = [
164 _make_param('id', key),
165 _make_param('value', value),
166 _make_param('min', minimum),
167 _make_param('max', maximum),
168 _make_param('num_steps', num_steps),
169 _make_param('_coordinate', coor),
171 else: #regular variable
172 var_block['key'] = 'variable'
173 var_block['param'] = [
174 _make_param('id', key),
175 _make_param('value', value),
176 _make_param('_coordinate', coor),
178 #append variable block
179 new_n['block'].append(var_block)
180 ############################################################
181 # conversion - blocks
182 ############################################################
183 #create name to key map for all blocks in platform
184 name_to_key = dict((b.get_name(), b.get_key()) for b in platform.get_blocks())
189 if tag in ('Note', 'About'): continue
190 id = _convert_id(block['id'])
191 coor = '(%s, %s + 100)'%(
192 utils.exists_or_else(block, 'x_coordinate', '0'),
193 utils.exists_or_else(block, 'y_coordinate', '0'),
195 rot = utils.exists_or_else(block, 'rotation', '0')
196 params = _get_params(block)
199 matches = difflib.get_close_matches(tag, name_to_key.keys(), 1)
200 if not matches: continue
202 key = name_to_key[matches[0]]
203 new_block['key'] = key
204 new_block['param'] = [
205 _make_param('id', id),
206 _make_param('_coordinate', coor),
207 _make_param('_rotation', rot),
209 #handle specific blocks
210 if key == 'wxgui_fftsink2':
211 params = params[0:3] + ['0'] + params[3:4] + ['8'] + params[4:]
213 for i, param in enumerate(params):
214 platform_block = platform.get_block(key)
215 try: platform_param = platform_block.get_params()[i+2]
216 except IndexError: break
217 if platform_param.is_enum():
218 try: param_value = platform_param.get_option_keys()[int(param)]
219 except: param_value = platform_param.get_option_keys()[0]
221 param_value = param.replace('$', '').replace('^', '**')
222 new_block['param'].append(_make_param(platform_param.get_key(), param_value))
224 new_n['block'].append(new_block)
225 ############################################################
226 # conversion - connections
227 ############################################################
228 for connection in connections:
230 input_signal_block_id = connection['input_signal_block_id']
231 input_socket_index = connection['input_socket_index']
232 output_signal_block_id = connection['output_signal_block_id']
233 output_socket_index = connection['output_socket_index']
236 new_conn['source_block_id'] = _convert_id(output_signal_block_id)
237 new_conn['sink_block_id'] = _convert_id(input_signal_block_id)
238 new_conn['source_key'] = output_socket_index
239 new_conn['sink_key'] = input_socket_index
241 new_n['connection'].append(new_conn)
242 ############################################################
244 ############################################################
245 #backup after successful conversion
246 os.rename(file_path, file_path+'.bak')
247 #save new flow graph to file path
248 ParseXML.to_file({'flow_graph': new_n}, file_path)