From: eb Date: Sat, 13 Jan 2007 06:39:33 +0000 (+0000) Subject: Merged latest pmt and mblock into trunk (eb/wip -r4262:4268) X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=29c73e79ef50525b56d8e9f89808baace75fae82;p=debian%2Fgnuradio Merged latest pmt and mblock into trunk (eb/wip -r4262:4268) git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@4269 221aa14e-8319-0410-a670-987f0aec2ac5 --- diff --git a/mblock/README b/mblock/README index dae3147b..ca91edfa 100644 --- a/mblock/README +++ b/mblock/README @@ -19,4 +19,4 @@ # Boston, MA 02110-1301, USA. # -The "Message block" implementation. +The "Message block" implementation, a work in progress... diff --git a/mblock/src/lib/Makefile.am b/mblock/src/lib/Makefile.am index 28304f0c..41747300 100644 --- a/mblock/src/lib/Makefile.am +++ b/mblock/src/lib/Makefile.am @@ -23,7 +23,7 @@ include $(top_srcdir)/Makefile.common INCLUDES = $(PMT_INCLUDES) $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES) -# TESTS = test_mblock +TESTS = test_mblock lib_LTLIBRARIES = libmblock.la libmblock-qa.la @@ -32,8 +32,17 @@ EXTRA_DIST = # These are the source files that go into the mblock shared library libmblock_la_SOURCES = \ + mb_connection.cc \ + mb_exception.cc \ + mb_mblock.cc \ + mb_mblock_impl.cc \ mb_message.cc \ - mb_protocol_class.cc + mb_port.cc \ + mb_port_detail.cc \ + mb_protocol_class.cc \ + mb_runtime.cc \ + mb_runtime_impl.cc \ + mb_util.cc # magic flags @@ -45,38 +54,52 @@ libmblock_la_LIBADD = \ -lstdc++ include_HEADERS = \ - mb_mblock.h \ mb_common.h \ + mb_exception.h \ + mb_mblock.h \ mb_message.h \ - mb_protocol_class.h + mb_port.h \ + mb_protocol_class.h \ + mb_runtime.h \ + mb_util.h + -noinst_HEADERS = +noinst_HEADERS = \ + mb_connection.h \ + mb_endpoint.h \ + mb_mblock_impl.h \ + mb_port_detail.h \ + mb_runtime_impl.h \ + qa_mblock.h \ + qa_mblock_prims.h # Build the qa code into its own library -libmblock_qa_la_SOURCES = +libmblock_qa_la_SOURCES = \ + qa_mblock.cc \ + qa_mblock_prims.cc # magic flags libmblock_qa_la_LDFLAGS = $(NO_UNDEFINED) -avoid-version # link the library against the c++ standard library -libmblock_qa_la_LIBADD = \ - libmblock.la \ - $(CPPUNIT_LIBS) \ +libmblock_qa_la_LIBADD = \ + libmblock.la \ + $(CPPUNIT_LIBS) \ -lstdc++ -#noinst_PROGRAMS = \ -# test_mblock +noinst_PROGRAMS = \ + test_mblock LIBMBLOCK = libmblock.la LIBMBLOCKQA = libmblock-qa.la $(LIBMBLOCK) -#test_mblock_SOURCES = test_mblock.cc -#test_mblock_LDADD = $(LIBMBLOCKQA) +test_mblock_SOURCES = test_mblock.cc +test_mblock_LDADD = $(LIBMBLOCKQA) CLEANFILES = $(BUILT_SOURCES) *.pyc diff --git a/mblock/src/lib/mb_common.h b/mblock/src/lib/mb_common.h index abeb0657..f54fa56a 100644 --- a/mblock/src/lib/mb_common.h +++ b/mblock/src/lib/mb_common.h @@ -22,8 +22,32 @@ #define INCLUDED_MB_COMMON_H #include +#include +#include +#include + typedef unsigned int mb_pri_t; static const mb_pri_t MB_PRI_DEFAULT = 5; + +class mb_runtime; +typedef boost::shared_ptr mb_runtime_sptr; + +class mb_runtime_impl; +typedef boost::shared_ptr mb_runtime_impl_sptr; + +class mb_mblock; +typedef boost::shared_ptr mb_mblock_sptr; + +class mb_mblock_impl; +typedef boost::shared_ptr mb_mblock_impl_sptr; + +class mb_port; +typedef boost::shared_ptr mb_port_sptr; + +class mb_port_detail; +typedef boost::shared_ptr mb_port_detail_sptr; + + #endif /* INCLUDED_MB_COMMON_H */ diff --git a/mblock/src/lib/mb_connection.cc b/mblock/src/lib/mb_connection.cc new file mode 100644 index 00000000..526de650 --- /dev/null +++ b/mblock/src/lib/mb_connection.cc @@ -0,0 +1,126 @@ +/* -*- 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 +#endif + +#include + +bool +mb_conn_table::lookup_conn_by_name(const std::string &component_name, + const std::string &port_name, + 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].component_name() == component_name + && it->d_ep[0].port_name() == port_name){ + *itp = it; + *which_ep = 0; + return true; + } + + if (it->d_ep[1].component_name() == component_name + && it->d_ep[1].port_name() == port_name){ + *itp = it; + *which_ep = 1; + return true; + } + } + + return false; +} + +bool +mb_conn_table::lookup_conn_by_port(mb_port_sptr 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){ + *itp = it; + *which_ep = 0; + return true; + } + if (it->d_ep[1].port() == port){ + *itp = it; + *which_ep = 1; + return true; + } + } + + return false; +} + +void +mb_conn_table::create_conn(const mb_endpoint &ep0, const mb_endpoint &ep1) +{ + d_connections.push_back(mb_connection(ep0, ep1)); +} + +void +mb_conn_table::disconnect(const std::string &comp_name1, const std::string &port_name1, + const std::string &comp_name2, const std::string &port_name2) +{ + mb_conn_iter it; + int which_ep; + + // look for comp_name1/port_name1 + bool found = lookup_conn_by_name(comp_name1, port_name1, &it, &which_ep); + + if (!found) // no error if not found + return; + + // FIXME if/when we do replicated ports, we may have one-to-many, + // or many-to-many bindings. For now, be paranoid + assert(it->d_ep[which_ep^1].component_name() == comp_name2); + assert(it->d_ep[which_ep^1].port_name() == port_name2); + + d_connections.erase(it); // Poof! +} + +void +mb_conn_table::disconnect_component(const std::string component_name) +{ + mb_conn_iter next; + mb_conn_iter end = d_connections.end(); + for (mb_conn_iter it = d_connections.begin(); it != end; it = next){ + if (it->d_ep[0].component_name() == component_name + || it->d_ep[1].component_name() == component_name) + next = d_connections.erase(it); // Poof! + else + next = ++it; + } +} + +void +mb_conn_table::disconnect_all() +{ + d_connections.clear(); // All gone! +} + +int +mb_conn_table::nconnections() const +{ + return d_connections.size(); +} diff --git a/mblock/src/lib/mb_connection.h b/mblock/src/lib/mb_connection.h new file mode 100644 index 00000000..859d8467 --- /dev/null +++ b/mblock/src/lib/mb_connection.h @@ -0,0 +1,78 @@ +/* -*- 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_CONNECTION_H +#define INCLUDED_MB_CONNECTION_H + +#include +#include + +/*! + * \brief Representation of a connection + */ +struct mb_connection { + mb_endpoint d_ep[2]; + + mb_connection(const mb_endpoint &ep0, const mb_endpoint &ep1){ + d_ep[0] = ep0; + d_ep[1] = ep1; + } +}; + +typedef std::list::iterator mb_conn_iter; +typedef std::list::const_iterator mb_conn_const_iter; + +/*! + * \brief data structure that keeps track of connections + */ +class mb_conn_table { + std::list d_connections; + +public: + bool + lookup_conn_by_name(const std::string &component_name, + const std::string &port_name, + mb_conn_iter *it, int *which_ep); + + bool + lookup_conn_by_port(mb_port_sptr port, + mb_conn_iter *it, int *which_ep); + + void + create_conn(const mb_endpoint &ep0, const mb_endpoint &ep1); + + + void + disconnect(const std::string &comp_name1, const std::string &port_name1, + const std::string &comp_name2, const std::string &port_name2); + + void + disconnect_component(const std::string component_name); + + void + disconnect_all(); + + int + nconnections() const; + +}; + +#endif /* INCLUDED_MB_CONNECTION_H */ diff --git a/mblock/src/lib/mb_endpoint.h b/mblock/src/lib/mb_endpoint.h new file mode 100644 index 00000000..90ae6fe6 --- /dev/null +++ b/mblock/src/lib/mb_endpoint.h @@ -0,0 +1,52 @@ +/* -*- 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_ENDPOINT_H +#define INCLUDED_MB_ENDPOINT_H + +#include +#include + +/*! + * \brief Endpoint specification for connection + */ +class mb_endpoint +{ + std::string d_component_name; + std::string d_port_name; + mb_port_sptr d_port; // the port object that this maps to + +public: + mb_endpoint(){} + + mb_endpoint(const std::string &component_name, + const std::string &port_name, + mb_port_sptr port) + : d_component_name(component_name), + d_port_name(port_name), + d_port(port) {} + + 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; } +}; + +#endif /* INCLUDED_MB_ENDPOINT_H */ diff --git a/mblock/src/lib/mb_exception.cc b/mblock/src/lib/mb_exception.cc new file mode 100644 index 00000000..4282f6dd --- /dev/null +++ b/mblock/src/lib/mb_exception.cc @@ -0,0 +1,82 @@ +/* -*- 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 +#endif + +#include +#include +#include + + +mbe_base::mbe_base(mb_mblock *mb, const std::string &msg) + : logic_error(msg) // FIXME extract block class name and id and add to 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) +{ +} + + +mbe_duplicate_component::mbe_duplicate_component(mb_mblock *mb, const std::string &component_name) + : mbe_base(mb, "Duplicate component: " + component_name) +{ +} + +mbe_no_such_port::mbe_no_such_port(mb_mblock *mb, const std::string &port_name) + : mbe_base(mb, "No such port: " + port_name) +{ +} + +mbe_duplicate_port::mbe_duplicate_port(mb_mblock *mb, const std::string &port_name) + : mbe_base(mb, "Duplicate port: " + port_name) +{ +} + +mbe_already_connected::mbe_already_connected(mb_mblock *mb, + const std::string &comp_name, + const std::string &port_name) + : mbe_base(mb, "Port already connected: " + mb_util::join_names(comp_name, port_name)) +{ +} + + + +mbe_incompatible_ports::mbe_incompatible_ports(mb_mblock *mb, + const std::string &comp1_name, + const std::string &port1_name, + const std::string &comp2_name, + const std::string &port2_name) + : mbe_base(mb, "Incompatible ports: " + + mb_util::join_names(comp1_name, port1_name) + " " + + mb_util::join_names(comp2_name, port2_name)) +{ +} + +mbe_invalid_port_type::mbe_invalid_port_type(mb_mblock *mb, + const std::string &comp_name, + const std::string &port_name) + : mbe_base(mb, "Invalid port type for connection: " + mb_util::join_names(comp_name, port_name)) +{ +} diff --git a/mblock/src/lib/mb_exception.h b/mblock/src/lib/mb_exception.h new file mode 100644 index 00000000..188acf48 --- /dev/null +++ b/mblock/src/lib/mb_exception.h @@ -0,0 +1,87 @@ +/* -*- 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_EXCEPTION_H +#define INCLUDED_MB_EXCEPTION_H + +#include + +class mb_mblock; + + +class mbe_base : public std::logic_error +{ +public: + mbe_base(mb_mblock *mb, const std::string &msg); +}; + + + +class mbe_no_such_component : public mbe_base +{ +public: + mbe_no_such_component(mb_mblock *, const std::string &component_name); +}; + +class mbe_duplicate_component : public mbe_base +{ +public: + mbe_duplicate_component(mb_mblock *, const std::string &component_name); +}; + +class mbe_no_such_port : public mbe_base +{ +public: + mbe_no_such_port(mb_mblock *, const std::string &port_name); +}; + +class mbe_duplicate_port : public mbe_base +{ +public: + mbe_duplicate_port(mb_mblock *, const std::string &port_name); +}; + +class mbe_already_connected : public mbe_base +{ +public: + mbe_already_connected(mb_mblock *, const std::string &comp_name, + const std::string &port_name); +}; + +class mbe_incompatible_ports : public mbe_base +{ +public: + mbe_incompatible_ports(mb_mblock *, + const std::string &comp1_name, + const std::string &port1_name, + const std::string &comp2_name, + const std::string &port2_name); +}; + +class mbe_invalid_port_type : public mbe_base +{ +public: + mbe_invalid_port_type(mb_mblock *, const std::string &comp_name, + const std::string &port_name); +}; + + + +#endif /* INCLUDED_MB_EXCEPTION_H */ diff --git a/mblock/src/lib/mb_mblock.cc b/mblock/src/lib/mb_mblock.cc new file mode 100644 index 00000000..9ab1fbbf --- /dev/null +++ b/mblock/src/lib/mb_mblock.cc @@ -0,0 +1,115 @@ +/* -*- 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 +#endif + +#include +#include + + +mb_mblock::mb_mblock() + : d_impl(mb_mblock_impl_sptr(new mb_mblock_impl(this))) +{ +} + +mb_mblock::~mb_mblock() +{ + disconnect_all(); + + // FIXME more? +} + + +void +mb_mblock::init_fsm() +{ + // default implementation does nothing +} + +void +mb_mblock::handle_message(mb_message_sptr msg) +{ + // default implementation does nothing +} + +//////////////////////////////////////////////////////////////////////// +// Forward other methods to implementation class // +//////////////////////////////////////////////////////////////////////// + +mb_port_sptr +mb_mblock::define_port(const std::string &port_name_string, + const std::string &protocol_class_name, + bool conjugated, + mb_port::port_type_t port_type) +{ + return d_impl->define_port(port_name_string, protocol_class_name, + conjugated, port_type); +} + +void +mb_mblock::define_component(const std::string &component_name, + mb_mblock_sptr component) +{ + d_impl->define_component(component_name, component); +} + +void +mb_mblock::connect(const std::string &comp_name1, const std::string &port_name1, + const std::string &comp_name2, const std::string &port_name2) +{ + d_impl->connect(comp_name1, port_name1, + comp_name2, port_name2); +} + + +void +mb_mblock::disconnect(const std::string &comp_name1, const std::string &port_name1, + const std::string &comp_name2, const std::string &port_name2) +{ + d_impl->disconnect(comp_name1, port_name1, + comp_name2, port_name2); +} + +void +mb_mblock::disconnect_component(const std::string component_name) +{ + d_impl->disconnect_component(component_name); +} + +void +mb_mblock::disconnect_all() +{ + d_impl->disconnect_all(); +} + +int +mb_mblock::nconnections() const +{ + return d_impl->nconnections(); +} + +bool +mb_mblock::walk_tree(mb_visitor *visitor, const std::string &path) +{ + return d_impl->walk_tree(visitor, path); +} diff --git a/mblock/src/lib/mb_mblock.h b/mblock/src/lib/mb_mblock.h index db9d0a33..ce0065f2 100644 --- a/mblock/src/lib/mb_mblock.h +++ b/mblock/src/lib/mb_mblock.h @@ -22,5 +22,167 @@ #define INCLUDED_MB_MBLOCK_H #include +#include +#include + + +/*! + * Abstract class implementing visitor pattern + * \ingroup internal + */ +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; +}; + +// ---------------------------------------------------------------------- + +/*! + * \brief Parent class for all message passing blocks + * + * Subclass this to define your mblocks. + */ +class mb_mblock : boost::noncopyable +{ +private: + mb_mblock_impl_sptr d_impl; // implementation details + + friend class mb_runtime; + friend class mb_mblock_impl; + +protected: + /*! + * \brief mblock constructor. + * + * Initializing all mblocks in the system is a 3 step procedure. + * + * The top level mblock's constructor is run. That constructor (a) + * registers all of its ports using define_port, (b) constructs and + * registers any subcomponents it may have via the define_component + * method, and then (c) issues connect calls to wire its + * subcomponents together. + */ + mb_mblock(); + + /*! + * \brief Called by the runtime system to execute the initial + * transition of the finite state machine. + * + * Override this to initialize your finite state machine. + */ + virtual void init_fsm(); + + /*! + * \brief Called by the runtime system when there's a message to handle. + * + * Override this to define your behavior. + * + * Do not issue any potentially blocking calls in this method. This + * includes things such reads or writes on sockets, pipes or slow + * i/o devices. + */ + virtual void handle_message(mb_message_sptr msg); + + /*! + * \brief Define a port. + * + * EXTERNAL and RELAY ports are part of our peer interface. + * INTERNAL ports are used to talk to sub-components. + * + * \param port_name The name of the port (must be unique within this mblock). + * \param protocol_class_name The name of the protocol class associated with + * this port. It must already be defined. + * \param conjugated Are the incoming and outgoing message sets swapped? + * \param port_type INTERNAL, EXTERNAL or RELAY. + */ + mb_port_sptr + define_port(const std::string &port_name, + const std::string &protocol_class_name, + bool conjugated, + mb_port::port_type_t port_type); + + /*! + * \brief Define a subcomponent by name. + * + * Called within the constructor to tell the system the + * names and identities of our sub-component mblocks. + * + * \param component_name The name of the sub-component (must be unique with this mblock). + * \param component The sub-component instance. + */ + void + define_component(const std::string &component_name, + mb_mblock_sptr component); + + /*! + * \brief connect endpoint_1 to endpoint_2 + * + * \param comp_name1 component on one of the connection + * \param port_name1 the name of the port on comp1 + * \param comp_name2 component on the other end the connection + * \param port_name2 the name of the port on comp2 + * + * An endpoint is specified by the component's local name (given as + * component_name in the call to register_component) and the name of + * the port on that component. + * + * To connect an internal or relay port, use "self" as the component name. + */ + void + connect(const std::string &comp_name1, const std::string &port_name1, + const std::string &comp_name2, const std::string &port_name2); + + /*! + * \brief disconnect endpoint_1 from endpoint_2 + * + * \param comp_name1 component on one of the connection + * \param port_name1 the name of the port on comp1 + * \param comp_name2 component on the other end the connection + * \param port_name2 the name of the port on comp2 + * + * An endpoint is specified by the component's local name (given as + * component_name in the call to register_component) and the name of + * the port on that component. + * + * To disconnect an internal or relay port, use "self" as the component name. + */ + void + disconnect(const std::string &comp_name1, const std::string &port_name1, + const std::string &comp_name2, const std::string &port_name2); + + /*! + * \brief disconnect all connections to specified component + * \param component_name component to disconnect + */ + void + disconnect_component(const std::string component_name); + + /*! + * \brief disconnect all connections to all components + */ + void + disconnect_all(); + + /*! + * \brief Return number of connections (QA mostly) + */ + int + nconnections() const; + + +public: + virtual ~mb_mblock(); + + /*! + * \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=""); +}; + #endif /* INCLUDED_MB_MBLOCK_H */ diff --git a/mblock/src/lib/mb_mblock_impl.cc b/mblock/src/lib/mb_mblock_impl.cc new file mode 100644 index 00000000..8a9efe2b --- /dev/null +++ b/mblock/src/lib/mb_mblock_impl.cc @@ -0,0 +1,214 @@ +/* -*- 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 +#endif +#include +#include +#include +#include +#include +#include + + +static pmt_t s_self = pmt_intern("self"); + +//////////////////////////////////////////////////////////////////////// + +bool +mb_mblock_impl::port_is_defined(const std::string &name) +{ + return d_port_map.count(name) != 0; +} + +bool +mb_mblock_impl::comp_is_defined(const std::string &name) +{ + return name == "self" || d_comp_map.count(name) != 0; +} + +//////////////////////////////////////////////////////////////////////// + +mb_mblock_impl::mb_mblock_impl(mb_mblock *mb) + : d_mb(mb) +{ +} + +mb_mblock_impl::~mb_mblock_impl() +{ + d_mb = 0; // we don't own it +} + + +mb_port_sptr +mb_mblock_impl::define_port(const std::string &port_name, + const std::string &protocol_class_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); + + mb_port_sptr p = mb_port_sptr(new mb_port(port_name, protocol_class_name, + conjugated, port_type)); + d_port_map[port_name] = p; + return p; +} + +void +mb_mblock_impl::define_component(const std::string &name, + mb_mblock_sptr component) +{ + if (comp_is_defined(name)) // check for duplicate name + throw mbe_duplicate_component(d_mb, name); + + d_comp_map[name] = component; +} + +void +mb_mblock_impl::connect(const std::string &comp_name1, const std::string &port_name1, + const std::string &comp_name2, const std::string &port_name2) +{ + 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())) + throw mbe_incompatible_ports(d_mb, + comp_name1, port_name1, + comp_name2, port_name2); + // FIXME more checks? + + d_conn_table.create_conn(ep0, ep1); +} + +void +mb_mblock_impl::disconnect(const std::string &comp_name1, const std::string &port_name1, + const std::string &comp_name2, const std::string &port_name2) +{ + d_conn_table.disconnect(comp_name1, port_name1, comp_name2, port_name2); +} + +void +mb_mblock_impl::disconnect_component(const std::string component_name) +{ + d_conn_table.disconnect_component(component_name); +} + +void +mb_mblock_impl::disconnect_all() +{ + d_conn_table.disconnect_all(); +} + +int +mb_mblock_impl::nconnections() const +{ + return d_conn_table.nconnections(); +} + +//////////////////////////////////////////////////////////////////////// + +mb_endpoint +mb_mblock_impl::check_and_resolve_endpoint(const std::string &comp_name, + const std::string &port_name) +{ + mb_conn_iter it; + int which_ep; + mb_port_sptr port = resolve_port(comp_name, port_name); + + // Confirm that we're not trying to connect to the inside of one of + // our EXTERNAL ports. Connections that include "self" as the + // component name must be either INTERNAL or RELAY. + + if (comp_name == "self" && port->port_type() == mb_port::EXTERNAL) + throw mbe_invalid_port_type(d_mb, comp_name, port_name); + + // Is this endpoint already connected? + if (d_conn_table.lookup_conn_by_name(comp_name, port_name, &it, &which_ep)) + throw mbe_already_connected(d_mb, comp_name, port_name); + + return mb_endpoint(comp_name, port_name, port); +} + +mb_port_sptr +mb_mblock_impl::resolve_port(const std::string &comp_name, + const std::string &port_name) +{ + if (comp_name == "self"){ + // Look through our ports. + if (!port_is_defined(port_name)) + throw mbe_no_such_port(d_mb, mb_util::join_names("self", port_name)); + return d_port_map[port_name]; + } + else { + // Look through the specified child's ports. + if (!comp_is_defined(comp_name)) + throw mbe_no_such_component(d_mb, comp_name); + + mb_mblock_impl_sptr c_impl = d_comp_map[comp_name]->d_impl; // childs impl pointer + if (!c_impl->port_is_defined(port_name)) + throw mbe_no_such_port(d_mb, mb_util::join_names(comp_name, port_name)); + + mb_port_sptr c_port = c_impl->d_port_map[port_name]; + + if (c_port->port_type() == mb_port::INTERNAL) // can't "see" a child's internal ports + throw mbe_no_such_port(d_mb, mb_util::join_names(comp_name, port_name)); + + return c_port; + } +} + + + +bool +mb_mblock_impl::ports_are_compatible(mb_port_sptr p0, mb_port_sptr p1) +{ + using std::cout; + using std::endl; + + pmt_t p0_outgoing = p0->outgoing_message_set(); + pmt_t p0_incoming = p0->incoming_message_set(); + + pmt_t p1_outgoing = p1->outgoing_message_set(); + pmt_t p1_incoming = p1->incoming_message_set(); + + return (pmt_subsetp(p0_outgoing, p1_incoming) + && pmt_subsetp(p1_outgoing, p0_incoming)); +} + +bool +mb_mblock_impl::walk_tree(mb_visitor *visitor, const std::string &path) +{ + if (!(*visitor)(d_mb, path)) + return false; + + mb_comp_map_t::iterator it; + for (it = d_comp_map.begin(); it != d_comp_map.end(); ++it) + if (!(it->second->walk_tree(visitor, path + "/" + it->first))) + return false; + + return true; +} + diff --git a/mblock/src/lib/mb_mblock_impl.h b/mblock/src/lib/mb_mblock_impl.h new file mode 100644 index 00000000..c5610edd --- /dev/null +++ b/mblock/src/lib/mb_mblock_impl.h @@ -0,0 +1,162 @@ +/* -*- 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_MBLOCK_IMPL_H +#define INCLUDED_MB_MBLOCK_IMPL_H + +#include +#include +#include +#include + + +typedef std::map mb_port_map_t; +typedef std::map mb_comp_map_t; + + +/*! + * \brief The private implementation details of the mblock system. + */ +class mb_mblock_impl : boost::noncopyable +{ + mb_mblock *d_mb; // pointer to our associated mblock + + 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 + +public: + mb_mblock_impl(mb_mblock *mb); + ~mb_mblock_impl(); + + /*! + * \brief Define a port. + * + * EXTERNAL and RELAY ports are part of our peer interface. + * INTERNAL ports are used to talk to sub-components. + * + * \param port_name The name of the port (must be unique within this mblock). + * \param protocol_class_name The name of the protocol class associated with + * this port. It must already be defined. + * \param conjugated Are the incoming and outgoing message sets swapped? + * \param port_type INTERNAL, EXTERNAL or RELAY. + */ + mb_port_sptr + define_port(const std::string &port_name, + const std::string &protocol_class_name, + bool conjugated, + mb_port::port_type_t port_type); + + /*! + * \brief Define a subcomponent by name. + * + * Called within the constructor to tell the system the + * names and identities of our sub-component mblocks. + * + * \param component_name The name of the sub-component (must be unique with this mblock). + * \param component The sub-component instance. + */ + void + define_component(const std::string &component_name, + mb_mblock_sptr component); + + /*! + * \brief connect endpoint_1 to endpoint_2 + * + * \param comp_name1 component on one of the connection + * \param port_name1 the name of the port on comp1 + * \param comp_name2 component on the other end the connection + * \param port_name2 the name of the port on comp2 + * + * An endpoint is specified by the component's local name (given as + * component_name in the call to register_component) and the name of + * the port on that component. + * + * To connect an internal or relay port, use "self" as the component name. + */ + void + connect(const std::string &comp_name1, const std::string &port_name1, + const std::string &comp_name2, const std::string &port_name2); + + /*! + * \brief disconnect endpoint_1 from endpoint_2 + * + * \param comp_name1 component on one of the connection + * \param port_name1 the name of the port on comp1 + * \param comp_name2 component on the other end the connection + * \param port_name2 the name of the port on comp2 + * + * An endpoint is specified by the component's local name (given as + * component_name in the call to register_component) and the name of + * the port on that component. + * + * To disconnect an internal or relay port, use "self" as the component name. + */ + void + disconnect(const std::string &comp_name1, const std::string &port_name1, + const std::string &comp_name2, const std::string &port_name2); + + /*! + * \brief disconnect all connections to specified component + * \param component_name component to disconnect + */ + void + disconnect_component(const std::string component_name); + + /*! + * \brief disconnect all connections to all components + */ + void + disconnect_all(); + + /*! + * \brief Return number of connections (QA mostly) + */ + int + nconnections() const; + + bool + walk_tree(mb_visitor *visitor, const std::string &path=""); + + /* + * Our implementation methods + */ +private: + //bool port_is_defined(pmt_t name); + bool port_is_defined(const std::string &name); + //bool comp_is_defined(pmt_t name); + bool comp_is_defined(const std::string &name); + + mb_endpoint + check_and_resolve_endpoint(const std::string &comp_name, + const std::string &port_name); + + + mb_port_sptr + resolve_port(const std::string &comp_name, + const std::string &port_name); + + static bool + ports_are_compatible(mb_port_sptr p0, mb_port_sptr p1); + +}; + + +#endif /* INCLUDED_MB_MBLOCK_IMPL_H */ diff --git a/mblock/src/lib/mb_port.cc b/mblock/src/lib/mb_port.cc new file mode 100644 index 00000000..d7851126 --- /dev/null +++ b/mblock/src/lib/mb_port.cc @@ -0,0 +1,66 @@ +/* -*- 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 +#endif + +#include +#include +#include + +mb_port::mb_port(const std::string &port_name, + const std::string &protocol_class_name, + bool conjugated, + mb_port::port_type_t port_type) + : d_detail(mb_port_detail_sptr(new mb_port_detail())), + d_port_name(port_name), d_conjugated(conjugated), d_port_type(port_type) +{ + pmt_t pc = mb_protocol_class_lookup(pmt_intern(protocol_class_name)); + if (pmt_is_null(pc)){ + throw std::runtime_error("mb_port: unknown protocol class '" + + protocol_class_name + "'"); + } + d_protocol_class = pc; +} + +mb_port::~mb_port() +{ + // nop +} + +pmt_t +mb_port::incoming_message_set() const +{ + if (!conjugated()) + return mb_protocol_class_incoming(protocol_class()); + else // swap the sets + return mb_protocol_class_outgoing(protocol_class()); +} + +pmt_t +mb_port::outgoing_message_set() const +{ + if (!conjugated()) + return mb_protocol_class_outgoing(protocol_class()); + else // swap the sets + return mb_protocol_class_incoming(protocol_class()); +} diff --git a/mblock/src/lib/mb_port.h b/mblock/src/lib/mb_port.h new file mode 100644 index 00000000..35ac34e2 --- /dev/null +++ b/mblock/src/lib/mb_port.h @@ -0,0 +1,83 @@ +/* -*- 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_H +#define INCLUDED_MB_PORT_H + +#include + +/*! + * \brief Public port characteristics + */ +class mb_port : boost::noncopyable +{ +public: + + //! port classification + enum port_type_t { + EXTERNAL, //< Externally visible + RELAY, //< Externally visible but really connected to a sub-component + INTERNAL //< Visible to self only + }; + +private: + friend class mb_mblock_impl; + + mb_port_detail_sptr d_detail; + std::string d_port_name; + pmt_t d_protocol_class; + bool d_conjugated; + port_type_t d_port_type; + + // private constructor + mb_port(const std::string &port_name, + const std::string &protocol_class_name, + bool conjugated, + mb_port::port_type_t port_type); + + +public: + std::string port_name() const { return d_port_name; } + pmt_t protocol_class() const { return d_protocol_class; } + bool conjugated() const { return d_conjugated; } + port_type_t port_type() const { return d_port_type; } + + pmt_t incoming_message_set() const; + pmt_t outgoing_message_set() const; + + ~mb_port(); + + /*! + * \brief send a message + * + * \param signal the event name + * \param data optional data + * \param metadata optional metadata + * \param priority the urgency at which the message is sent + */ + void + send(pmt_t signal, + pmt_t data = PMT_NIL, + pmt_t metadata = PMT_NIL, + mb_pri_t priority = MB_PRI_DEFAULT); + +}; + +#endif /* INCLUDED_MB_PORT_H */ diff --git a/mblock/src/lib/mb_port_detail.cc b/mblock/src/lib/mb_port_detail.cc new file mode 100644 index 00000000..3a58fa24 --- /dev/null +++ b/mblock/src/lib/mb_port_detail.cc @@ -0,0 +1,34 @@ +/* -*- 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 +#endif + +#include + +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 new file mode 100644 index 00000000..3623a1b4 --- /dev/null +++ b/mblock/src/lib/mb_port_detail.h @@ -0,0 +1,35 @@ +/* -*- 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 + +class mb_port_detail : boost::noncopyable +{ +public: + mb_port_detail(); + ~mb_port_detail(); +}; + + +#endif /* INCLUDED_MB_PORT_DETAIL_H */ diff --git a/mblock/src/lib/mb_protocol_class.cc b/mblock/src/lib/mb_protocol_class.cc index ffa54870..f3eeb603 100644 --- a/mblock/src/lib/mb_protocol_class.cc +++ b/mblock/src/lib/mb_protocol_class.cc @@ -25,26 +25,58 @@ #include +static pmt_t s_ALL_PROTOCOL_CLASSES = PMT_NIL; -mb_protocol_class_sptr +pmt_t mb_make_protocol_class(pmt_t name, pmt_t incoming, pmt_t outgoing) { - return mb_protocol_class_sptr(new mb_protocol_class(name, incoming, outgoing)); + // (protocol-class ) + + if (!pmt_is_symbol(name)) + throw pmt_wrong_type("mb_make_protocol_class: NAME must be symbol", name); + if (!(pmt_is_pair(incoming) || pmt_is_null(incoming))) + throw pmt_wrong_type("mb_make_protocol_class: INCOMING must be a list", name); + if (!(pmt_is_pair(outgoing) || pmt_is_null(outgoing))) + throw pmt_wrong_type("mb_make_protocol_class: OUTGOING must be a list", name); + + pmt_t t = pmt_cons(pmt_intern("protocol-class"), + pmt_cons(name, + pmt_cons(incoming, + pmt_cons(outgoing, PMT_NIL)))); + + // Remember this protocol class. + s_ALL_PROTOCOL_CLASSES = pmt_cons(t, s_ALL_PROTOCOL_CLASSES); + return t; } -mb_protocol_class::mb_protocol_class(pmt_t name, pmt_t incoming, pmt_t outgoing) - : d_name(name), d_incoming(incoming), d_outgoing(outgoing) +pmt_t +mb_protocol_class_name(pmt_t pc) { + return pmt_nth(1, pc); } -mb_protocol_class::~mb_protocol_class() +pmt_t +mb_protocol_class_incoming(pmt_t pc) { - // NOP + return pmt_nth(2, pc); } +pmt_t +mb_protocol_class_outgoing(pmt_t pc) +{ + return pmt_nth(3, pc); +} -mb_protocol_class_sptr -mb_protocol_class::conj() const +pmt_t +mb_protocol_class_lookup(pmt_t name) { - return mb_make_protocol_class(name(), outgoing(), incoming()); + pmt_t lst = s_ALL_PROTOCOL_CLASSES; + + while (pmt_is_pair(lst)){ + if (pmt_eq(name, mb_protocol_class_name(pmt_car(lst)))) + return pmt_car(lst); + lst = pmt_cdr(lst); + } + + return PMT_NIL; } diff --git a/mblock/src/lib/mb_protocol_class.h b/mblock/src/lib/mb_protocol_class.h index 771a63e0..f4382ada 100644 --- a/mblock/src/lib/mb_protocol_class.h +++ b/mblock/src/lib/mb_protocol_class.h @@ -23,40 +23,20 @@ #include -// FIXME maybe this should just be a pmt_t aggregate??? - -class mb_protocol_class; -typedef boost::shared_ptr mb_protocol_class_sptr; - /*! - * \brief construct a protocol_class and return boost::shared_ptr + * \brief construct a protocol_class * * \param name the name of the class (symbol) - * \param incoming incoming message set (dict: keys are message types) - * \param outgoing outgoing message set (dict: keys are message types) + * \param incoming incoming message set (list of symbols) + * \param outgoing outgoing message set (list of symbols) */ -mb_protocol_class_sptr -mb_make_protocol_class(pmt_t name, pmt_t incoming, pmt_t outgoing); - -class mb_protocol_class { - pmt_t d_name; - pmt_t d_incoming; - pmt_t d_outgoing; - - friend mb_protocol_class_sptr - mb_make_protocol_class(pmt_t name, pmt_t incoming, pmt_t outgoing); - - // private constructor - mb_protocol_class(pmt_t name, pmt_t incoming, pmt_t outgoing); - -public: - ~mb_protocol_class(); +pmt_t mb_make_protocol_class(pmt_t name, pmt_t incoming, pmt_t outgoing); - pmt_t name() const { return d_name; } - pmt_t incoming() const { return d_incoming; } - pmt_t outgoing() const { return d_outgoing; } +// Accessors +pmt_t mb_protocol_class_name(pmt_t pc); //< return name of protocol class +pmt_t mb_protocol_class_incoming(pmt_t pc); //< return incoming message set +pmt_t mb_protocol_class_outgoing(pmt_t pc); //< return outgoing message set - mb_protocol_class_sptr conj() const; // return the conjugate of this protocol class -}; +pmt_t mb_protocol_class_lookup(pmt_t name); //< lookup an existing protocol class by name #endif /* INCLUDED_MB_PROTOCOL_CLASS_H */ diff --git a/mblock/src/lib/mb_runtime.cc b/mblock/src/lib/mb_runtime.cc new file mode 100644 index 00000000..8c396f19 --- /dev/null +++ b/mblock/src/lib/mb_runtime.cc @@ -0,0 +1,52 @@ +/* -*- 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 +#endif + +#include +#include + +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 + +} + +mb_runtime::~mb_runtime() +{ + // FIXME +} + +bool +mb_runtime::run() +{ + // FIXME + return true; +} diff --git a/mblock/src/lib/mb_runtime.h b/mblock/src/lib/mb_runtime.h new file mode 100644 index 00000000..c4eb206b --- /dev/null +++ b/mblock/src/lib/mb_runtime.h @@ -0,0 +1,63 @@ +/* -*- 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_H +#define INCLUDED_MB_RUNTIME_H + +#include + +/*! + * \brief Public constructor for mb_runtime. + */ +mb_runtime_sptr mb_make_runtime(); + +/*! + * \brief 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(); + + /*! + * \brief Run the mblocks... + * + * This routine turns into the m-block scheduler, and + * blocks until the system is shutdown. + * + * \returns true if the system ran successfully. + */ + bool run(); +}; + +#endif /* INCLUDED_MB_RUNTIME_H */ diff --git a/mblock/src/lib/mb_runtime_impl.cc b/mblock/src/lib/mb_runtime_impl.cc new file mode 100644 index 00000000..5a354ef1 --- /dev/null +++ b/mblock/src/lib/mb_runtime_impl.cc @@ -0,0 +1,36 @@ +/* -*- 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 +#endif + +#include + +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 new file mode 100644 index 00000000..2325a351 --- /dev/null +++ b/mblock/src/lib/mb_runtime_impl.h @@ -0,0 +1,41 @@ +/* -*- 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 + +/*! + * \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_util.cc b/mblock/src/lib/mb_util.cc new file mode 100644 index 00000000..8a14d4c0 --- /dev/null +++ b/mblock/src/lib/mb_util.cc @@ -0,0 +1,34 @@ +/* -*- 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 +#endif + +#include + + +std::string +mb_util::join_names(const std::string &comp_name, + const std::string &port_name) +{ + return comp_name + "/" + port_name; +} diff --git a/mblock/src/lib/mb_util.h b/mblock/src/lib/mb_util.h new file mode 100644 index 00000000..98ff3dd8 --- /dev/null +++ b/mblock/src/lib/mb_util.h @@ -0,0 +1,35 @@ +/* -*- 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_UTIL_H +#define INCLUDED_MB_UTIL_H + +#include + +class mb_util +{ +public: + static std::string + join_names(const std::string &comp_name, + const std::string &port_name); +}; + +#endif /* INCLUDED_MB_UTIL_H */ diff --git a/mblock/src/lib/qa_mblock.cc b/mblock/src/lib/qa_mblock.cc new file mode 100644 index 00000000..72dccc05 --- /dev/null +++ b/mblock/src/lib/qa_mblock.cc @@ -0,0 +1,38 @@ +/* + * 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 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. + */ + +/* + * This class gathers together all the test cases for mblock into + * a single test suite. As you create new test cases, add them here. + */ + +#include +#include + +CppUnit::TestSuite * +qa_mblock::suite() +{ + CppUnit::TestSuite *s = new CppUnit::TestSuite("mblock"); + + s->addTest (qa_mblock_prims::suite()); + + return s; +} diff --git a/mblock/src/lib/qa_mblock.h b/mblock/src/lib/qa_mblock.h new file mode 100644 index 00000000..8d843742 --- /dev/null +++ b/mblock/src/lib/qa_mblock.h @@ -0,0 +1,36 @@ +/* -*- 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 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_H +#define INCLUDED_QA_MBLOCK_H + +#include + +//! collect all the tests for mblock + +class qa_mblock { + public: + //! return suite of tests for all of mblock + static CppUnit::TestSuite *suite(); +}; + +#endif /* INCLUDED_QA_MBLOCK_H */ diff --git a/mblock/src/lib/qa_mblock_prims.cc b/mblock/src/lib/qa_mblock_prims.cc new file mode 100644 index 00000000..432e819a --- /dev/null +++ b/mblock/src/lib/qa_mblock_prims.cc @@ -0,0 +1,331 @@ +/* -*- 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 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +static pmt_t s_cs = pmt_intern("cs"); +static pmt_t s_debug = pmt_intern("debug"); +static pmt_t s_in = pmt_intern("in"); +static pmt_t s_out = pmt_intern("out"); + + +// ================================================================ + +class dp_1 : public mb_mblock +{ +public: + dp_1(); + ~dp_1(); +}; + +dp_1::dp_1() +{ +} + +dp_1::~dp_1(){} + +// ---------------------------------------------------------------- + +class dp_2 : public mb_mblock +{ +public: + dp_2(); + ~dp_2(); +}; + +dp_2::dp_2() +{ + define_port("cs", "cs-protocol", false, mb_port::EXTERNAL); +} + +dp_2::~dp_2(){} + +// ---------------------------------------------------------------- + +class dp_3 : public mb_mblock +{ +public: + dp_3(); + ~dp_3(); +}; + +dp_3::dp_3() +{ + define_port("cs", "cs-protocol", false, mb_port::EXTERNAL); + define_port("cs", "cs-protocol", false, mb_port::EXTERNAL); // duplicate def +} + +dp_3::~dp_3(){} + +// ---------------------------------------------------------------- + +void +qa_mblock_prims::test_define_ports() +{ + mb_runtime_sptr rt = mb_make_runtime(); + // std::vector intf; + + mb_mblock_sptr mb1 = mb_mblock_sptr(new dp_1()); + // intf = mb1->peer_interface(); + // CPPUNIT_ASSERT_EQUAL(size_t(0), intf.size()); + + // raises runtime_error because of unknown protocol "cs-protocol" + CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_2()), std::runtime_error); + + // 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_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 + +} + +// ================================================================ + +class dc_0 : public mb_mblock +{ +public: + dc_0(); + ~dc_0(); +}; + +dc_0::dc_0() +{ +} + +dc_0::~dc_0() {} + +// ---------------------------------------------------------------- + +class dc_ok : public mb_mblock +{ +public: + dc_ok(); + ~dc_ok(); +}; + +dc_ok::dc_ok() +{ + define_component("c0", mb_mblock_sptr(new dc_0())); + define_component("c1", mb_mblock_sptr(new dc_0())); + define_component("c2", mb_mblock_sptr(new dc_0())); +} + +dc_ok::~dc_ok(){} + +// ---------------------------------------------------------------- + +class dc_not_ok : public mb_mblock +{ +public: + dc_not_ok(); + ~dc_not_ok(); +}; + +dc_not_ok::dc_not_ok() + : mb_mblock() +{ + define_component("c0", mb_mblock_sptr(new dc_0())); + define_component("c0", mb_mblock_sptr(new dc_0())); // duplicate name +} + +dc_not_ok::~dc_not_ok(){} + +// ---------------------------------------------------------------- + +void +qa_mblock_prims::test_define_components() +{ + mb_runtime_sptr rt = mb_make_runtime(); + mb_mblock_sptr mb1 = mb_mblock_sptr(new dc_ok()); // OK + + // raises pmt_exception because of duplicate component definition of "c0" + CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dc_not_ok()), mbe_duplicate_component); +} + +// ================================================================ + +class tc_norm : public mb_mblock +{ +public: + tc_norm(){ + define_port("data", "i/o", false, mb_port::EXTERNAL); + define_port("norm", "i/o", false, mb_port::EXTERNAL); + define_port("conj", "i/o", true, mb_port::EXTERNAL); + define_port("int", "i/o", false, mb_port::INTERNAL); + } + + ~tc_norm(); +}; + +tc_norm::~tc_norm(){} + +//////////////////////////////////////////////////////////////// + +class tc_0 : public mb_mblock +{ +public: + tc_0(){ + define_port("norm", "i/o", false, mb_port::EXTERNAL); + define_port("conj", "i/o", true, mb_port::EXTERNAL); + define_port("int", "i/o", false, mb_port::INTERNAL); + + define_component("c0", mb_mblock_sptr(new tc_norm())); + define_component("c1", mb_mblock_sptr(new tc_norm())); + define_component("c2", mb_mblock_sptr(new tc_norm())); + define_component("c3", mb_mblock_sptr(new tc_norm())); + define_component("c4", mb_mblock_sptr(new tc_norm())); + define_component("c5", mb_mblock_sptr(new tc_norm())); + + // OK + connect("c0", "norm", "c1", "conj"); + + // No: No such component name + CPPUNIT_ASSERT_THROW(connect("foo", "data", "c1", "norm"), mbe_no_such_component); + + // No: No such port name + CPPUNIT_ASSERT_THROW(connect("c0", "data", "c1", "foo"), mbe_no_such_port); + + // No: already connected + CPPUNIT_ASSERT_THROW(connect("c0", "norm", "c2", "data"), mbe_already_connected); + + // No: already connected + CPPUNIT_ASSERT_THROW(connect("c2", "data", "c0", "norm"), mbe_already_connected); + + // No: incompatible ports + CPPUNIT_ASSERT_THROW(connect("c1", "norm", "c2", "norm"), mbe_incompatible_ports); + + // OK + connect("c1", "norm", "c2", "conj"); + + // No: No such port name + CPPUNIT_ASSERT_THROW(connect("c2", "norm", "self", "foo"), mbe_no_such_port); + + // No: can't connect to child's internal port + CPPUNIT_ASSERT_THROW(connect("c0", "conj", "c2", "int"), mbe_no_such_port); + + // No: can't connect to our own external port + CPPUNIT_ASSERT_THROW(connect("self", "norm", "c0", "conj"), mbe_invalid_port_type); + + // OK: connecting to one of our internal ports + connect("self", "int", "c3", "conj"); + + // ===== Now test disconnecting some stuff ===== + + // Confirm we're already connected + CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected); + + int nc = nconnections(); + disconnect("self", "int", "c3", "conj"); // disconnect + CPPUNIT_ASSERT_EQUAL(nc-1, nconnections()); + + connect("self", "int", "c3", "conj"); // reconnect + CPPUNIT_ASSERT_EQUAL(nc, nconnections()); + + // confirm we're already connected + CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected); + + + connect("c0", "conj", "c5", "data"); + connect("c4", "norm", "c5", "conj"); + connect("c4", "conj", "c5", "norm"); + + nc = nconnections(); + disconnect_component("c4"); + CPPUNIT_ASSERT_EQUAL(nc-2, nconnections()); + + disconnect_component("c5"); + CPPUNIT_ASSERT_EQUAL(nc-3, nconnections()); + + disconnect_all(); + CPPUNIT_ASSERT_EQUAL(0, nconnections()); + + } + + ~tc_0(); +}; + +tc_0::~tc_0(){} + +//////////////////////////////////////////////////////////////// + +class tc_1 : public mb_mblock +{ +public: + tc_1(){ + define_component("c0", mb_mblock_sptr(new tc_norm())); + define_component("c1", mb_mblock_sptr(new tc_norm())); + + connect("c0", "norm", "c1", "conj"); + } + + ~tc_1(); +}; + +tc_1::~tc_1(){} + +//////////////////////////////////////////////////////////////// + +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("i/o"), // name of class + pmt_cons(pmt_intern("in"), PMT_NIL), // in + pmt_cons(pmt_intern("out"), PMT_NIL)); // out + + + mb_runtime_sptr rt = mb_make_runtime(); + mb_mblock_sptr mb0 = mb_mblock_sptr(new tc_0()); +} diff --git a/mblock/src/lib/qa_mblock_prims.h b/mblock/src/lib/qa_mblock_prims.h new file mode 100644 index 00000000..36b35550 --- /dev/null +++ b/mblock/src/lib/qa_mblock_prims.h @@ -0,0 +1,43 @@ +/* -*- 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 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_PRIMS_H +#define INCLUDED_QA_MBLOCK_PRIMS_H + +#include +#include + +class qa_mblock_prims : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE(qa_mblock_prims); + CPPUNIT_TEST(test_define_ports); + CPPUNIT_TEST(test_define_components); + CPPUNIT_TEST(test_connect); + CPPUNIT_TEST_SUITE_END(); + + private: + void test_define_ports(); + void test_define_components(); + void test_connect(); +}; + +#endif /* INCLUDED_QA_MBLOCK_PRIMS_H */ + diff --git a/mblock/src/lib/test_mblock.cc b/mblock/src/lib/test_mblock.cc new file mode 100644 index 00000000..d1abdea6 --- /dev/null +++ b/mblock/src/lib/test_mblock.cc @@ -0,0 +1,37 @@ +/* -*- 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 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. + */ + +#include +#include + +int +main(int argc, char **argv) +{ + + CppUnit::TextTestRunner runner; + + runner.addTest(qa_mblock::suite ()); + + bool was_successful = runner.run("", false); + + return was_successful ? 0 : 1; +} diff --git a/pmt/src/lib/Makefile.am b/pmt/src/lib/Makefile.am index 672424ed..60f889c4 100644 --- a/pmt/src/lib/Makefile.am +++ b/pmt/src/lib/Makefile.am @@ -59,6 +59,7 @@ EXTRA_DIST = \ # These are the source files that go into the pmt shared library libpmt_la_SOURCES = \ pmt.cc \ + pmt_io.cc \ pmt_unv.cc # magic flags diff --git a/pmt/src/lib/pmt.cc b/pmt/src/lib/pmt.cc index 0f2ceec5..036a5f8b 100644 --- a/pmt/src/lib/pmt.cc +++ b/pmt/src/lib/pmt.cc @@ -36,18 +36,23 @@ pmt_base::~pmt_base() // Exceptions //////////////////////////////////////////////////////////////////////////// -pmt_exception::pmt_exception(const char *msg, pmt_t obj) - : d_msg(msg), d_obj(obj) +pmt_exception::pmt_exception(const std::string &msg, pmt_t obj) + : logic_error(msg + ": " + pmt_write_string(obj)) { } -pmt_wrong_type::pmt_wrong_type(const char *msg, pmt_t obj) - : pmt_exception(msg, obj) +pmt_wrong_type::pmt_wrong_type(const std::string &msg, pmt_t obj) + : pmt_exception(msg + ": wrong_type ", obj) { } -pmt_out_of_range::pmt_out_of_range(const char *msg, pmt_t obj) - : pmt_exception(msg, obj) +pmt_out_of_range::pmt_out_of_range(const std::string &msg, pmt_t obj) + : pmt_exception(msg + ": out of range ", obj) +{ +} + +pmt_notimplemented::pmt_notimplemented(const std::string &msg, pmt_t obj) + : pmt_exception(msg + ": notimplemented ", obj) { } @@ -197,6 +202,13 @@ pmt_string_to_symbol(const std::string &name) return sym; } +// alias... +pmt_t +pmt_intern(const std::string &name) +{ + return pmt_string_to_symbol(name); +} + const std::string pmt_symbol_to_string(pmt_t sym) { @@ -206,6 +218,8 @@ pmt_symbol_to_string(pmt_t sym) return _symbol(sym)->name(); } + + //////////////////////////////////////////////////////////////////////////// // Number //////////////////////////////////////////////////////////////////////////// @@ -753,3 +767,77 @@ pmt_reverse_x(pmt_t list) return pmt_reverse(list); } +pmt_t +pmt_nth(size_t n, pmt_t list) +{ + pmt_t t = pmt_nthcdr(n, list); + if (pmt_is_pair(t)) + return pmt_car(t); + else + return PMT_NIL; +} + +pmt_t +pmt_nthcdr(size_t n, pmt_t list) +{ + if (!(pmt_is_null(list) || pmt_is_pair(list))) + throw pmt_wrong_type("pmt_nthcdr", list); + + while (n > 0){ + if (pmt_is_pair(list)){ + list = pmt_cdr(list); + n--; + continue; + } + if (pmt_is_null(list)) + return PMT_NIL; + else + throw pmt_wrong_type("pmt_nthcdr: not a LIST", list); + } + return list; +} + +pmt_t +pmt_memq(pmt_t obj, pmt_t list) +{ + while (pmt_is_pair(list)){ + if (pmt_eq(obj, pmt_car(list))) + return list; + list = pmt_cdr(list); + } + return PMT_BOOL_F; +} + +pmt_t +pmt_memv(pmt_t obj, pmt_t list) +{ + while (pmt_is_pair(list)){ + if (pmt_eqv(obj, pmt_car(list))) + return list; + list = pmt_cdr(list); + } + return PMT_BOOL_F; +} + +pmt_t +pmt_member(pmt_t obj, pmt_t list) +{ + while (pmt_is_pair(list)){ + if (pmt_equal(obj, pmt_car(list))) + return list; + list = pmt_cdr(list); + } + return PMT_BOOL_F; +} + +bool +pmt_subsetp(pmt_t list1, pmt_t list2) +{ + while (pmt_is_pair(list1)){ + pmt_t p = pmt_car(list1); + if (pmt_is_false(pmt_memv(p, list2))) + return false; + list1 = pmt_cdr(list1); + } + return true; +} diff --git a/pmt/src/lib/pmt.h b/pmt/src/lib/pmt.h index 0499a16c..2cb032e5 100644 --- a/pmt/src/lib/pmt.h +++ b/pmt/src/lib/pmt.h @@ -28,6 +28,7 @@ #include #include #include +#include /*! * This file defines a polymorphic type and the operations on it. @@ -49,27 +50,28 @@ class pmt_base; typedef boost::shared_ptr pmt_t; -class pmt_exception +class pmt_exception : public std::logic_error { - const char *d_msg; - pmt_t d_obj; - public: - pmt_exception(const char *msg, pmt_t obj); - const char *msg() { return d_msg; } - pmt_t obj() { return d_obj; } + pmt_exception(const std::string &msg, pmt_t obj); }; class pmt_wrong_type : public pmt_exception { public: - pmt_wrong_type(const char *msg, pmt_t obj); + pmt_wrong_type(const std::string &msg, pmt_t obj); }; class pmt_out_of_range : public pmt_exception { public: - pmt_out_of_range(const char *msg, pmt_t obj); + pmt_out_of_range(const std::string &msg, pmt_t obj); +}; + +class pmt_notimplemented : public pmt_exception +{ +public: + pmt_notimplemented(const std::string &msg, pmt_t obj); }; /* @@ -111,6 +113,10 @@ bool pmt_is_symbol(pmt_t obj); //! Return the symbol whose name is \p s. pmt_t pmt_string_to_symbol(const std::string &s); +//! Alias for pmt_string_to_symbol +pmt_t pmt_intern(const std::string &s); + + /*! * If \p is a symbol, return the name of the symbol as a string. * Otherwise, raise the wrong_type exception. @@ -504,6 +510,44 @@ pmt_acons(pmt_t x, pmt_t y, pmt_t a) return pmt_cons(pmt_cons(x, y), a); } +/*! + * \brief locates \p nth element of \n list where the car is the 'zeroth' element. + */ +pmt_t pmt_nth(size_t n, pmt_t list); + +/*! + * \brief returns the tail of \p list that would be obtained by calling + * cdr \p n times in succession. + */ +pmt_t pmt_nthcdr(size_t n, pmt_t list); + +/*! + * \brief Return the first sublist of \p list whose car is \p obj. + * If \p obj does not occur in \p list, then #f is returned. + * pmt_memq use pmt_eq to compare \p obj with the elements of \p list. + */ +pmt_t pmt_memq(pmt_t obj, pmt_t list); + +/*! + * \brief Return the first sublist of \p list whose car is \p obj. + * If \p obj does not occur in \p list, then #f is returned. + * pmt_memv use pmt_eqv to compare \p obj with the elements of \p list. + */ +pmt_t pmt_memv(pmt_t obj, pmt_t list); + +/*! + * \brief Return the first sublist of \p list whose car is \p obj. + * If \p obj does not occur in \p list, then #f is returned. + * pmt_member use pmt_equal to compare \p obj with the elements of \p list. + */ +pmt_t pmt_member(pmt_t obj, pmt_t list); + +/*! + * \brief Return true if every element of \p list1 appears in \p list2, and false otherwise. + * Comparisons are done with pmt_eqv. + */ +bool pmt_subsetp(pmt_t list1, pmt_t list2); + /* * ------------------------------------------------------------------------ * read / write @@ -536,6 +580,16 @@ pmt_t pmt_read(std::istream &port); */ void pmt_write(pmt_t obj, std::ostream &port); +/*! + * Return a string representation of \p obj. + * This is the same output as would be generated by pmt_write. + */ +std::string pmt_write_string(pmt_t obj); + + +std::ostream& operator<<(std::ostream &os, pmt_t obj); + + /* * ------------------------------------------------------------------------ * portable byte stream representation diff --git a/pmt/src/lib/pmt_int.h b/pmt/src/lib/pmt_int.h index 5a178523..458443ea 100644 --- a/pmt/src/lib/pmt_int.h +++ b/pmt/src/lib/pmt_int.h @@ -23,6 +23,7 @@ #define INCLUDED_PMT_INT_H #include +#include /* * EVERYTHING IN THIS FILE IS PRIVATE TO THE IMPLEMENTATION! @@ -30,16 +31,11 @@ * See pmt.h for the public interface */ -class pmt_base { +class pmt_base : boost::noncopyable { protected: pmt_base(){}; virtual ~pmt_base(); -private: - pmt_base(const pmt_base& rhs); // NOT IMPLEMENTED - pmt_base& operator=(const pmt_base& rhs); // NOT IMPLEMENTED - - public: virtual bool is_bool() const { return false; } virtual bool is_symbol() const { return false; } @@ -102,6 +98,7 @@ public: pmt_integer(long value); //~pmt_integer(){} + bool is_number() const { return true; } bool is_integer() const { return true; } long value() const { return d_value; } }; @@ -114,6 +111,7 @@ public: pmt_real(double value); //~pmt_real(){} + bool is_number() const { return true; } bool is_real() const { return true; } double value() const { return d_value; } }; @@ -126,6 +124,7 @@ public: pmt_complex(std::complex value); //~pmt_complex(){} + bool is_number() const { return true; } bool is_complex() const { return true; } std::complex value() const { return d_value; } }; diff --git a/pmt/src/lib/pmt_io.cc b/pmt/src/lib/pmt_io.cc new file mode 100644 index 00000000..2d7af68b --- /dev/null +++ b/pmt/src/lib/pmt_io.cc @@ -0,0 +1,138 @@ +/* -*- 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 +#endif +#include +#include +#include "pmt_int.h" +#include + +static void +pmt_write_list_tail(pmt_t obj, std::ostream &port) +{ + pmt_write(pmt_car(obj), port); // write the car + obj = pmt_cdr(obj); // step to cdr + + if (pmt_is_null(obj)) // () + port << ")"; + + else if (pmt_is_pair(obj)){ // normal list + port << " "; + pmt_write_list_tail(obj, port); + } + else { // dotted pair + port << " . "; + pmt_write(obj, port); + port << ")"; + } +} + +void +pmt_write(pmt_t obj, std::ostream &port) +{ + if (pmt_is_bool(obj)){ + if (pmt_is_true(obj)) + port << "#t"; + else + port << "#f"; + } + else if (pmt_is_symbol(obj)){ + port << pmt_symbol_to_string(obj); + } + else if (pmt_is_number(obj)){ + if (pmt_is_integer(obj)) + port << pmt_to_long(obj); + else if (pmt_is_real(obj)) + port << pmt_to_double(obj); + else if (pmt_is_complex(obj)){ + std::complex c = pmt_to_complex(obj); + port << c.real() << '+' << c.imag() << 'i'; + } + else + goto error; + } + else if (pmt_is_null(obj)){ + port << "()"; + } + else if (pmt_is_pair(obj)){ + port << "("; + pmt_write_list_tail(obj, port); + } + else if (pmt_is_dict(obj)){ + // FIXME + // port << "#"; + port << "#"; + } + else if (pmt_is_vector(obj)){ + // FIXME + // port << "#"; + port << "#"; + } + else if (pmt_is_uniform_vector(obj)){ + // FIXME + // port << "#"; + port << "#"; + } + else { + error: + // FIXME + // port << "#<" << obj << ">"; + port << "#"; + } +} + +std::ostream& operator<<(std::ostream &os, pmt_t obj) +{ + pmt_write(obj, os); + return os; +} + +std::string +pmt_write_string(pmt_t obj) +{ + std::ostringstream s; + s << obj; + return s.str(); +} + +pmt_t +pmt_read(std::istream &port) +{ + throw pmt_notimplemented("notimplemented: pmt_read", PMT_NIL); +} + +void +pmt_serialize(pmt_t obj, std::ostream &sink) +{ + throw pmt_notimplemented("notimplemented: pmt_serialize", obj); +} + +/*! + * \brief Create obj from portable byte-serial representation + */ +pmt_t +pmt_deserialize(std::istream &source) +{ + throw pmt_notimplemented("notimplemented: pmt_deserialize", PMT_NIL); +} + diff --git a/pmt/src/lib/qa_pmt_prims.cc b/pmt/src/lib/qa_pmt_prims.cc index 09669c31..cb687b0e 100644 --- a/pmt/src/lib/qa_pmt_prims.cc +++ b/pmt/src/lib/qa_pmt_prims.cc @@ -282,3 +282,14 @@ qa_pmt_prims::test_dict() CPPUNIT_ASSERT(pmt_equal(keys, pmt_dict_keys(dict))); CPPUNIT_ASSERT(pmt_equal(vals, pmt_dict_values(dict))); } + +void +qa_pmt_prims::test_io() +{ + pmt_t k0 = pmt_string_to_symbol("k0"); + pmt_t k1 = pmt_string_to_symbol("k1"); + pmt_t k2 = pmt_string_to_symbol("k2"); + pmt_t k3 = pmt_string_to_symbol("k3"); + + CPPUNIT_ASSERT_EQUAL(std::string("k0"), pmt_write_string(k0)); +} diff --git a/pmt/src/lib/qa_pmt_prims.h b/pmt/src/lib/qa_pmt_prims.h index d5e8e753..8d379c5a 100644 --- a/pmt/src/lib/qa_pmt_prims.h +++ b/pmt/src/lib/qa_pmt_prims.h @@ -38,6 +38,7 @@ class qa_pmt_prims : public CppUnit::TestCase { CPPUNIT_TEST(test_equivalence); CPPUNIT_TEST(test_misc); CPPUNIT_TEST(test_dict); + CPPUNIT_TEST(test_io); CPPUNIT_TEST_SUITE_END(); private: @@ -51,6 +52,7 @@ class qa_pmt_prims : public CppUnit::TestCase { void test_equivalence(); void test_misc(); void test_dict(); + void test_io(); }; #endif /* INCLUDED_QA_PMT_PRIMS_H */