00001 """
00002 Copyright 2008 Free Software Foundation, Inc.
00003 This file is part of GNU Radio
00004
00005 GNU Radio Companion is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU General Public License
00007 as published by the Free Software Foundation; either version 2
00008 of the License, or (at your option) any later version.
00009
00010 GNU Radio Companion is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013 GNU General Public License for more details.
00014
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software
00017 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
00018 """
00019
00020
00021
00022
00023 from grc.Constants import FLOW_GRAPH_DTD
00024 from grc import ParseXML, Utils
00025 from grc.Utils import odict
00026 from lxml import etree
00027 import difflib
00028 import os
00029
00030 def _make_param(key, value):
00031 """!
00032 Make a paramater dict from the key/value pair.
00033 @param key the key
00034 @param value the value
00035 @return a dictionary object
00036 """
00037 param = odict()
00038 param['key'] = key
00039 param['value'] = value
00040 return param
00041
00042 def _get_blocks(blocks, tag):
00043 """!
00044 Get a list of blocks with the tag.
00045 @param blocks the old block list
00046 @param tag the tag name
00047 @retun a list of matching blocks
00048 """
00049 return filter(lambda b: b['tag'] == tag, blocks)
00050
00051 def _get_params(block):
00052 """!
00053 Get a list of params.
00054 @param block the old block
00055 @retun a list of params
00056 """
00057 params = Utils.exists_or_else(block, 'params', {}) or {}
00058 params = Utils.listify(params, 'param')
00059 return params
00060
00061 def _convert_id(id):
00062 """!
00063 Convert an old id to a new safe id.
00064 Replace spaces with underscores.
00065 Lower case the odl id.
00066 @return the reformatted id
00067 """
00068 return id.lower().replace(' ', '_')
00069
00070 def convert(file_path, platform):
00071 """!
00072 Convert the flow graph to the new format.
00073 Make a backup of the old file.
00074 Save a reformated flow graph to the file path.
00075 If this is a new format flow graph, do nothing.
00076 @param file_path the path to the saved flow graph
00077 @param platform the grc gnuradio platform
00078 """
00079 try:
00080 ParseXML.validate_dtd(file_path, FLOW_GRAPH_DTD)
00081 try:
00082 changed = False
00083
00084 xml = etree.parse(file_path)
00085 for find, replace in (
00086 ('gui_coordinate', '_coordinate'),
00087 ('gui_rotation', '_rotation'),
00088 ):
00089 keys = xml.xpath('/flow_graph/block/param[key="%s"]/key'%find)
00090 for key in keys:
00091 key.text = replace
00092 changed = True
00093 if not changed: return
00094
00095 os.rename(file_path, file_path+'.bak')
00096
00097 xml.write(file_path, xml_declaration=True, pretty_print=True)
00098 except Exception, e: print e
00099 return
00100 except: pass
00101
00102
00103
00104 old_n = ParseXML.from_file(file_path)['flow_graph']
00105 try: window_width = min(3*int(old_n['window_width'])/2, 2048)
00106 except: window_width = 2048
00107 try: window_height = min(3*int(old_n['window_height'])/2, 2048)
00108 except: window_height = 2048
00109 window_size = '%d, %d'%(window_width, window_height)
00110 variables = Utils.exists_or_else(old_n, 'vars', {}) or {}
00111 variables = Utils.listify(variables, 'var')
00112 blocks = Utils.exists_or_else(old_n, 'signal_blocks', {}) or {}
00113 blocks = Utils.listify(blocks, 'signal_block')
00114 connections = Utils.exists_or_else(old_n, 'connections', {}) or {}
00115 connections = Utils.listify(connections, 'connection')
00116
00117 new_n = odict()
00118 new_n['block'] = list()
00119 new_n['connection'] = list()
00120
00121
00122
00123
00124 about_blocks = _get_blocks(blocks, 'About')
00125 if about_blocks: title = _get_params(about_blocks[0])[0]
00126 else: title = 'Untitled'
00127
00128 if about_blocks: author = _get_params(about_blocks[0])[1]
00129 else: author = ''
00130
00131 note_blocks = _get_blocks(blocks, 'Note')
00132 if note_blocks: desc = _get_params(note_blocks[0])[0]
00133 else: desc = ''
00134
00135 options_block = odict()
00136 options_block['key'] = 'options'
00137 options_block['param'] = [
00138 _make_param('id', 'top_block'),
00139 _make_param('title', title),
00140 _make_param('author', author),
00141 _make_param('description', desc),
00142 _make_param('window_size', window_size),
00143 _make_param('_coordinate', '(10, 10)'),
00144 ]
00145
00146 new_n['block'].append(options_block)
00147
00148
00149
00150 x = 100
00151 for variable in variables:
00152 key = variable['key']
00153 value = variable['value']
00154 minimum = Utils.exists_or_else(variable, 'min', '')
00155 maximum = Utils.exists_or_else(variable, 'max', '')
00156 step = Utils.exists_or_else(variable, 'step', '')
00157 x = x + 150
00158 coor = '(%d, %d)'%(x, 10)
00159 var_block = odict()
00160 if minimum and maximum:
00161
00162 try: num_steps = str(int((float(maximum) - float(minimum))/float(step)))
00163 except: num_steps = '100'
00164 var_block['key'] = 'variable_slider'
00165 var_block['param'] = [
00166 _make_param('id', key),
00167 _make_param('value', value),
00168 _make_param('min', minimum),
00169 _make_param('max', maximum),
00170 _make_param('num_steps', num_steps),
00171 _make_param('_coordinate', coor),
00172 ]
00173 else:
00174 var_block['key'] = 'variable'
00175 var_block['param'] = [
00176 _make_param('id', key),
00177 _make_param('value', value),
00178 _make_param('_coordinate', coor),
00179 ]
00180
00181 new_n['block'].append(var_block)
00182
00183
00184
00185
00186 name_to_key = dict((b.get_name(), b.get_key()) for b in platform.get_blocks())
00187 for block in blocks:
00188
00189 tag = block['tag']
00190
00191 if tag in ('Note', 'About'): continue
00192 id = _convert_id(block['id'])
00193 coor = '(%s, %s + 100)'%(
00194 Utils.exists_or_else(block, 'x_coordinate', '0'),
00195 Utils.exists_or_else(block, 'y_coordinate', '0'),
00196 )
00197 rot = Utils.exists_or_else(block, 'rotation', '0')
00198 params = _get_params(block)
00199
00200 new_block = odict()
00201 matches = difflib.get_close_matches(tag, name_to_key.keys(), 1)
00202 if not matches: continue
00203
00204 key = name_to_key[matches[0]]
00205 new_block['key'] = key
00206 new_block['param'] = [
00207 _make_param('id', id),
00208 _make_param('_coordinate', coor),
00209 _make_param('_rotation', rot),
00210 ]
00211
00212 if key == 'wxgui_fftsink2':
00213 params = params[0:3] + ['0'] + params[3:4] + ['8'] + params[4:]
00214
00215 for i, param in enumerate(params):
00216 platform_block = platform.get_block(key)
00217 try: platform_param = platform_block.get_params()[i+2]
00218 except IndexError: break
00219 if platform_param.is_enum():
00220 try: param_value = platform_param.get_option_keys()[int(param)]
00221 except: param_value = platform_param.get_option_keys()[0]
00222 else:
00223 param_value = param.replace('$', '').replace('^', '**')
00224 new_block['param'].append(_make_param(platform_param.get_key(), param_value))
00225
00226 new_n['block'].append(new_block)
00227
00228
00229
00230 for connection in connections:
00231
00232 input_signal_block_id = connection['input_signal_block_id']
00233 input_socket_index = connection['input_socket_index']
00234 output_signal_block_id = connection['output_signal_block_id']
00235 output_socket_index = connection['output_socket_index']
00236
00237 new_conn = odict()
00238 new_conn['source_block_id'] = _convert_id(output_signal_block_id)
00239 new_conn['sink_block_id'] = _convert_id(input_signal_block_id)
00240 new_conn['source_key'] = output_socket_index
00241 new_conn['sink_key'] = input_socket_index
00242
00243 new_n['connection'].append(new_conn)
00244
00245
00246
00247
00248 os.rename(file_path, file_path+'.bak')
00249
00250 ParseXML.to_file({'flow_graph': new_n}, file_path)
00251