Merged mblock work-in-progress (eb/mb r4273:4312) into trunk.
[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_port_simple.h>
30 #include <mb_exception.h>
31 #include <mb_util.h>
32 #include <mb_msg_accepter_smp.h>
33
34
35 static pmt_t s_self = pmt_intern("self");
36
37 ////////////////////////////////////////////////////////////////////////
38
39 bool 
40 mb_mblock_impl::port_is_defined(const std::string &name)
41 {
42   return d_port_map.count(name) != 0;
43 }
44
45 bool
46 mb_mblock_impl::comp_is_defined(const std::string &name)
47 {
48   return name == "self" || d_comp_map.count(name) != 0;
49 }
50
51 ////////////////////////////////////////////////////////////////////////
52
53 mb_mblock_impl::mb_mblock_impl(mb_mblock *mb)
54   : d_mb(mb), d_mb_parent(0)
55 {
56 }
57
58 mb_mblock_impl::~mb_mblock_impl()
59 {
60   d_mb = 0;     // we don't own it
61 }
62
63
64 mb_port_sptr
65 mb_mblock_impl::define_port(const std::string &port_name,
66                             const std::string &protocol_class_name,
67                             bool conjugated,
68                             mb_port::port_type_t port_type)
69 {
70   if (port_type == mb_port::RELAY)
71     throw mbe_base(d_mb,
72              "mb_block_impl::define_port: RELAY ports are not implemented: "
73              + port_name);
74   
75   if (port_is_defined(port_name))
76     throw mbe_duplicate_port(d_mb, port_name);
77
78   mb_port_sptr p =
79     mb_port_sptr(new mb_port_simple(d_mb,
80                                     port_name, protocol_class_name,
81                                     conjugated, port_type));
82   d_port_map[port_name] = p;
83   return p;
84 }
85
86 void
87 mb_mblock_impl::define_component(const std::string &name,
88                                  mb_mblock_sptr component)
89 {
90   if (comp_is_defined(name))    // check for duplicate name
91     throw mbe_duplicate_component(d_mb, name);
92
93   component->d_impl->d_mb_parent = d_mb;    // set component's parent link
94   d_comp_map[name] = component;
95 }
96
97 void
98 mb_mblock_impl::connect(const std::string &comp_name1,
99                         const std::string &port_name1,
100                         const std::string &comp_name2,
101                         const std::string &port_name2)
102 {
103   mb_endpoint   ep0 = check_and_resolve_endpoint(comp_name1, port_name1);
104   mb_endpoint   ep1 = check_and_resolve_endpoint(comp_name2, port_name2);
105
106   if (!ports_are_compatible(ep0.port(), ep1.port()))
107     throw mbe_incompatible_ports(d_mb,
108                                  comp_name1, port_name1,
109                                  comp_name2, port_name2);
110   // FIXME more checks?
111
112   d_conn_table.create_conn(ep0, ep1);
113 }
114
115 void
116 mb_mblock_impl::disconnect(const std::string &comp_name1,
117                            const std::string &port_name1,
118                            const std::string &comp_name2,
119                            const std::string &port_name2)
120 {
121   d_conn_table.disconnect(comp_name1, port_name1, comp_name2, port_name2);
122 }
123
124 void
125 mb_mblock_impl::disconnect_component(const std::string component_name)
126 {
127   d_conn_table.disconnect_component(component_name);
128 }
129
130 void
131 mb_mblock_impl::disconnect_all()
132 {
133   d_conn_table.disconnect_all();
134 }
135
136 int
137 mb_mblock_impl::nconnections() const
138 {
139   return d_conn_table.nconnections();
140 }
141
142 ////////////////////////////////////////////////////////////////////////
143
144 mb_endpoint
145 mb_mblock_impl::check_and_resolve_endpoint(const std::string &comp_name,
146                                            const std::string &port_name)
147 {
148   mb_conn_iter  it;
149   int           which_ep;
150   mb_port_sptr  port = resolve_port(comp_name, port_name);
151
152   // Confirm that we're not trying to connect to the inside of one of
153   // our EXTERNAL ports.  Connections that include "self" as the
154   // component name must be either INTERNAL or RELAY.
155
156   if (comp_name == "self" && port->port_type() == mb_port::EXTERNAL)
157     throw mbe_invalid_port_type(d_mb, comp_name, port_name);
158
159   // Is this endpoint already connected?
160   if (d_conn_table.lookup_conn_by_name(comp_name, port_name, &it, &which_ep))
161     throw mbe_already_connected(d_mb, comp_name, port_name);
162
163   return mb_endpoint(comp_name, port_name, port);
164 }
165
166 mb_port_sptr
167 mb_mblock_impl::resolve_port(const std::string &comp_name,
168                              const std::string &port_name)
169 {
170   if (comp_name == "self"){
171     // Look through our ports.
172     if (!port_is_defined(port_name))
173       throw mbe_no_such_port(d_mb, mb_util::join_names("self", port_name));
174     return d_port_map[port_name];
175   }
176   else {
177     // Look through the specified child's ports.
178     if (!comp_is_defined(comp_name))
179       throw mbe_no_such_component(d_mb, comp_name);
180     
181     mb_mblock_impl_sptr  c_impl = d_comp_map[comp_name]->d_impl;  // childs impl pointer
182     if (!c_impl->port_is_defined(port_name))
183       throw mbe_no_such_port(d_mb, mb_util::join_names(comp_name, port_name));
184
185     mb_port_sptr c_port = c_impl->d_port_map[port_name];
186
187     if (c_port->port_type() == mb_port::INTERNAL) // can't "see" a child's internal ports
188       throw mbe_no_such_port(d_mb, mb_util::join_names(comp_name, port_name));
189
190     return c_port;
191   }
192 }
193
194
195
196 bool
197 mb_mblock_impl::ports_are_compatible(mb_port_sptr p0, mb_port_sptr p1)
198 {
199   using std::cout;
200   using std::endl;
201
202   pmt_t p0_outgoing = p0->outgoing_message_set();
203   pmt_t p0_incoming = p0->incoming_message_set();
204
205   pmt_t p1_outgoing = p1->outgoing_message_set();
206   pmt_t p1_incoming = p1->incoming_message_set();
207
208   return (pmt_subsetp(p0_outgoing, p1_incoming)
209           && pmt_subsetp(p1_outgoing, p0_incoming));
210 }
211
212 bool
213 mb_mblock_impl::walk_tree(mb_visitor *visitor, const std::string &path)
214 {
215   if (!(*visitor)(d_mb, path))
216     return false;
217
218   mb_comp_map_t::iterator it;
219   for (it = d_comp_map.begin(); it != d_comp_map.end(); ++it)
220     if (!(it->second->walk_tree(visitor, path + "/" + it->first)))
221       return false;
222
223   return true;
224 }
225
226 mb_msg_accepter_sptr
227 mb_mblock_impl::make_accepter(const std::string port_name)
228 {
229   mb_msg_accepter *ma =
230     new mb_msg_accepter_smp(d_mb->shared_from_this(),
231                             pmt_intern(port_name));
232
233   return mb_msg_accepter_sptr(ma);
234 }