added include <cstdio> statements in several files to make it compatible with g+...
[debian/gnuradio] / grc / src / utils / converter.py
1 """
2 Copyright 2008 Free Software Foundation, Inc.
3 This file is part of GNU Radio
4
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.
9
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.
14
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
18 """
19
20 from .. platforms.base.Constants import FLOW_GRAPH_DTD
21 import ParseXML
22 from .. import utils
23 from .. utils import odict
24 from lxml import etree
25 import difflib
26 import os
27
28 def _make_param(key, value):
29         """
30         Make a paramater dict from the key/value pair.
31         @param key the key
32         @param value the value
33         @return a dictionary object
34         """
35         param = odict()
36         param['key'] = key
37         param['value'] = value
38         return param
39
40 def _get_blocks(blocks, tag):
41         """
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
46         """
47         return filter(lambda b: b['tag'] == tag, blocks)
48
49 def _get_params(block):
50         """
51         Get a list of params.
52         @param block the old block
53         @retun a list of params
54         """
55         params = utils.exists_or_else(block, 'params', {}) or {}
56         params = utils.listify(params, 'param')
57         return params
58
59 def _convert_id(id):
60         """
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
65         """
66         return id.lower().replace(' ', '_')
67
68 def convert(file_path, platform):
69         """
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
76         """
77         try: #return if file passes validation
78                 ParseXML.validate_dtd(file_path, FLOW_GRAPH_DTD)
79                 try:
80                         changed = False
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'),
86                         ):
87                                 keys = xml.xpath('/flow_graph/block[key="%s"]/key'%find)
88                                 for key in keys:
89                                         key.text = replace
90                                         changed = True
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
97                 return
98         except: pass #convert
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
115         new_n = odict()
116         new_n['block'] = list()
117         new_n['connection'] = list()
118         ############################################################
119         # conversion - options block
120         ############################################################
121         #get name
122         about_blocks = _get_blocks(blocks, 'About')
123         if about_blocks: title = _get_params(about_blocks[0])[0]
124         else: title = 'Untitled'
125         #get author
126         if about_blocks: author = _get_params(about_blocks[0])[1]
127         else: author = ''
128         #get desc
129         note_blocks = _get_blocks(blocks, 'Note')
130         if note_blocks: desc = _get_params(note_blocks[0])[0]
131         else: desc = ''
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)'),
142         ]
143         #append options block
144         new_n['block'].append(options_block)
145         ############################################################
146         # conversion - variables
147         ############################################################
148         x = 100
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', '')
155                 x = x + 150
156                 coor = '(%d, %d)'%(x, 10)
157                 var_block = odict()
158                 if minimum and maximum: #slider varible
159                         #determine num steps
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),
170                         ]
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),
177                         ]
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())
185         for block in blocks:
186                 #extract info
187                 tag = block['tag']
188                 #ignore list
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'),
194                 )
195                 rot = utils.exists_or_else(block, 'rotation', '0')
196                 params = _get_params(block)
197                 #new block
198                 new_block = odict()
199                 matches = difflib.get_close_matches(tag, name_to_key.keys(), 1)
200                 if not matches: continue
201                 #match found
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),
208                 ]
209                 #handle specific blocks
210                 if key == 'wxgui_fftsink2':
211                         params = params[0:3] + ['0'] + params[3:4] + ['8'] + params[4:]
212                 #append params
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]
220                         else:
221                                 param_value = param.replace('$', '').replace('^', '**')
222                         new_block['param'].append(_make_param(platform_param.get_key(), param_value))
223                 #append block
224                 new_n['block'].append(new_block)
225         ############################################################
226         # conversion - connections
227         ############################################################
228         for connection in connections:
229                 #extract info
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']
234                 #new connection
235                 new_conn = odict()
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
240                 #append connection
241                 new_n['connection'].append(new_conn)
242         ############################################################
243         # backup and replace
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)