Merged latest pmt and mblock into trunk (eb/wip -r4262:4268)
[debian/gnuradio] / mblock / src / lib / mb_mblock_impl.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <mb_mblock_impl.h>
26 #include <mb_mblock.h>
27 #include <mb_protocol_class.h>
28 #include <mb_port.h>
29 #include <mb_exception.h>
30 #include <mb_util.h>
31
32
33 static pmt_t s_self = pmt_intern("self");
34
35 ////////////////////////////////////////////////////////////////////////
36
37 bool 
38 mb_mblock_impl::port_is_defined(const std::string &name)
39 {
40   return d_port_map.count(name) != 0;
41 }
42
43 bool
44 mb_mblock_impl::comp_is_defined(const std::string &name)
45 {
46   return name == "self" || d_comp_map.count(name) != 0;
47 }
48
49 ////////////////////////////////////////////////////////////////////////
50
51 mb_mblock_impl::mb_mblock_impl(mb_mblock *mb)
52   : d_mb(mb)
53 {
54 }
55
56 mb_mblock_impl::~mb_mblock_impl()
57 {
58   d_mb = 0;     // we don't own it
59 }
60
61
62 mb_port_sptr
63 mb_mblock_impl::define_port(const std::string &port_name,
64                             const std::string &protocol_class_name,
65                             bool conjugated,
66                             mb_port::port_type_t port_type)
67 {
68   if (port_type == mb_port::RELAY)
69     throw mbe_base(d_mb, "mb_block_impl::define_port: RELAY ports are not implemented: " + port_name);
70   
71   if (port_is_defined(port_name))
72     throw mbe_duplicate_port(d_mb, port_name);
73
74   mb_port_sptr p = mb_port_sptr(new mb_port(port_name, protocol_class_name,
75                                             conjugated, port_type));
76   d_port_map[port_name] = p;
77   return p;
78 }
79
80 void
81 mb_mblock_impl::define_component(const std::string &name,
82                                  mb_mblock_sptr component)
83 {
84   if (comp_is_defined(name))    // check for duplicate name
85     throw mbe_duplicate_component(d_mb, name);
86
87   d_comp_map[name] = component;
88 }
89
90 void
91 mb_mblock_impl::connect(const std::string &comp_name1, const std::string &port_name1,
92                         const std::string &comp_name2, const std::string &port_name2)
93 {
94   mb_endpoint   ep0 = check_and_resolve_endpoint(comp_name1, port_name1);
95   mb_endpoint   ep1 = check_and_resolve_endpoint(comp_name2, port_name2);
96
97   if (!ports_are_compatible(ep0.port(), ep1.port()))
98     throw mbe_incompatible_ports(d_mb,
99                                  comp_name1, port_name1,
100                                  comp_name2, port_name2);
101   // FIXME more checks?
102
103   d_conn_table.create_conn(ep0, ep1);
104 }
105
106 void
107 mb_mblock_impl::disconnect(const std::string &comp_name1, const std::string &port_name1,
108                            const std::string &comp_name2, const std::string &port_name2)
109 {
110   d_conn_table.disconnect(comp_name1, port_name1, comp_name2, port_name2);
111 }
112
113 void
114 mb_mblock_impl::disconnect_component(const std::string component_name)
115 {
116   d_conn_table.disconnect_component(component_name);
117 }
118
119 void
120 mb_mblock_impl::disconnect_all()
121 {
122   d_conn_table.disconnect_all();
123 }
124
125 int
126 mb_mblock_impl::nconnections() const
127 {
128   return d_conn_table.nconnections();
129 }
130
131 ////////////////////////////////////////////////////////////////////////
132
133 mb_endpoint
134 mb_mblock_impl::check_and_resolve_endpoint(const std::string &comp_name,
135                                            const std::string &port_name)
136 {
137   mb_conn_iter  it;
138   int           which_ep;
139   mb_port_sptr  port = resolve_port(comp_name, port_name);
140
141   // Confirm that we're not trying to connect to the inside of one of
142   // our EXTERNAL ports.  Connections that include "self" as the
143   // component name must be either INTERNAL or RELAY.
144
145   if (comp_name == "self" && port->port_type() == mb_port::EXTERNAL)
146     throw mbe_invalid_port_type(d_mb, comp_name, port_name);
147
148   // Is this endpoint already connected?
149   if (d_conn_table.lookup_conn_by_name(comp_name, port_name, &it, &which_ep))
150     throw mbe_already_connected(d_mb, comp_name, port_name);
151
152   return mb_endpoint(comp_name, port_name, port);
153 }
154
155 mb_port_sptr
156 mb_mblock_impl::resolve_port(const std::string &comp_name,
157                              const std::string &port_name)
158 {
159   if (comp_name == "self"){
160     // Look through our ports.
161     if (!port_is_defined(port_name))
162       throw mbe_no_such_port(d_mb, mb_util::join_names("self", port_name));
163     return d_port_map[port_name];
164   }
165   else {
166     // Look through the specified child's ports.
167     if (!comp_is_defined(comp_name))
168       throw mbe_no_such_component(d_mb, comp_name);
169     
170     mb_mblock_impl_sptr  c_impl = d_comp_map[comp_name]->d_impl;  // childs impl pointer
171     if (!c_impl->port_is_defined(port_name))
172       throw mbe_no_such_port(d_mb, mb_util::join_names(comp_name, port_name));
173
174     mb_port_sptr c_port = c_impl->d_port_map[port_name];
175
176     if (c_port->port_type() == mb_port::INTERNAL)             // can't "see" a child's internal ports
177       throw mbe_no_such_port(d_mb, mb_util::join_names(comp_name, port_name));
178
179     return c_port;
180   }
181 }
182
183
184
185 bool
186 mb_mblock_impl::ports_are_compatible(mb_port_sptr p0, mb_port_sptr p1)
187 {
188   using std::cout;
189   using std::endl;
190
191   pmt_t p0_outgoing = p0->outgoing_message_set();
192   pmt_t p0_incoming = p0->incoming_message_set();
193
194   pmt_t p1_outgoing = p1->outgoing_message_set();
195   pmt_t p1_incoming = p1->incoming_message_set();
196
197   return (pmt_subsetp(p0_outgoing, p1_incoming)
198           && pmt_subsetp(p1_outgoing, p0_incoming));
199 }
200
201 bool
202 mb_mblock_impl::walk_tree(mb_visitor *visitor, const std::string &path)
203 {
204   if (!(*visitor)(d_mb, path))
205     return false;
206
207   mb_comp_map_t::iterator it;
208   for (it = d_comp_map.begin(); it != d_comp_map.end(); ++it)
209     if (!(it->second->walk_tree(visitor, path + "/" + it->first)))
210       return false;
211
212   return true;
213 }
214