Merged mblock work-in-progress from eb/mb -r4341:4633 into trunk.
authoreb <eb@221aa14e-8319-0410-a670-987f0aec2ac5>
Mon, 26 Feb 2007 00:40:37 +0000 (00:40 +0000)
committereb <eb@221aa14e-8319-0410-a670-987f0aec2ac5>
Mon, 26 Feb 2007 00:40:37 +0000 (00:40 +0000)
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@4634 221aa14e-8319-0410-a670-987f0aec2ac5

33 files changed:
mblock/src/lib/Makefile.am
mblock/src/lib/mb_common.h
mblock/src/lib/mb_connection.cc
mblock/src/lib/mb_connection.h
mblock/src/lib/mb_endpoint.cc [new file with mode: 0644]
mblock/src/lib/mb_endpoint.h
mblock/src/lib/mb_exception.cc
mblock/src/lib/mb_exception.h
mblock/src/lib/mb_mblock.cc
mblock/src/lib/mb_mblock.h
mblock/src/lib/mb_mblock_impl.cc
mblock/src/lib/mb_mblock_impl.h
mblock/src/lib/mb_msg_queue.cc
mblock/src/lib/mb_msg_queue.h
mblock/src/lib/mb_port.cc
mblock/src/lib/mb_port.h
mblock/src/lib/mb_port_detail.cc [deleted file]
mblock/src/lib/mb_port_detail.h [deleted file]
mblock/src/lib/mb_port_simple.cc
mblock/src/lib/mb_port_simple.h
mblock/src/lib/mb_runtime.cc
mblock/src/lib/mb_runtime.h
mblock/src/lib/mb_runtime_impl.cc [deleted file]
mblock/src/lib/mb_runtime_impl.h [deleted file]
mblock/src/lib/mb_runtime_single_threaded.cc [new file with mode: 0644]
mblock/src/lib/mb_runtime_single_threaded.h [new file with mode: 0644]
mblock/src/lib/mb_util.cc
mblock/src/lib/qa_mblock.cc
mblock/src/lib/qa_mblock_prims.cc
mblock/src/lib/qa_mblock_send.cc [new file with mode: 0644]
mblock/src/lib/qa_mblock_send.h [new file with mode: 0644]
pmt/src/lib/pmt.cc
pmt/src/lib/pmt.h

index c049bd34735e258f4fed21267f645fe06a7a184a..e1922fcd83aea6435d7416c5517bba20b41b0f84 100644 (file)
@@ -21,7 +21,7 @@
 
 include $(top_srcdir)/Makefile.common
 
-INCLUDES = $(PMT_INCLUDES) $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES)
+INCLUDES = $(DEFINES) $(OMNITHREAD_INCLUDES) $(PMT_INCLUDES) $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES)
 
 TESTS = test_mblock
 
@@ -33,6 +33,7 @@ EXTRA_DIST =
 # These are the source files that go into the mblock shared library
 libmblock_la_SOURCES =                 \
        mb_connection.cc                \
+       mb_endpoint.cc                  \
        mb_exception.cc                 \
        mb_mblock.cc                    \
        mb_mblock_impl.cc               \
@@ -44,7 +45,7 @@ libmblock_la_SOURCES =                        \
        mb_port_simple.cc               \
        mb_protocol_class.cc            \
        mb_runtime.cc                   \
-       mb_runtime_impl.cc              \
+       mb_runtime_single_threaded.cc   \
        mb_util.cc                      
 
 
@@ -53,6 +54,7 @@ libmblock_la_LDFLAGS = $(NO_UNDEFINED) -avoid-version
 
 # link the library against the c++ standard library
 libmblock_la_LIBADD =                  \
+       $(OMNITHREAD_LIBS)              \
        $(PMT_LIBS)                     \
        -lstdc++                        
 
@@ -67,6 +69,7 @@ include_HEADERS =                     \
        mb_port_simple.h                \
        mb_protocol_class.h             \
        mb_runtime.h                    \
+       mb_runtime_single_threaded.h    \
        mb_util.h                       
 
 
@@ -75,17 +78,17 @@ noinst_HEADERS =                    \
        mb_endpoint.h                   \
        mb_mblock_impl.h                \
        mb_msg_accepter_smp.h           \
-       mb_port_detail.h                \
-       mb_runtime_impl.h               \
        qa_mblock.h                     \
-       qa_mblock_prims.h               
+       qa_mblock_prims.h               \
+       qa_mblock_send.h                
 
 
 # Build the qa code into its own library
 
 libmblock_qa_la_SOURCES =              \
        qa_mblock.cc                    \
-       qa_mblock_prims.cc              
+       qa_mblock_prims.cc              \
+       qa_mblock_send.cc               
 
 
 # magic flags
index 13837a8c55037c8d3b34c6cdd6779795b4972bae..3c9ec8e1625aa026159a509273386c63b590010d 100644 (file)
@@ -67,8 +67,8 @@ mb_pri_clamp(mb_pri_t p)
 class mb_runtime;
 typedef boost::shared_ptr<mb_runtime> mb_runtime_sptr;
 
-class mb_runtime_impl;
-typedef boost::shared_ptr<mb_runtime_impl> mb_runtime_impl_sptr;
+//class mb_runtime_impl;
+//typedef boost::shared_ptr<mb_runtime_impl> mb_runtime_impl_sptr;
 
 class mb_mblock;
 typedef boost::shared_ptr<mb_mblock> mb_mblock_sptr;
@@ -79,8 +79,8 @@ typedef boost::shared_ptr<mb_mblock_impl> mb_mblock_impl_sptr;
 class mb_port;
 typedef boost::shared_ptr<mb_port> mb_port_sptr;
 
-class mb_port_detail;
-typedef boost::shared_ptr<mb_port_detail> mb_port_detail_sptr;
+//class mb_port_detail;
+//typedef boost::shared_ptr<mb_port_detail> mb_port_detail_sptr;
 
 class mb_msg_accepter;
 typedef boost::shared_ptr<mb_msg_accepter> mb_msg_accepter_sptr;
index 526de6506c3d5714d398567c959adff8852a0d08..56338cd8ee738f27e07acecf6639e74d3fe16b1c 100644 (file)
@@ -52,17 +52,17 @@ mb_conn_table::lookup_conn_by_name(const std::string &component_name,
 }
 
 bool
-mb_conn_table::lookup_conn_by_port(mb_port_sptr port,
+mb_conn_table::lookup_conn_by_port(const mb_port *port,
                                   mb_conn_iter *itp, int *which_ep)
 {
   mb_conn_iter end = d_connections.end();
   for (mb_conn_iter it = d_connections.begin(); it != end; ++it){
-    if (it->d_ep[0].port() == port){
+    if (it->d_ep[0].port().get() == port){
       *itp = it;
       *which_ep = 0;
       return true;
     }
-    if (it->d_ep[1].port() == port){
+    if (it->d_ep[1].port().get() == port){
       *itp = it;
       *which_ep = 1;
       return true;
index 859d84677c027f55499c0d9b7948e0cbbe280329..caac95790780ca1ab98600b5718bb96be74aeaeb 100644 (file)
@@ -53,8 +53,8 @@ public:
                      mb_conn_iter *it, int *which_ep);
 
   bool
-  lookup_conn_by_port(mb_port_sptr port,
-                      mb_conn_iter *it, int *which_ep);
+  lookup_conn_by_port(const mb_port *port,
+                     mb_conn_iter *it, int *which_ep);
 
   void
   create_conn(const mb_endpoint &ep0, const mb_endpoint &ep1);
diff --git a/mblock/src/lib/mb_endpoint.cc b/mblock/src/lib/mb_endpoint.cc
new file mode 100644 (file)
index 0000000..3fe2d08
--- /dev/null
@@ -0,0 +1,49 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ * 
+ * This file is part of GNU Radio
+ * 
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ * 
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <mb_endpoint.h>
+
+bool
+mb_endpoint::inside_of_relay_port_p() const
+{
+  return d_port->port_type() == mb_port::RELAY && d_component_name == "self";
+}
+
+pmt_t
+mb_endpoint::incoming_message_set() const
+{
+  if (inside_of_relay_port_p())                        // swap incoming and outgoing
+    return port()->outgoing_message_set();
+  else
+    return port()->incoming_message_set();
+}
+
+pmt_t
+mb_endpoint::outgoing_message_set() const
+{
+  if (inside_of_relay_port_p())                        // swap incoming and outgoing
+    return port()->incoming_message_set();
+  else
+    return port()->outgoing_message_set();
+}
index 90ae6fe67911738537b389f7af6b6ace0f0757c1..82b0feb7e82a022abf70a62bdb16de97d50335a6 100644 (file)
@@ -47,6 +47,12 @@ public:
   const std::string &component_name() const { return d_component_name; }
   const std::string &port_name() const { return d_port_name; }
   mb_port_sptr port() const { return d_port; }
+
+  //! Does this endpoint represent the inside of a relay port
+  bool inside_of_relay_port_p() const;
+
+  pmt_t        incoming_message_set() const;
+  pmt_t        outgoing_message_set() const;
 };
 
 #endif /* INCLUDED_MB_ENDPOINT_H */
index 4282f6dd0708a8140409457110f58fc19d673483..4d4ca70b1256c32636d05c28634c51d21a766060 100644 (file)
@@ -33,6 +33,11 @@ mbe_base::mbe_base(mb_mblock *mb, const std::string &msg)
 {
 }
 
+mbe_not_implemented::mbe_not_implemented(mb_mblock *mb, const std::string &msg)
+  : mbe_base(mb, "Not implemented: " + msg)
+{
+}
+
 mbe_no_such_component::mbe_no_such_component(mb_mblock *mb, const std::string &component_name)
   : mbe_base(mb, "No such component: " + component_name)
 {
index 188acf48ff9dc411235cfadc57786f446366232e..40abd1c962402256f89fb2b5500b62ebf23d760a 100644 (file)
@@ -32,6 +32,11 @@ public:
   mbe_base(mb_mblock *mb, const std::string &msg);
 };
 
+class mbe_not_implemented : public mbe_base
+{
+public:
+  mbe_not_implemented(mb_mblock *mb, const std::string &msg);
+};
 
 
 class mbe_no_such_component : public mbe_base
index 9ab1fbbff3eae70d6b27ae6ceb03a1ec83143b90..bf9f5b0ce1c09de3266965564da3e8b8a7cf7c55 100644 (file)
 #include <mb_mblock_impl.h>
 
 
+mb_visitor::~mb_visitor()
+{
+  // nop base case for virtual destructor.
+}
+
+
 mb_mblock::mb_mblock()
   : d_impl(mb_mblock_impl_sptr(new mb_mblock_impl(this)))
 {
@@ -113,3 +119,21 @@ mb_mblock::walk_tree(mb_visitor *visitor, const std::string &path)
 {
   return d_impl->walk_tree(visitor, path);
 }
+
+std::string
+mb_mblock::fullname() const
+{
+  return d_impl->fullname();
+}
+
+void
+mb_mblock::set_fullname(const std::string name)
+{
+  d_impl->set_fullname(name);
+}
+
+mb_mblock *
+mb_mblock::parent() const
+{
+  return d_impl->mblock_parent();
+}
index c656f90f226e05c4f5392738e60cc808750afe4a..00e4051c070ff2881d4f1039c5d930d71e857d98 100644 (file)
@@ -35,8 +35,7 @@ class mb_visitor
 {
 public:
   virtual ~mb_visitor();
-  bool operator()(mb_mblock *mblock, const std::string &path) { return visit(mblock, path); }
-  virtual bool visit(mb_mblock *mblock, const std::string &path) = 0;
+  virtual bool operator()(mb_mblock *mblock, const std::string &path) = 0;
 };
 
 // ----------------------------------------------------------------------
@@ -69,6 +68,7 @@ protected:
    */
   mb_mblock();
 
+public:
   /*!
    * \brief Called by the runtime system to execute the initial
    * transition of the finite state machine.
@@ -77,6 +77,7 @@ protected:
    */
   virtual void init_fsm();
 
+protected:
   /*!
    * \brief Called by the runtime system when there's a message to handle.
    *
@@ -178,13 +179,21 @@ protected:
 public:
   virtual ~mb_mblock();
 
+  void set_fullname(const std::string name);
+  
+  //! Return full name of this block
+  std::string fullname() const;
+
+  //! Return the parent of this mblock, or 0 if we're the top-level block.
+  mb_mblock *parent() const;
+
   /*!
    * \brief Perform a pre-order depth-first traversal of the hierarchy.
    *
    * The traversal stops and returns false if any call to visitor returns false.
    */
   bool
-  walk_tree(mb_visitor *visitor, const std::string &path="");
+  walk_tree(mb_visitor *visitor, const std::string &path="top");
 
 
   //! \implementation
index f4fa523ee5397bb4ef5eb6e7a80d0e3a046374f7..a9e81e8de86676663fca9e462f1d4a8aad120c3c 100644 (file)
@@ -51,7 +51,7 @@ mb_mblock_impl::comp_is_defined(const std::string &name)
 ////////////////////////////////////////////////////////////////////////
 
 mb_mblock_impl::mb_mblock_impl(mb_mblock *mb)
-  : d_mb(mb), d_mb_parent(0)
+  : d_mb(mb), d_mb_parent(0), d_fullname("<unknown>")
 {
 }
 
@@ -67,11 +67,6 @@ mb_mblock_impl::define_port(const std::string &port_name,
                            bool conjugated,
                            mb_port::port_type_t port_type)
 {
-  if (port_type == mb_port::RELAY)
-    throw mbe_base(d_mb,
-            "mb_block_impl::define_port: RELAY ports are not implemented: "
-            + port_name);
-  
   if (port_is_defined(port_name))
     throw mbe_duplicate_port(d_mb, port_name);
 
@@ -90,7 +85,7 @@ mb_mblock_impl::define_component(const std::string &name,
   if (comp_is_defined(name))   // check for duplicate name
     throw mbe_duplicate_component(d_mb, name);
 
-  component->d_impl->d_mb_parent = d_mb;    // set component's parent link
+  component->d_impl->d_mb_parent = d_mb;     // set component's parent link
   d_comp_map[name] = component;
 }
 
@@ -103,7 +98,7 @@ mb_mblock_impl::connect(const std::string &comp_name1,
   mb_endpoint  ep0 = check_and_resolve_endpoint(comp_name1, port_name1);
   mb_endpoint  ep1 = check_and_resolve_endpoint(comp_name2, port_name2);
 
-  if (!ports_are_compatible(ep0.port(), ep1.port()))
+  if (!endpoints_are_compatible(ep0, ep1))
     throw mbe_incompatible_ports(d_mb,
                                 comp_name1, port_name1,
                                 comp_name2, port_name2);
@@ -194,16 +189,14 @@ mb_mblock_impl::resolve_port(const std::string &comp_name,
 
 
 bool
-mb_mblock_impl::ports_are_compatible(mb_port_sptr p0, mb_port_sptr p1)
+mb_mblock_impl::endpoints_are_compatible(const mb_endpoint &ep0,
+                                        const mb_endpoint &ep1)
 {
-  using std::cout;
-  using std::endl;
-
-  pmt_t p0_outgoing = p0->outgoing_message_set();
-  pmt_t p0_incoming = p0->incoming_message_set();
+  pmt_t p0_outgoing = ep0.outgoing_message_set();
+  pmt_t p0_incoming = ep0.incoming_message_set();
 
-  pmt_t p1_outgoing = p1->outgoing_message_set();
-  pmt_t p1_incoming = p1->incoming_message_set();
+  pmt_t p1_outgoing = ep1.outgoing_message_set();
+  pmt_t p1_incoming = ep1.incoming_message_set();
 
   return (pmt_subsetp(p0_outgoing, p1_incoming)
          && pmt_subsetp(p1_outgoing, p0_incoming));
@@ -232,3 +225,35 @@ mb_mblock_impl::make_accepter(const std::string port_name)
 
   return mb_msg_accepter_sptr(ma);
 }
+
+bool
+mb_mblock_impl::lookup_other_endpoint(const mb_port *port, mb_endpoint *ep)
+{
+  mb_conn_iter it;
+  int          which_ep = 0;
+
+  if (!d_conn_table.lookup_conn_by_port(port, &it, &which_ep))
+    return false;
+  
+  *ep = it->d_ep[which_ep^1];
+  return true;
+}
+
+mb_mblock_sptr
+mb_mblock_impl::component(const std::string &comp_name)
+{
+  if (comp_name == "self")
+    return d_mb->shared_from_this();
+
+  if (d_comp_map.count(comp_name) == 0)
+    return mb_mblock_sptr();   // null pointer
+
+  return d_comp_map[comp_name];
+}
+
+void
+mb_mblock_impl::set_fullname(const std::string &name)
+{
+  d_fullname = name;
+}
+
index 1e62dd8d7e1930ac117e4e4f30142b591bf6ace4..38cb5d5f6250c9dcf7ef7c541a74271f48fc80b8 100644 (file)
@@ -40,6 +40,8 @@ class mb_mblock_impl : boost::noncopyable
   mb_mblock                   *d_mb;           // pointer to our associated mblock
   mb_mblock                   *d_mb_parent;    // pointer to our parent
 
+  std::string                  d_fullname;     // hierarchical name
+
   mb_port_map_t                        d_port_map;     // our ports
   mb_comp_map_t                        d_comp_map;     // our components
   mb_conn_table                        d_conn_table;   // our connections
@@ -145,6 +147,34 @@ public:
   mb_msg_queue &
   msgq() { return d_msgq; }
 
+  //! Return full name of this block
+  std::string fullname() const { return d_fullname; }
+
+  //! Set the name of this block
+  void set_fullname(const std::string &name);
+
+  /*!
+   * \brief If bound, store endpoint from the other end of the connection.
+   *
+   * \param port [in]  port the port that we're searching for.
+   * \param ep   [out] the other end point from the matching connection.
+   *
+   * \returns true iff there's a matching connection.
+   */
+  bool
+  lookup_other_endpoint(const mb_port *port, mb_endpoint *ep);
+
+
+  mb_mblock *
+  mblock() const { return d_mb; }
+
+  mb_mblock *
+  mblock_parent() const { return d_mb_parent; }
+
+  mb_mblock_sptr
+  component(const std::string &comp_name);
+
+
   /*
    * Our implementation methods
    */
@@ -164,7 +194,8 @@ private:
               const std::string &port_name);
 
   static bool
-  ports_are_compatible(mb_port_sptr p0, mb_port_sptr p1);
+  endpoints_are_compatible(const mb_endpoint &ep0,
+                          const mb_endpoint &ep1);
 
 };
 
index e6269492595d53ec59c4ec9875be4f7136411586..8afdea07ea445a01ab626abc6eedcb22f9f51aba 100644 (file)
@@ -38,7 +38,7 @@ mb_msg_queue::~mb_msg_queue()
 void
 mb_msg_queue::insert(mb_message_sptr msg)
 {
-  // omni_mutex_lock   l(d_mutex);             FIXME
+  omni_mutex_lock      l(d_mutex);
   
   mb_pri_t q = mb_pri_clamp(msg->priority());
 
@@ -57,7 +57,7 @@ mb_msg_queue::insert(mb_message_sptr msg)
 mb_message_sptr
 mb_msg_queue::get_highest_pri_msg()
 {
-  // omni_mutex_lock   l(d_mutex);             FIXME
+  omni_mutex_lock      l(d_mutex);
 
   // FIXME use bitmap and ffz to find best queue in O(1)
 
index 2749e6a59f5bfe336611ae200b26e62b8fd87796..57f6dd0b3dd8cc233432155b479551f2221279dd 100644 (file)
@@ -22,7 +22,7 @@
 #define INCLUDED_MB_MSG_QUEUE_H
 
 #include <mb_common.h>
-//#include <omnithread.h>      FIXME
+#include <omnithread.h>
 
 /*!
  * \brief priority queue for mblock messages
@@ -37,7 +37,7 @@ class mb_msg_queue : boost::noncopyable
     bool empty_p() const { return head == 0; }
   };
 
-  // omni_mutex        d_mutex;        FIXME
+  omni_mutex   d_mutex;
 
   // FIXME add bitmap to indicate which queues are non-empty.
   subq         d_queue[MB_NPRI];
index 5c9f544c4baa4c79a37996a545243e32af105a73..b265db2dc5a4a8aec7b0e4bbfe90ca3dfe8dc8f2 100644 (file)
@@ -24,7 +24,6 @@
 #endif
 
 #include <mb_port.h>
-#include <mb_port_detail.h>
 #include <mb_protocol_class.h>
 
 mb_port::mb_port(mb_mblock *mblock,
index 59a508c92e9d62e539af651c9dbd53a37da43fee..3c3e963687edbb23ce6e34e868967f7742441e58 100644 (file)
@@ -54,6 +54,8 @@ protected:
          bool conjugated,
          mb_port::port_type_t port_type);
 
+  mb_mblock *mblock() const { return d_mblock; }
+
 public:
   std::string  port_name() const { return d_port_name; }
   pmt_t                protocol_class() const { return d_protocol_class; }
diff --git a/mblock/src/lib/mb_port_detail.cc b/mblock/src/lib/mb_port_detail.cc
deleted file mode 100644 (file)
index 3a58fa2..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006 Free Software Foundation, Inc.
- * 
- * This file is part of GNU Radio
- * 
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- * 
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <mb_port_detail.h>
-
-mb_port_detail::mb_port_detail()
-{
-}
-
-mb_port_detail::~mb_port_detail()
-{
-}
diff --git a/mblock/src/lib/mb_port_detail.h b/mblock/src/lib/mb_port_detail.h
deleted file mode 100644 (file)
index 3623a1b..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006 Free Software Foundation, Inc.
- * 
- * This file is part of GNU Radio
- * 
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- * 
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef INCLUDED_MB_PORT_DETAIL_H
-#define INCLUDED_MB_PORT_DETAIL_H
-
-#include <mb_port.h>
-
-class mb_port_detail : boost::noncopyable
-{
-public:
-  mb_port_detail();
-  ~mb_port_detail();
-};
-
-
-#endif /* INCLUDED_MB_PORT_DETAIL_H */
index 4896df3a6c16d08a34e1637ba8b8af093c2da2a9..1315b617223c5f21b1e7b91183a0b88c12ee87b3 100644 (file)
 
 #include <mb_port_simple.h>
 #include <mb_msg_accepter.h>
+#include <mb_exception.h>
+#include <mb_mblock.h>
+#include <mb_mblock_impl.h>
+#include <assert.h>
+
 
 mb_port_simple::mb_port_simple(mb_mblock *mblock,
                               const std::string &port_name,
@@ -43,17 +48,84 @@ mb_port_simple::~mb_port_simple()
 void
 mb_port_simple::send(pmt_t signal, pmt_t data, pmt_t metadata, mb_pri_t priority)
 {
-  mb_msg_accepter_sptr  accepter = find_accepter();
+  if (port_type() == mb_port::RELAY)  // Can't send directly to a RELAY port
+    throw mbe_invalid_port_type(mblock(), mblock()->fullname(), port_name());
+
+  mb_msg_accepter_sptr  accepter = find_accepter(this);
   if (accepter)
     (*accepter)(signal, data, metadata, priority);
 }
 
+
 mb_msg_accepter_sptr
-mb_port_simple::find_accepter()
+mb_port_simple::find_accepter(mb_port_simple *start)
 {
+  mb_port_simple       *p = start;
+  mb_port_simple       *pp = 0;
+  mb_mblock            *context = 0;
+  mb_endpoint          peer_ep;
   mb_msg_accepter_sptr r;
 
-  // FIXME, actually do the work ;)
+  // Set up initial context.
+
+  switch(p->port_type()){
+  case mb_port::INTERNAL:      // binding is in our name space
+    context = p->mblock();
+    break;
+
+  case mb_port::EXTERNAL:      // binding is in parent's name space
+    context = p->mblock()->parent();
+    break;
+
+  default:
+    throw std::logic_error("Can't happen: mb_port_simple::find_accepter [1]");
+  }
+
+
+ traverse:
+
+  if (!context->impl()->lookup_other_endpoint(p, &peer_ep))
+    return mb_msg_accepter_sptr();     // not bound
+  
+  pp = dynamic_cast<mb_port_simple *>(peer_ep.port().get());   // peer port
+  assert(pp);
 
-  return r;
+  switch (pp->port_type()){    
+  case mb_port::INTERNAL:      // Terminate here.
+  case mb_port::EXTERNAL:
+    r = pp->make_accepter();
+    // FIXME cache the result
+    return r;
+
+  case mb_port::RELAY:         // Traverse to other side of relay port.
+    if (peer_ep.inside_of_relay_port_p()){
+      // We're on inside of relay port, headed out.
+      p = pp;
+      context = p->mblock()->parent();
+
+      // Corner case: we're attempting to traverse a relay port on the border
+      // of the top block...
+      if (!context)
+       return mb_msg_accepter_sptr();  // not bound
+
+      goto traverse;
+    }
+    else {
+      // We're on the outside of relay port, headed in.
+      p = pp;
+      context = p->mblock();
+      goto traverse;
+    }
+    break;
+
+  default:
+    throw std::logic_error("Can't happen: mb_port_simple::find_accepter [2]");
+  }
+}
+
+
+mb_msg_accepter_sptr
+mb_port_simple::make_accepter()
+{
+  return d_mblock->impl()->make_accepter(port_name());
 }
index 3ce3e3cb1b8c180b8a13d48ddf14b25672982424..5cfbd3dc0870354115c9b980bb0c12aa77423980 100644 (file)
 class mb_port_simple : public mb_port
 {
 protected:
+  static mb_msg_accepter_sptr
+  find_accepter(mb_port_simple *start);
+
   mb_msg_accepter_sptr
-  find_accepter();
+  make_accepter();
 
 public:
   mb_port_simple(mb_mblock *mblock,
index 8c396f190a498a95ad6d4cf5503778929eebc77c..fa762270b0c6b434584823d8453444990fba0d83 100644 (file)
 #endif
 
 #include <mb_runtime.h>
-#include <mb_runtime_impl.h>
+#include <mb_runtime_single_threaded.h>
 
 mb_runtime_sptr
 mb_make_runtime()
 {
-  return mb_runtime_sptr(new mb_runtime());
-}
-
-mb_runtime::mb_runtime()
-  : d_impl(mb_runtime_impl_sptr(new mb_runtime_impl()))
-{
-  // FIXME
-  
+  return mb_runtime_sptr(new mb_runtime_single_threaded());
 }
 
 mb_runtime::~mb_runtime()
 {
-  // FIXME
-}
-
-bool
-mb_runtime::run()
-{
-  // FIXME
-  return true;
+  // nop
 }
index c4eb206bd6270671f6c0b9efb2e36d3de44eff94..9b47537b2d74116b37ee6c3700a05db4967bc571 100644 (file)
 #include <mb_common.h>
 
 /*!
- * \brief Public constructor for mb_runtime.
+ * \brief Public constructor (factory) for mb_runtime objects.
  */
 mb_runtime_sptr mb_make_runtime();
 
 /*!
- * \brief Runtime support for m-blocks
+ * \brief Abstract runtime support for m-blocks
  *
  * There should generally be only a single instance of this class.
- *
- * It should be created by the top-level initialization code,
- * and that instance should be passed into the constructor of the
- * top-level mblock.
  */
 class mb_runtime : boost::noncopyable
 {
-private:
-  mb_runtime_impl_sptr         d_impl;           // implementation details
-
-  mb_runtime();
-
-  friend mb_runtime_sptr mb_make_runtime();
-
 public:
-  ~mb_runtime();
+  mb_runtime(){}
+  virtual ~mb_runtime();
 
   /*!
-   * \brief Run the mblocks...
+   * \brief Run the mblock hierarchy rooted at \p top
    *
    * This routine turns into the m-block scheduler, and
    * blocks until the system is shutdown.
    *
+   * \param top top-level mblock
    * \returns true if the system ran successfully.
    */
-  bool run();
+  virtual bool run(mb_mblock_sptr top) = 0;
 };
 
 #endif /* INCLUDED_MB_RUNTIME_H */
diff --git a/mblock/src/lib/mb_runtime_impl.cc b/mblock/src/lib/mb_runtime_impl.cc
deleted file mode 100644 (file)
index 5a354ef..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006 Free Software Foundation, Inc.
- * 
- * This file is part of GNU Radio
- * 
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- * 
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <mb_runtime_impl.h>
-
-mb_runtime_impl::mb_runtime_impl()
-{
-  // FIXME
-}
-
-mb_runtime_impl::~mb_runtime_impl()
-{
-  // FIXME
-}
diff --git a/mblock/src/lib/mb_runtime_impl.h b/mblock/src/lib/mb_runtime_impl.h
deleted file mode 100644 (file)
index 2325a35..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006 Free Software Foundation, Inc.
- * 
- * This file is part of GNU Radio
- * 
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- * 
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef INCLUDED_MB_RUNTIME_IMPL_H
-#define INCLUDED_MB_RUNTIME_IMPL_H
-
-#include <mb_common.h>
-
-/*!
- * \brief The private implementation details of the runtime system.
- */
-class mb_runtime_impl : boost::noncopyable
-{
-private:
-  friend class mb_runtime;
-
-  mb_runtime_impl();
-
-public:
-  ~mb_runtime_impl();
-};
-
-
-#endif /* INCLUDED_MB_RUNTIME_IMPL_H */
diff --git a/mblock/src/lib/mb_runtime_single_threaded.cc b/mblock/src/lib/mb_runtime_single_threaded.cc
new file mode 100644 (file)
index 0000000..dc8597a
--- /dev/null
@@ -0,0 +1,60 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ * 
+ * This file is part of GNU Radio
+ * 
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ * 
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <mb_runtime_single_threaded.h>
+#include <mb_mblock.h>
+
+
+mb_runtime_single_threaded::mb_runtime_single_threaded()
+{
+  // nop for now
+}
+
+mb_runtime_single_threaded::~mb_runtime_single_threaded()
+{
+  // nop for now
+}
+
+bool
+mb_runtime_single_threaded::run(mb_mblock_sptr top)
+{
+  class initial_visitor : public mb_visitor
+  {
+  public:
+    bool operator()(mb_mblock *mblock, const std::string &path)
+    {
+      mblock->set_fullname(path);
+      mblock->init_fsm();
+      return true;
+    }
+  };
+
+  initial_visitor      visitor;
+
+  d_top = top;         // remember top of tree
+
+  d_top->walk_tree(&visitor);
+
+  return true;
+}
diff --git a/mblock/src/lib/mb_runtime_single_threaded.h b/mblock/src/lib/mb_runtime_single_threaded.h
new file mode 100644 (file)
index 0000000..b56e0a5
--- /dev/null
@@ -0,0 +1,42 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ * 
+ * This file is part of GNU Radio
+ * 
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ * 
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_MB_RUNTIME_SINGLE_THREADED_H
+#define INCLUDED_MB_RUNTIME_SINGLE_THREADED_H
+
+#include <mb_runtime.h>
+
+/*!
+ * \brief Concrete runtime that uses a single thread for all work.
+ */
+class mb_runtime_single_threaded : public mb_runtime
+{
+  mb_mblock_sptr       d_top;          // top mblock
+
+public:
+  mb_runtime_single_threaded();
+  ~mb_runtime_single_threaded();
+
+  bool run(mb_mblock_sptr top);
+};
+
+
+
+#endif /* INCLUDED_MB_RUNTIME_SINGLE_THREADED_H */
index 8a14d4c06097e8dff8c4867582370df270022f8c..03f0469fba4db8cb99edd084a3dfd5be3741fd61 100644 (file)
@@ -30,5 +30,5 @@ std::string
 mb_util::join_names(const std::string &comp_name,
                    const std::string &port_name)
 {
-  return comp_name + "/" + port_name;
+  return comp_name + ":" + port_name;
 }
index 72dccc053374a963f5b4c1dd0f4ec1fc6df45865..4be4a23c3c02f1bf8d4085af9627338e44c0b2df 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <qa_mblock.h>
 #include <qa_mblock_prims.h>
+#include <qa_mblock_send.h>
 
 CppUnit::TestSuite *
 qa_mblock::suite()
@@ -33,6 +34,7 @@ qa_mblock::suite()
   CppUnit::TestSuite   *s = new CppUnit::TestSuite("mblock");
 
   s->addTest (qa_mblock_prims::suite());
+  s->addTest (qa_mblock_send::suite());
   
   return s;
 }
index fc3452f968eff304ea889260d314e2e340c053fd..7385a17ef1b42e4924ecb5695780df8c45d550a8 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <qa_mblock_prims.h>
 #include <cppunit/TestAssert.h>
 #include <mb_mblock.h>
@@ -103,32 +107,16 @@ qa_mblock_prims::test_define_ports()
 
   // define the protocol class
   pmt_t pc = mb_make_protocol_class(pmt_intern("cs-protocol"),
-                                   pmt_cons(pmt_intern("start"),
-                                            pmt_cons(pmt_intern("stop"),
-                                                     PMT_NIL)),
+                                   pmt_list2(pmt_intern("start"),
+                                             pmt_intern("stop")),
                                    PMT_NIL);
 
   // std::cout << "pc = " << pc << '\n';
 
   mb_mblock_sptr mb2 = mb_mblock_sptr(new dp_2());
 
-  // intf = mb2->peer_interface();
-  // CPPUNIT_ASSERT_EQUAL(size_t(1), intf.size());
-  // CPPUNIT_ASSERT(pmt_eq(s_cs, intf[0]->port_name()));
-
-
   // raises pmt_exception because of duplicate port definition of "cs"
   CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_3()), mbe_duplicate_port);
-
-#if 0
-  try {
-    mb_mblock_sptr mb2 = mb_mblock_sptr(new dp_2());
-  }
-  catch (pmt_exception &e){
-    std::cerr << e.msg() << ' ' << e.obj() << '\n';
-  }
-#endif
-
 }
 
 // ================================================================
@@ -321,13 +309,13 @@ void
 qa_mblock_prims::test_connect()
 {
   // define the protocol class
-  mb_make_protocol_class(pmt_intern("data"),                           // name of class
-                        pmt_cons(pmt_intern("data"), PMT_NIL),         // in
-                        PMT_NIL);                                      // out
+  mb_make_protocol_class(pmt_intern("data"),                   // name of class
+                        pmt_list1(pmt_intern("data")),         // in
+                        PMT_NIL);                              // out
 
-  mb_make_protocol_class(pmt_intern("i/o"),                            // name of class
-                        pmt_cons(pmt_intern("in"), PMT_NIL),           // in
-                        pmt_cons(pmt_intern("out"), PMT_NIL));         // out
+  mb_make_protocol_class(pmt_intern("i/o"),                    // name of class
+                        pmt_list1(pmt_intern("in")),           // in
+                        pmt_list1(pmt_intern("out")));         // out
 
 
   mb_runtime_sptr      rt = mb_make_runtime();
@@ -416,4 +404,3 @@ qa_mblock_prims::test_make_accepter()
   CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg()->data()));
   CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg()->data()));
 }
-
diff --git a/mblock/src/lib/qa_mblock_send.cc b/mblock/src/lib/qa_mblock_send.cc
new file mode 100644 (file)
index 0000000..ff86adb
--- /dev/null
@@ -0,0 +1,450 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006,2007 Free Software Foundation, Inc.
+ * 
+ * This file is part of GNU Radio
+ * 
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ * 
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qa_mblock_send.h>
+#include <cppunit/TestAssert.h>
+#include <mb_mblock.h>
+#include <mb_runtime.h>
+#include <mb_protocol_class.h>
+#include <mb_exception.h>
+#include <mb_msg_queue.h>
+#include <mb_message.h>
+#include <mb_mblock_impl.h>
+#include <mb_msg_accepter.h>
+#include <stdio.h>
+
+static pmt_t s_data    = pmt_intern("data");
+static pmt_t s_status  = pmt_intern("status");
+static pmt_t s_control = pmt_intern("control");
+static pmt_t s_p0   = pmt_intern("p0");
+static pmt_t s_p1   = pmt_intern("p1");
+static pmt_t s_p2   = pmt_intern("p2");
+static pmt_t s_p3   = pmt_intern("p3");
+static pmt_t s_e1   = pmt_intern("e1");
+static pmt_t s_r1   = pmt_intern("r1");
+
+static void
+define_protocol_classes()
+{
+  // Defined from client point-of-view.
+  mb_make_protocol_class(pmt_intern("qa-send-cs"),     // name
+                        pmt_list1(s_status),           // incoming
+                        pmt_list1(s_control));         // outgoing
+
+}
+
+// ================================================================
+//                    test_simple_routing
+// ================================================================
+
+// sub-block for test_simple_routing
+
+class sr1 : public mb_mblock
+{
+  mb_port_sptr d_p1;
+  mb_port_sptr d_p2;
+  mb_port_sptr d_p3;
+
+public:
+  sr1();
+  ~sr1();
+  void init_fsm();
+};
+
+sr1::sr1()
+{
+  d_p1 = define_port("p1", "qa-send-cs", true, mb_port::EXTERNAL);
+  d_p2 = define_port("p2", "qa-send-cs", true, mb_port::EXTERNAL);
+  d_p3 = define_port("p3", "qa-send-cs", false, mb_port::EXTERNAL);
+}
+
+sr1::~sr1(){}
+  
+void
+sr1::init_fsm()
+{
+  // std::cout << fullname() << "[sr1]: init_fsm\n";
+
+  // send two messages to each port
+  pmt_t our_name = pmt_intern(fullname());
+  d_p1->send(s_status, pmt_list3(our_name, s_p1, pmt_from_long(0)));
+  d_p1->send(s_status, pmt_list3(our_name, s_p1, pmt_from_long(1)));
+
+  d_p2->send(s_status, pmt_list3(our_name, s_p2, pmt_from_long(0)));
+  d_p2->send(s_status, pmt_list3(our_name, s_p2, pmt_from_long(1)));
+}
+
+// ----------------------------------------------------------------
+
+// top-level container block for test_simple_routing
+class sr0 : public mb_mblock
+{
+  mb_port_sptr d_p0;
+  
+public:
+  sr0();
+  ~sr0();
+  void init_fsm();
+};
+
+sr0::sr0()
+{
+  d_p0 = define_port("p0", "qa-send-cs", false, mb_port::INTERNAL);
+
+  define_component("mb1", mb_mblock_sptr(new sr1()));
+  define_component("mb2", mb_mblock_sptr(new sr1()));
+
+  connect("self", "p0", "mb1", "p1");
+  connect("mb1", "p2", "mb2", "p3");
+  connect("mb1", "p3", "mb2", "p2");
+}
+
+sr0::~sr0(){}
+
+void
+sr0::init_fsm()
+{
+  // std::cout << fullname() << "[sr0]: init_fsm\n";
+
+  // send two messages to p0
+  pmt_t our_name = pmt_intern(fullname());
+  d_p0->send(s_control, pmt_list3(our_name, s_p0, pmt_from_long(0)));
+  d_p0->send(s_control, pmt_list3(our_name, s_p0, pmt_from_long(1)));
+}
+  
+// ----------------------------------------------------------------
+
+/*
+ * This tests basic message routing using INTERNAL and EXTERNAL ports.
+ * It does not rely on the guts of the runtime being complete,
+ * which is good, because at the time this is being written, it isn't.
+ */
+void
+qa_mblock_send::test_simple_routing()
+{
+  define_protocol_classes();
+
+  mb_message_sptr msg;
+
+  mb_runtime_sptr rt = mb_make_runtime();
+  mb_mblock_sptr mb0 = mb_mblock_sptr(new sr0());
+  rt->run(mb0);
+
+  // Reach into the guts and see if the messages ended up where they should have
+
+  // mb0 should have received two messages sent from mb1 via its p1
+  msg = mb0->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  // std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p0, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/mb1"), s_p1, pmt_from_long(0)),
+                          msg->data()));
+
+  msg = mb0->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  // std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p0, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/mb1"), s_p1, pmt_from_long(1)),
+                          msg->data()));
+
+  // mb1 should have received
+  //   two messages from mb0 via its p0 and
+  //   two messages from mb2 via its p3
+
+  mb_mblock_sptr mb1 = mb0->impl()->component("mb1");
+
+  msg = mb1->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  // std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p1, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top"), s_p0, pmt_from_long(0)),
+                          msg->data()));
+
+  msg = mb1->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  // std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p1, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top"), s_p0, pmt_from_long(1)),
+                          msg->data()));
+
+  msg = mb1->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  // std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p3, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/mb2"), s_p2, pmt_from_long(0)),
+                          msg->data()));
+
+  msg = mb1->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  // std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p3, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/mb2"), s_p2, pmt_from_long(1)),
+                          msg->data()));
+
+
+  // mb2 should have received
+  //   two messages from mb2 via its p2
+
+  mb_mblock_sptr mb2 = mb0->impl()->component("mb2");
+
+  msg = mb2->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  // std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p3, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/mb1"), s_p2, pmt_from_long(0)),
+                          msg->data()));
+
+  msg = mb2->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  // std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p3, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/mb1"), s_p2, pmt_from_long(1)),
+                          msg->data()));
+}
+
+// ================================================================
+//                    test_relay_routing_1
+// ================================================================
+
+// internal block for test_relay_routing
+
+class rr2 : public mb_mblock
+{
+  mb_port_sptr d_p1;
+  mb_port_sptr d_p2;
+
+public:
+  rr2();
+  ~rr2();
+  void init_fsm();
+};
+
+rr2::rr2()
+{
+  d_p1 = define_port("p1", "qa-send-cs", true,  mb_port::EXTERNAL);
+  d_p2 = define_port("p2", "qa-send-cs", false, mb_port::EXTERNAL);
+}
+
+rr2::~rr2(){}
+  
+void
+rr2::init_fsm()
+{
+  // std::cout << fullname() << "[rr2]: init_fsm\n";
+
+  // send two messages via p1
+  pmt_t our_name = pmt_intern(fullname());
+  d_p1->send(s_status, pmt_list3(our_name, s_p1, pmt_from_long(0)));
+  d_p1->send(s_status, pmt_list3(our_name, s_p1, pmt_from_long(1)));
+}
+
+// ----------------------------------------------------------------
+
+// intermediate block for test_relay_routing
+
+class rr1 : public mb_mblock
+{
+  mb_port_sptr d_p1;
+  mb_port_sptr d_p2;
+
+public:
+  rr1();
+  ~rr1();
+};
+
+rr1::rr1()
+{
+  d_p1 = define_port("p1", "qa-send-cs", true,  mb_port::RELAY);
+  d_p2 = define_port("p2", "qa-send-cs", false, mb_port::RELAY);
+
+  define_component("c0", mb_mblock_sptr(new rr2()));
+
+  connect("self", "p1", "c0", "p1");
+  connect("self", "p2", "c0", "p2");
+}
+
+rr1::~rr1(){}
+
+// ----------------------------------------------------------------
+
+// top-level container for test_relay_routing
+
+class rr0_a : public mb_mblock
+{
+public:
+  rr0_a();
+  ~rr0_a();
+};
+
+rr0_a::rr0_a()
+{
+  define_component("c0", mb_mblock_sptr(new rr1()));
+  define_component("c1", mb_mblock_sptr(new rr2()));
+
+  connect("c0", "p1", "c1", "p2");
+  connect("c0", "p2", "c1", "p1");
+}
+
+rr0_a::~rr0_a(){}
+
+
+/*
+ * This tests basic message routing using RELAY and EXTERNAL ports.
+ * It does not rely on the guts of the runtime being complete,
+ * which is good, because at the time this is being written, it isn't.
+ */
+void
+qa_mblock_send::test_relay_routing_1()
+{
+  mb_message_sptr msg;
+
+  mb_runtime_sptr rt = mb_make_runtime();
+  mb_mblock_sptr  top = mb_mblock_sptr(new rr0_a());
+  rt->run(top);
+
+  // Reach into the guts and see if the messages ended up where they should have
+
+  mb_mblock_sptr c0 = top->impl()->component("c0");
+  mb_mblock_sptr c0c0 = c0->impl()->component("c0");
+
+  mb_mblock_sptr c1 = top->impl()->component("c1");
+
+  // c0c0 should have received
+  //   two message from c1 via its p2
+
+  msg = c0c0->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  //std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c1"), s_p1, pmt_from_long(0)),
+                          msg->data()));
+
+  msg = c0c0->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  //std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c1"), s_p1, pmt_from_long(1)),
+                          msg->data()));
+
+  // c1 should have received
+  //   two message from c0c0 via its p2
+
+  msg = c1->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  //std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c0/c0"), s_p1, pmt_from_long(0)),
+                          msg->data()));
+
+  msg = c1->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  //std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c0/c0"), s_p1, pmt_from_long(1)),
+                          msg->data()));
+}
+
+// ================================================================
+//                    test_relay_routing_2
+// ================================================================
+
+// top-level container for test_relay_routing_2
+
+class rr0_b : public mb_mblock
+{
+public:
+  rr0_b();
+  ~rr0_b();
+};
+
+rr0_b::rr0_b()
+{
+  define_component("c0", mb_mblock_sptr(new rr1()));
+  define_component("c1", mb_mblock_sptr(new rr1()));
+
+  connect("c0", "p1", "c1", "p2");
+  connect("c0", "p2", "c1", "p1");
+}
+
+rr0_b::~rr0_b(){}
+
+
+/*
+ * This tests basic message routing using RELAY and EXTERNAL ports.
+ * It does not rely on the guts of the runtime being complete,
+ * which is good, because at the time this is being written, it isn't.
+ */
+void
+qa_mblock_send::test_relay_routing_2()
+{
+  mb_message_sptr msg;
+
+  mb_runtime_sptr rt = mb_make_runtime();
+  mb_mblock_sptr  top = mb_mblock_sptr(new rr0_b());
+  rt->run(top);
+
+  // Reach into the guts and see if the messages ended up where they should have
+
+  mb_mblock_sptr c0 = top->impl()->component("c0");
+  mb_mblock_sptr c0c0 = c0->impl()->component("c0");
+
+  mb_mblock_sptr c1 = top->impl()->component("c1");
+  mb_mblock_sptr c1c0 = c1->impl()->component("c0");
+
+  // c0c0 should have received
+  //   two message from c1c0 via its p2
+
+  msg = c0c0->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  // std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c1/c0"), s_p1, pmt_from_long(0)),
+                          msg->data()));
+
+  msg = c0c0->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  // std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c1/c0"), s_p1, pmt_from_long(1)),
+                          msg->data()));
+
+  // c1c0 should have received
+  //   two message from c0c0 via its p2
+
+  msg = c1c0->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  // std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c0/c0"), s_p1, pmt_from_long(0)),
+                          msg->data()));
+
+  msg = c1c0->impl()->msgq().get_highest_pri_msg();
+  CPPUNIT_ASSERT(msg);
+  // std::cerr << msg->data() << std::endl;
+  CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+  CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c0/c0"), s_p1, pmt_from_long(1)),
+                          msg->data()));
+}
diff --git a/mblock/src/lib/qa_mblock_send.h b/mblock/src/lib/qa_mblock_send.h
new file mode 100644 (file)
index 0000000..6aeee7a
--- /dev/null
@@ -0,0 +1,43 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006,2007 Free Software Foundation, Inc.
+ * 
+ * This file is part of GNU Radio
+ * 
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ * 
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef INCLUDED_QA_MBLOCK_SEND_H
+#define INCLUDED_QA_MBLOCK_SEND_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+class qa_mblock_send : public CppUnit::TestCase {
+
+  CPPUNIT_TEST_SUITE(qa_mblock_send);
+  CPPUNIT_TEST(test_simple_routing);
+  CPPUNIT_TEST(test_relay_routing_1);
+  CPPUNIT_TEST(test_relay_routing_2);
+  CPPUNIT_TEST_SUITE_END();
+
+ private:
+  void test_simple_routing();
+  void test_relay_routing_1();
+  void test_relay_routing_2();
+};
+
+#endif /* INCLUDED_QA_MBLOCK_SEND_H */
+
index 036a5f8ba1bed6b9ad8b4f3ac96644666b6beee4..cf6547b572f6834a149ae963fc4634e94f354e1b 100644 (file)
@@ -841,3 +841,27 @@ pmt_subsetp(pmt_t list1, pmt_t list2)
   }
   return true;
 }
+
+pmt_t
+pmt_list1(pmt_t x1)
+{
+  return pmt_cons(x1, PMT_NIL);
+}
+
+pmt_t
+pmt_list2(pmt_t x1, pmt_t x2)
+{
+  return pmt_cons(x1, pmt_cons(x2, PMT_NIL));
+}
+
+pmt_t
+pmt_list3(pmt_t x1, pmt_t x2, pmt_t x3)
+{
+  return pmt_cons(x1, pmt_cons(x2, pmt_cons(x3, PMT_NIL)));
+}
+
+pmt_t
+pmt_list4(pmt_t x1, pmt_t x2, pmt_t x3, pmt_t x4)
+{
+  return pmt_cons(x1, pmt_cons(x2, pmt_cons(x3, pmt_cons(x4, PMT_NIL))));
+}
index 2cb032e5b8e473e7313dc00c940506f77980a52b..030637c4d2318a64d925fa8bcdac0c591e7529bc 100644 (file)
@@ -548,6 +548,26 @@ pmt_t pmt_member(pmt_t obj, pmt_t list);
  */
 bool pmt_subsetp(pmt_t list1, pmt_t list2);
 
+/*!
+ * \brief Return a list of length 1 containing \p x1
+ */
+pmt_t pmt_list1(pmt_t x1);
+
+/*!
+ * \brief Return a list of length 2 containing \p x1, \p x2
+ */
+pmt_t pmt_list2(pmt_t x1, pmt_t x2);
+
+/*!
+ * \brief Return a list of length 3 containing \p x1, \p x2, \p x3
+ */
+pmt_t pmt_list3(pmt_t x1, pmt_t x2, pmt_t x3);
+
+/*!
+ * \brief Return a list of length 4 containing \p x1, \p x2, \p x3, \p x4
+ */
+pmt_t pmt_list4(pmt_t x1, pmt_t x2, pmt_t x3, pmt_t x4);
+
 /*
  * ------------------------------------------------------------------------
  *                          read / write