Statistics
| Branch: | Tag: | Revision:

root / gnuradio-core / src / lib / runtime / gr_hier_block2_detail.cc @ 651837d3

History | View | Annotate | Download (11.1 kB)

1
/*
2
 * Copyright 2006,2007 Free Software Foundation, Inc.
3
 * 
4
 * This file is part of GNU Radio
5
 * 
6
 * GNU Radio is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3, or (at your option)
9
 * any later version.
10
 * 
11
 * GNU Radio is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 * 
16
 * You should have received a copy of the GNU General Public License
17
 * along with GNU Radio; see the file COPYING.  If not, write to
18
 * the Free Software Foundation, Inc., 51 Franklin Street,
19
 * Boston, MA 02110-1301, USA.
20
 */
21
22
#ifdef HAVE_CONFIG_H
23
#include "config.h"
24
#endif
25
26
#include <gr_hier_block2_detail.h>
27
#include <gr_io_signature.h>
28
#include <stdexcept>
29
#include <sstream>
30
31
#define GR_HIER_BLOCK2_DETAIL_DEBUG 0
32
33
gr_hier_block2_detail::gr_hier_block2_detail(gr_hier_block2 *owner) :
34
  d_owner(owner), 
35
  d_parent_detail(0),
36
  d_fg(gr_make_flowgraph()),
37
  d_inputs(owner->input_signature()->max_streams()),
38
  d_outputs(owner->output_signature()->max_streams())
39
{
40
}
41
42
gr_hier_block2_detail::~gr_hier_block2_detail()
43
{
44
  d_owner = 0; // Don't use delete, we didn't allocate
45
}
46
47
void
48
gr_hier_block2_detail::connect(gr_basic_block_sptr block)
49
{
50
  std::stringstream msg;
51
52
  // Check if duplicate
53
  if (std::find(d_blocks.begin(), d_blocks.end(), block) != d_blocks.end()) {
54
    msg << "Block " << block << " already connected.";
55
    throw std::invalid_argument(msg.str());
56
  }
57
58
  // Check if has inputs or outputs
59
  if (block->input_signature()->max_streams() != 0 ||
60
      block->output_signature()->max_streams() != 0) {
61
    msg << "Block " << block << " must not have any input or output ports";
62
    throw std::invalid_argument(msg.str());
63
  }
64
65
  d_blocks.push_back(block);
66
}
67
68
void 
69
gr_hier_block2_detail::connect(gr_basic_block_sptr src, int src_port, 
70
                               gr_basic_block_sptr dst, int dst_port)
71
{
72
  std::stringstream msg;
73
  
74
  if (GR_HIER_BLOCK2_DETAIL_DEBUG)
75
    std::cout << "connecting: " << gr_endpoint(src, src_port)
76
              << " -> " << gr_endpoint(dst, dst_port) << std::endl;
77
78
  if (src.get() == dst.get())
79
    throw std::invalid_argument("connect: src and destination blocks cannot be the same");
80
81
  gr_hier_block2_sptr src_block(cast_to_hier_block2_sptr(src));
82
  gr_hier_block2_sptr dst_block(cast_to_hier_block2_sptr(dst));
83
84
  if (src_block && src.get() != d_owner) {
85
    if (GR_HIER_BLOCK2_DETAIL_DEBUG)
86
      std::cout << "connect: src is hierarchical, setting parent to " << this << std::endl;
87
    src_block->d_detail->d_parent_detail = this;
88
  }
89
                
90
  if (dst_block && dst.get() != d_owner) {
91
    if (GR_HIER_BLOCK2_DETAIL_DEBUG)
92
      std::cout << "connect: dst is hierarchical, setting parent to " << this << std::endl;
93
    dst_block->d_detail->d_parent_detail = this;
94
  }
95
96
  // Connections to block inputs or outputs
97
  int max_port;
98
  if (src.get() == d_owner) {
99
    max_port = src->input_signature()->max_streams();
100
    if ((max_port != -1 && (src_port >= max_port)) || src_port < 0) {
101
      msg << "source port " << src_port << " out of range for " << src;
102
      throw std::invalid_argument(msg.str());
103
    }
104
105
    return connect_input(src_port, dst_port, dst);
106
  }
107
108
  if (dst.get() == d_owner) {
109
    max_port = dst->output_signature()->max_streams();
110
    if ((max_port != -1 && (dst_port >= max_port)) || dst_port < 0) {
111
      msg << "destination port " << dst_port << " out of range for " << dst;
112
      throw std::invalid_argument(msg.str());
113
    }
114
115
    return connect_output(dst_port, src_port, src);
116
  }
117
118
  // Internal connections
119
  d_fg->connect(src, src_port, dst, dst_port);
120
121
  // TODO: connects to NC
122
}
123
124
void
125
gr_hier_block2_detail::disconnect(gr_basic_block_sptr block)
126
{
127
  for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
128
    if (*p == block) {
129
      d_blocks.erase(p);
130
      return;
131
    }
132
  }
133
134
  std::stringstream msg;
135
  msg << "cannot disconnect block " << block << ", not found";
136
  throw std::invalid_argument(msg.str());
137
}
138
139
void 
140
gr_hier_block2_detail::disconnect(gr_basic_block_sptr src, int src_port, 
141
                                  gr_basic_block_sptr dst, int dst_port)
142
{
143
  if (GR_HIER_BLOCK2_DETAIL_DEBUG)
144
    std::cout << "disconnecting: " << gr_endpoint(src, src_port)
145
              << " -> " << gr_endpoint(dst, dst_port) << std::endl;
146
147
  if (src.get() == dst.get())
148
    throw std::invalid_argument("disconnect: source and destination blocks cannot be the same");
149
150
  gr_hier_block2_sptr src_block(cast_to_hier_block2_sptr(src));
151
  gr_hier_block2_sptr dst_block(cast_to_hier_block2_sptr(dst));
152
153
  if (src_block && src.get() != d_owner) {
154
    if (GR_HIER_BLOCK2_DETAIL_DEBUG)
155
      std::cout << "connect: src is hierarchical, clearing parent" << std::endl;
156
    src_block->d_detail->d_parent_detail = 0;
157
  }
158
                
159
  if (dst_block && dst.get() != d_owner) {
160
    if (GR_HIER_BLOCK2_DETAIL_DEBUG)
161
      std::cout << "connect: dst is hierarchical, clearing parent" << std::endl;
162
    dst_block->d_detail->d_parent_detail = 0;
163
  }
164
165
  if (src.get() == d_owner)
166
    return disconnect_input(src_port, dst_port, dst);
167
168
  if (dst.get() == d_owner)
169
    return disconnect_output(dst_port, src_port, src);
170
171
  // Internal connections
172
  d_fg->disconnect(src, src_port, dst, dst_port);
173
}
174
175
// FIXME: ticket:161 will be implemented here
176
void
177
gr_hier_block2_detail::connect_input(int my_port, int port, gr_basic_block_sptr block)
178
{
179
  std::stringstream msg;
180
181
  if (my_port < 0 || my_port >= (signed)d_inputs.size()) {
182
    msg << "input port " << my_port << " out of range for " << block;
183
    throw std::invalid_argument(msg.str());
184
  }
185
186
  if (d_inputs[my_port].block()) {
187
    msg << "external input port " << my_port << " already wired to "
188
        << d_inputs[my_port];
189
    throw std::invalid_argument(msg.str());
190
  }
191
192
  d_inputs[my_port] = gr_endpoint(block, port);
193
}
194
195
void
196
gr_hier_block2_detail::connect_output(int my_port, int port, gr_basic_block_sptr block)
197
{
198
  std::stringstream msg;
199
200
  if (my_port < 0 || my_port >= (signed)d_outputs.size()) {
201
    msg << "output port " << my_port << " out of range for " << block;
202
    throw std::invalid_argument(msg.str());
203
  }
204
205
  if (d_outputs[my_port].block()) {
206
    msg << "external output port " << my_port << " already connected from "
207
        << d_outputs[my_port];
208
    throw std::invalid_argument(msg.str());
209
  }
210
211
  d_outputs[my_port] = gr_endpoint(block, port);
212
}
213
214
void
215
gr_hier_block2_detail::disconnect_input(int my_port, int port, gr_basic_block_sptr block)
216
{
217
  std::stringstream msg;
218
219
  if (my_port < 0 || my_port >= (signed)d_inputs.size()) {
220
    msg << "input port number " << my_port << " out of range for " << block;
221
    throw std::invalid_argument(msg.str());
222
  }
223
224
  if (d_inputs[my_port].block() != block) {
225
    msg << "block " << block << " not assigned to input " 
226
        << my_port << ", can't disconnect";
227
    throw std::invalid_argument(msg.str());
228
  }
229
230
  d_inputs[my_port] = gr_endpoint();
231
}
232
233
void
234
gr_hier_block2_detail::disconnect_output(int my_port, int port, gr_basic_block_sptr block)
235
{
236
  std::stringstream msg;
237
238
  if (my_port < 0 || my_port >= (signed)d_outputs.size()) {
239
    msg << "output port number " << my_port << " out of range for " << block;
240
    throw std::invalid_argument(msg.str());
241
  }
242
243
  if (d_outputs[my_port].block() != block) {
244
    msg << "block " << block << " not assigned to output " 
245
        << my_port << ", can't disconnect";
246
    throw std::invalid_argument(msg.str());
247
  }
248
249
  d_outputs[my_port] = gr_endpoint();
250
}
251
252
gr_endpoint
253
gr_hier_block2_detail::resolve_port(int port, bool is_input)
254
{
255
  std::stringstream msg;
256
257
  if (GR_HIER_BLOCK2_DETAIL_DEBUG)
258
    std::cout << "Resolving port " << port << " as an "
259
              << (is_input ? "input" : "output")
260
              << " of " << d_owner->name() << std::endl;
261
262
  gr_endpoint result;
263
264
  if (is_input) {
265
    if (port < 0 || port >= (signed)d_inputs.size()) {
266
      msg << "resolve_port: input " << port << " is out of range";
267
      throw std::runtime_error(msg.str());
268
    }
269
270
    result = resolve_endpoint(d_inputs[port], true);
271
  }
272
  else {
273
    if (port < 0 || port >= (signed)d_outputs.size()) {
274
      msg << "resolve_port: output " << port << " is out of range";
275
      throw std::runtime_error(msg.str());
276
    }
277
278
    result = resolve_endpoint(d_outputs[port], false);
279
  }
280
281
  if (!result.block()) {
282
    msg << "unable to resolve " 
283
        << (is_input ? "input port " : "output port ")
284
        << port;
285
    throw std::runtime_error(msg.str());
286
  }
287
288
  return result;
289
}
290
291
void
292
gr_hier_block2_detail::disconnect_all()
293
{
294
  d_fg->clear();
295
  d_blocks.clear();
296
  d_inputs.clear();
297
  d_outputs.clear();
298
}
299
300
gr_endpoint
301
gr_hier_block2_detail::resolve_endpoint(const gr_endpoint &endp, bool is_input) const
302
{
303
  std::stringstream msg;
304
305
  // Check if endpoint is a leaf node
306
  if (cast_to_block_sptr(endp.block()))
307
    return endp;
308
  
309
  // Check if endpoint is a hierarchical block
310
  gr_hier_block2_sptr hier_block2(cast_to_hier_block2_sptr(endp.block()));
311
  if (hier_block2) {
312
    if (GR_HIER_BLOCK2_DETAIL_DEBUG)
313
      std::cout << "Resolving endpoint " << endp << " as an " 
314
                << (is_input ? "input" : "output")
315
                << ", recursing" << std::endl;
316
    return hier_block2->d_detail->resolve_port(endp.port(), is_input);
317
  }
318
319
  msg << "unable to resolve" << (is_input ? " input " : " output ")
320
      << "endpoint " << endp;
321
  throw std::runtime_error(msg.str());
322
}
323
324
void
325
gr_hier_block2_detail::flatten_aux(gr_flat_flowgraph_sptr sfg) const
326
{
327
  if (GR_HIER_BLOCK2_DETAIL_DEBUG)
328
    std::cout << "flattening " << d_owner->name() << std::endl;
329
330
  // Add my edges to the flow graph, resolving references to actual endpoints
331
  gr_edge_vector_t edges = d_fg->edges();
332
333
  for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) {
334
    if (GR_HIER_BLOCK2_DETAIL_DEBUG)
335
      std::cout << "Flattening edge " << (*p) << std::endl;
336
337
    gr_endpoint src_endp = resolve_endpoint(p->src(), false);
338
    gr_endpoint dst_endp = resolve_endpoint(p->dst(), true);
339
    sfg->connect(src_endp, dst_endp);
340
  }
341
342
  // Construct unique list of blocks used either in edges or
343
  // by themselves.  I hate STL.
344
  gr_basic_block_vector_t blocks, tmp = d_fg->calc_used_blocks();
345
  std::insert_iterator<gr_basic_block_vector_t> inserter(blocks, blocks.begin());
346
  std::vector<gr_basic_block_sptr>::const_iterator p; // Because flatten_aux is const
347
  for (p = d_blocks.begin(); p != d_blocks.end(); p++) 
348
    tmp.push_back(*p);
349
  sort(tmp.begin(), tmp.end());
350
  unique_copy(tmp.begin(), tmp.end(), inserter);
351
352
  // Recurse hierarchical children
353
  for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
354
    gr_hier_block2_sptr hier_block2(cast_to_hier_block2_sptr(*p));
355
    if (hier_block2)
356
      hier_block2->d_detail->flatten_aux(sfg);
357
  }
358
}
359
360
void
361
gr_hier_block2_detail::lock()
362
{
363
  if (GR_HIER_BLOCK2_DETAIL_DEBUG)
364
    std::cout << "lock: entered in " << this << std::endl;
365
366
  if (d_parent_detail)
367
    d_parent_detail->lock();
368
  else
369
    d_owner->lock();
370
}
371
372
void
373
gr_hier_block2_detail::unlock()
374
{
375
  if (GR_HIER_BLOCK2_DETAIL_DEBUG)
376
    std::cout << "unlock: entered in " << this << std::endl;
377
378
  if (d_parent_detail)
379
    d_parent_detail->unlock();
380
  else
381
    d_owner->unlock();
382
}