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
19 ##@package grc.converter
20 #convert old flow graph file format to new format
23 from grc.Constants import FLOW_GRAPH_DTD
24 from grc import ParseXML, Utils
25 from grc.Utils import odict
26 from lxml import etree
30 def _make_param(key, value):
32 Make a paramater dict from the key/value pair.
34 @param value the value
35 @return a dictionary object
39 param['value'] = value
42 def _get_blocks(blocks, tag):
44 Get a list of blocks with the tag.
45 @param blocks the old block list
46 @param tag the tag name
47 @retun a list of matching blocks
49 return filter(lambda b: b['tag'] == tag, blocks)
51 def _get_params(block):
54 @param block the old block
55 @retun a list of params
57 params = Utils.exists_or_else(block, 'params', {}) or {}
58 params = Utils.listify(params, 'param')
63 Convert an old id to a new safe id.
64 Replace spaces with underscores.
65 Lower case the odl id.
66 @return the reformatted id
68 return id.lower().replace(' ', '_')
70 def convert(file_path, platform):
72 Convert the flow graph to the new format.
73 Make a backup of the old file.
74 Save a reformated flow graph to the file path.
75 If this is a new format flow graph, do nothing.
76 @param file_path the path to the saved flow graph
77 @param platform the grc gnuradio platform
79 try: #return if file passes validation
80 ParseXML.validate_dtd(file_path, FLOW_GRAPH_DTD)
83 #convert instances of gui_coordinate and gui_rotation
84 xml = etree.parse(file_path)
85 for find, replace in (
86 ('gui_coordinate', '_coordinate'),
87 ('gui_rotation', '_rotation'),
89 keys = xml.xpath('/flow_graph/block/param[key="%s"]/key'%find)
93 if not changed: return
94 #backup after successful conversion
95 os.rename(file_path, file_path+'.bak')
96 #save new flow graph to file path
97 xml.write(file_path, xml_declaration=True, pretty_print=True)
98 except Exception, e: print e
100 except: pass #convert
101 ############################################################
102 # extract window size, variables, blocks, and connections
103 ############################################################
104 old_n = ParseXML.from_file(file_path)['flow_graph']
105 try: window_width = min(3*int(old_n['window_width'])/2, 2048)
106 except: window_width = 2048
107 try: window_height = min(3*int(old_n['window_height'])/2, 2048)
108 except: window_height = 2048
109 window_size = '%d, %d'%(window_width, window_height)
110 variables = Utils.exists_or_else(old_n, 'vars', {}) or {}
111 variables = Utils.listify(variables, 'var')
112 blocks = Utils.exists_or_else(old_n, 'signal_blocks', {}) or {}
113 blocks = Utils.listify(blocks, 'signal_block')
114 connections = Utils.exists_or_else(old_n, 'connections', {}) or {}
115 connections = Utils.listify(connections, 'connection')
116 #initialize new nested data
118 new_n['block'] = list()
119 new_n['connection'] = list()
120 ############################################################
121 # conversion - options block
122 ############################################################
124 about_blocks = _get_blocks(blocks, 'About')
125 if about_blocks: title = _get_params(about_blocks[0])[0]
126 else: title = 'Untitled'
128 if about_blocks: author = _get_params(about_blocks[0])[1]
131 note_blocks = _get_blocks(blocks, 'Note')
132 if note_blocks: desc = _get_params(note_blocks[0])[0]
134 #create options block
135 options_block = odict()
136 options_block['key'] = 'options'
137 options_block['param'] = [
138 _make_param('id', 'top_block'),
139 _make_param('title', title),
140 _make_param('author', author),
141 _make_param('description', desc),
142 _make_param('window_size', window_size),
143 _make_param('_coordinate', '(10, 10)'),
145 #append options block
146 new_n['block'].append(options_block)
147 ############################################################
148 # conversion - variables
149 ############################################################
151 for variable in variables:
152 key = variable['key']
153 value = variable['value']
154 minimum = Utils.exists_or_else(variable, 'min', '')
155 maximum = Utils.exists_or_else(variable, 'max', '')
156 step = Utils.exists_or_else(variable, 'step', '')
158 coor = '(%d, %d)'%(x, 10)
160 if minimum and maximum: #slider varible
162 try: num_steps = str(int((float(maximum) - float(minimum))/float(step)))
163 except: num_steps = '100'
164 var_block['key'] = 'variable_slider'
165 var_block['param'] = [
166 _make_param('id', key),
167 _make_param('value', value),
168 _make_param('min', minimum),
169 _make_param('max', maximum),
170 _make_param('num_steps', num_steps),
171 _make_param('_coordinate', coor),
173 else: #regular variable
174 var_block['key'] = 'variable'
175 var_block['param'] = [
176 _make_param('id', key),
177 _make_param('value', value),
178 _make_param('_coordinate', coor),
180 #append variable block
181 new_n['block'].append(var_block)
182 ############################################################
183 # conversion - blocks
184 ############################################################
185 #create name to key map for all blocks in platform
186 name_to_key = dict((b.get_name(), b.get_key()) for b in platform.get_blocks())
191 if tag in ('Note', 'About'): continue
192 id = _convert_id(block['id'])
193 coor = '(%s, %s + 100)'%(
194 Utils.exists_or_else(block, 'x_coordinate', '0'),
195 Utils.exists_or_else(block, 'y_coordinate', '0'),
197 rot = Utils.exists_or_else(block, 'rotation', '0')
198 params = _get_params(block)
201 matches = difflib.get_close_matches(tag, name_to_key.keys(), 1)
202 if not matches: continue
204 key = name_to_key[matches[0]]
205 new_block['key'] = key
206 new_block['param'] = [
207 _make_param('id', id),
208 _make_param('_coordinate', coor),
209 _make_param('_rotation', rot),
211 #handle specific blocks
212 if key == 'wxgui_fftsink2':
213 params = params[0:3] + ['0'] + params[3:4] + ['8'] + params[4:]
215 for i, param in enumerate(params):
216 platform_block = platform.get_block(key)
217 try: platform_param = platform_block.get_params()[i+2]
218 except IndexError: break
219 if platform_param.is_enum():
220 try: param_value = platform_param.get_option_keys()[int(param)]
221 except: param_value = platform_param.get_option_keys()[0]
223 param_value = param.replace('$', '').replace('^', '**')
224 new_block['param'].append(_make_param(platform_param.get_key(), param_value))
226 new_n['block'].append(new_block)
227 ############################################################
228 # conversion - connections
229 ############################################################
230 for connection in connections:
232 input_signal_block_id = connection['input_signal_block_id']
233 input_socket_index = connection['input_socket_index']
234 output_signal_block_id = connection['output_signal_block_id']
235 output_socket_index = connection['output_socket_index']
238 new_conn['source_block_id'] = _convert_id(output_signal_block_id)
239 new_conn['sink_block_id'] = _convert_id(input_signal_block_id)
240 new_conn['source_key'] = output_socket_index
241 new_conn['sink_key'] = input_socket_index
243 new_n['connection'].append(new_conn)
244 ############################################################
246 ############################################################
247 #backup after successful conversion
248 os.rename(file_path, file_path+'.bak')
249 #save new flow graph to file path
250 ParseXML.to_file({'flow_graph': new_n}, file_path)