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
22 from .. gui import Messages
24 class FlowGraph(Element):
26 def __init__(self, platform):
28 Make a flow graph from the arguments.
29 @param platform a platforms with blocks and contrcutors
30 @return the flow graph object
33 Element.__init__(self, platform)
37 def _get_unique_id(self, base_id=''):
39 Get a unique id starting with the base id.
40 @param base_id the id starts with this and appends a count
45 id = '%s_%d'%(base_id, index)
47 #make sure that the id is not used by another block
48 if not filter(lambda b: b.get_id() == id, self.get_blocks()): return id
50 def __str__(self): return 'FlowGraph - %s(%s)'%(self.get_option('title'), self.get_option('id'))
52 def get_option(self, key):
54 Get the option for a given key.
55 The option comes from the special options block.
56 @param key the param key for the options block
57 @return the value held by that param
59 return self._options_block.get_param(key).get_evaluated()
61 def is_flow_graph(self): return True
63 ##############################################
65 ##############################################
66 def get_block(self, id): return filter(lambda b: b.get_id() == id, self.get_blocks())[0]
67 def get_blocks(self): return filter(lambda e: e.is_block(), self.get_elements())
68 def get_connections(self): return filter(lambda e: e.is_connection(), self.get_elements())
69 def get_children(self): return self.get_elements()
70 def get_elements(self):
72 Get a list of all the elements.
73 Always ensure that the options block is in the list (only once).
74 @return the element list
76 options_block_count = self._elements.count(self._options_block)
77 if not options_block_count:
78 self._elements.append(self._options_block)
79 for i in range(options_block_count-1):
80 self._elements.remove(self._options_block)
83 def get_enabled_blocks(self):
85 Get a list of all blocks that are enabled.
86 @return a list of blocks
88 return filter(lambda b: b.get_enabled(), self.get_blocks())
90 def get_enabled_connections(self):
92 Get a list of all connections that are enabled.
93 @return a list of connections
95 return filter(lambda c: c.get_enabled(), self.get_connections())
97 def get_new_block(self, key):
99 Get a new block of the specified key.
100 Add the block to the list of elements.
101 @param key the block key
102 @return the new block or None if not found
104 if key not in self.get_parent().get_block_keys(): return None
105 block = self.get_parent().get_new_block(self, key)
106 self.get_elements().append(block)
109 def connect(self, porta, portb):
111 Create a connection between porta and portb.
113 @param portb another port
114 @throw Exception bad connection
115 @return the new connection
117 connection = self.get_parent().Connection(flow_graph=self, porta=porta, portb=portb)
118 self.get_elements().append(connection)
121 def remove_element(self, element):
123 Remove the element from the list of elements.
124 If the element is a port, remove the whole block.
125 If the element is a block, remove its connections.
126 If the element is a connection, just remove the connection.
128 if element not in self.get_elements(): return
129 #found a port, set to parent signal block
130 if element.is_port():
131 element = element.get_parent()
132 #remove block, remove all involved connections
133 if element.is_block():
134 for port in element.get_ports():
135 map(self.remove_element, port.get_connections())
136 self.get_elements().remove(element)
138 def evaluate(self, expr):
140 Evaluate the expression.
141 @param expr the string expression
142 @throw NotImplementedError
144 raise NotImplementedError
146 ##############################################
147 ## Import/Export Methods
148 ##############################################
149 def export_data(self):
151 Export this flow graph to nested data.
152 Export all block and connection data.
153 @return a nested data odict
157 n['timestamp'] = time.ctime()
158 n['block'] = [block.export_data() for block in self.get_blocks()]
159 n['connection'] = [connection.export_data() for connection in self.get_connections()]
160 return odict({'flow_graph': n})
162 def import_data(self, n=None):
164 Import blocks and connections into this flow graph.
165 Clear this flowgraph of all previous blocks and connections.
166 Any blocks or connections in error will be ignored.
167 @param n the nested data odict
169 #remove previous elements
170 self._elements = list()
171 #use blank data if none provided
172 fg_n = n and n.find('flow_graph') or odict()
173 blocks_n = fg_n.findall('block')
174 connections_n = fg_n.findall('connection')
176 self._options_block = self.get_parent().get_new_block(self, 'options')
178 for block_n in blocks_n:
179 key = block_n.find('key')
180 if key == 'options': block = self._options_block
181 else: block = self.get_new_block(key)
182 #only load the block when the block key was valid
183 if block: block.import_data(block_n)
184 else: Messages.send_error_load('Block key "%s" not found in %s'%(key, self.get_parent()))
185 #build the connections
186 for connection_n in connections_n:
187 #try to make the connection
190 source_block_id = connection_n.find('source_block_id')
191 sink_block_id = connection_n.find('sink_block_id')
193 source_key = connection_n.find('source_key')
194 sink_key = connection_n.find('sink_key')
196 block_ids = map(lambda b: b.get_id(), self.get_blocks())
197 assert(source_block_id in block_ids)
198 assert(sink_block_id in block_ids)
200 source_block = self.get_block(source_block_id)
201 sink_block = self.get_block(sink_block_id)
203 assert(source_key in source_block.get_source_keys())
204 assert(sink_key in sink_block.get_sink_keys())
206 source = source_block.get_source(source_key)
207 sink = sink_block.get_sink(sink_key)
208 #build the connection
209 self.connect(source, sink)
210 except AssertionError: Messages.send_error_load('Connection between %s(%s) and %s(%s) could not be made.'%(source_block_id, source_key, sink_block_id, sink_key))
211 self.rewrite() #global rewrite