diff options
author | eb | 2007-05-02 04:08:47 +0000 |
---|---|---|
committer | eb | 2007-05-02 04:08:47 +0000 |
commit | 0bf2128a621ae84099f43744e1b81800f2b9d2d7 (patch) | |
tree | 1345b44ae9060e99ff236f983dd272c6d35a012e /pmt | |
parent | 28259329a829f157fd877a1c14139eaf0117dabd (diff) | |
download | gnuradio-0bf2128a621ae84099f43744e1b81800f2b9d2d7.tar.gz gnuradio-0bf2128a621ae84099f43744e1b81800f2b9d2d7.tar.bz2 gnuradio-0bf2128a621ae84099f43744e1b81800f2b9d2d7.zip |
Merged features/inband -r4812:5218 into trunk. This group of changes
includes:
* working stand-alone mblock code
* work-in-progress on usrp inband signaling
usrp now depends on mblock, and guile is a dependency.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@5221 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'pmt')
-rw-r--r-- | pmt/src/Makefile.am | 4 | ||||
-rw-r--r-- | pmt/src/lib/Makefile.am | 17 | ||||
-rw-r--r-- | pmt/src/lib/pmt.cc | 170 | ||||
-rw-r--r-- | pmt/src/lib/pmt.h | 45 | ||||
-rw-r--r-- | pmt/src/lib/pmt_int.h | 21 | ||||
-rw-r--r-- | pmt/src/lib/pmt_pool.cc | 96 | ||||
-rw-r--r-- | pmt/src/lib/pmt_pool.h | 61 | ||||
-rw-r--r-- | pmt/src/lib/pmt_serialize.cc | 353 | ||||
-rw-r--r-- | pmt/src/lib/qa_pmt_prims.cc | 132 | ||||
-rw-r--r-- | pmt/src/lib/qa_pmt_prims.h | 4 | ||||
-rw-r--r-- | pmt/src/scheme/Makefile.am | 21 | ||||
-rw-r--r-- | pmt/src/scheme/gnuradio/Makefile.am | 32 | ||||
-rwxr-xr-x | pmt/src/scheme/gnuradio/gen-serial-tags.scm | 118 | ||||
-rw-r--r-- | pmt/src/scheme/gnuradio/macros-etc.scm | 50 | ||||
-rw-r--r-- | pmt/src/scheme/gnuradio/pmt-serial-tags.scm | 75 | ||||
-rw-r--r-- | pmt/src/scheme/gnuradio/pmt-serialize.scm | 48 |
16 files changed, 1198 insertions, 49 deletions
diff --git a/pmt/src/Makefile.am b/pmt/src/Makefile.am index bcbab2455..df73ba515 100644 --- a/pmt/src/Makefile.am +++ b/pmt/src/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2004,2006 Free Software Foundation, Inc. +# Copyright 2006,2007 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -19,4 +19,4 @@ # Boston, MA 02110-1301, USA. # -SUBDIRS = lib +SUBDIRS = lib scheme diff --git a/pmt/src/lib/Makefile.am b/pmt/src/lib/Makefile.am index a738a1692..b77f6201b 100644 --- a/pmt/src/lib/Makefile.am +++ b/pmt/src/lib/Makefile.am @@ -21,7 +21,7 @@ include $(top_srcdir)/Makefile.common -INCLUDES = $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES) +INCLUDES = $(DEFINES) $(OMNITHREAD_INCLUDES) $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES) TESTS = test_pmt @@ -48,18 +48,22 @@ GENERATED_CC = \ $(GENERATED_H) $(GENERATED_I) $(GENERATED_CC): $(CODE_GENERATOR) PYTHONPATH=$(top_srcdir)/pmt/src/lib srcdir=$(srcdir) $(PYTHON) $(srcdir)/generate_unv.py -BUILT_SOURCES = $(GENERATED_H) $(GENERATED_CC) +pmt_serial_tags.h: $(srcdir)/../scheme/gnuradio/gen-serial-tags.scm $(srcdir)/../scheme/gnuradio/pmt-serial-tags.scm + $(RUN_GUILE) $(srcdir)/../scheme/gnuradio/gen-serial-tags.scm $(srcdir)/../scheme/gnuradio/pmt-serial-tags.scm pmt_serial_tags.h + +BUILT_SOURCES = $(GENERATED_H) $(GENERATED_CC) pmt_serial_tags.h # ---------------------------------------------------------------- EXTRA_DIST = \ - $(CODE_GENERATOR) - + $(CODE_GENERATOR) # These are the source files that go into the pmt shared library libpmt_la_SOURCES = \ pmt.cc \ pmt_io.cc \ + pmt_pool.cc \ + pmt_serialize.cc \ pmt_unv.cc # magic flags @@ -67,10 +71,13 @@ libpmt_la_LDFLAGS = $(NO_UNDEFINED) -avoid-version # link the library against the c++ standard library libpmt_la_LIBADD = \ + $(OMNITHREAD_LA) \ -lstdc++ include_HEADERS = \ - pmt.h + pmt.h \ + pmt_pool.h \ + pmt_serial_tags.h noinst_HEADERS = \ $(GENERATED_H) \ diff --git a/pmt/src/lib/pmt.cc b/pmt/src/lib/pmt.cc index cf6547b57..9378953c1 100644 --- a/pmt/src/lib/pmt.cc +++ b/pmt/src/lib/pmt.cc @@ -26,6 +26,33 @@ #include <vector> #include <pmt.h> #include "pmt_int.h" +#include <stdio.h> +#include <pmt_pool.h> + +static const int CACHE_LINE_SIZE = 64; // good guess + +# if (PMT_LOCAL_ALLOCATOR) + +static pmt_pool global_pmt_pool(sizeof(pmt_pair), CACHE_LINE_SIZE); + +void * +pmt_base::operator new(size_t size) +{ + void *p = global_pmt_pool.malloc(); + + // fprintf(stderr, "pmt_base::new p = %p\n", p); + assert((reinterpret_cast<intptr_t>(p) & (CACHE_LINE_SIZE - 1)) == 0); + return p; +} + +void +pmt_base::operator delete(void *p, size_t size) +{ + global_pmt_pool.free(p); +} + +#endif + pmt_base::~pmt_base() { @@ -108,25 +135,37 @@ _dict(pmt_t x) return dynamic_cast<pmt_dict*>(x.get()); } +static pmt_any * +_any(pmt_t x) +{ + return dynamic_cast<pmt_any*>(x.get()); +} + //////////////////////////////////////////////////////////////////////////// -// Booleans +// Globals //////////////////////////////////////////////////////////////////////////// -const pmt_t PMT_BOOL_T = pmt_t(new pmt_bool()); // singleton -const pmt_t PMT_BOOL_F = pmt_t(new pmt_bool()); // singleton +const pmt_t PMT_T = pmt_t(new pmt_bool()); // singleton +const pmt_t PMT_F = pmt_t(new pmt_bool()); // singleton +const pmt_t PMT_NIL = pmt_t(new pmt_null()); // singleton +const pmt_t PMT_EOF = pmt_cons(PMT_NIL, PMT_NIL); // singleton + +//////////////////////////////////////////////////////////////////////////// +// Booleans +//////////////////////////////////////////////////////////////////////////// pmt_bool::pmt_bool(){} bool pmt_is_true(pmt_t obj) { - return obj != PMT_BOOL_F; + return obj != PMT_F; } bool pmt_is_false(pmt_t obj) { - return obj == PMT_BOOL_F; + return obj == PMT_F; } bool @@ -138,15 +177,15 @@ pmt_is_bool(pmt_t obj) pmt_t pmt_from_bool(bool val) { - return val ? PMT_BOOL_T : PMT_BOOL_F; + return val ? PMT_T : PMT_F; } bool pmt_to_bool(pmt_t val) { - if (val == PMT_BOOL_T) + if (val == PMT_T) return true; - if (val == PMT_BOOL_F) + if (val == PMT_F) return false; throw pmt_wrong_type("pmt_to_bool", val); } @@ -167,7 +206,7 @@ hash_string(const std::string &s) unsigned int h = 0; unsigned int g = 0; - for (std::string::const_iterator p = s.begin(); p != s.end(); p++){ + for (std::string::const_iterator p = s.begin(); p != s.end(); ++p){ h = (h << 4) + (*p & 0xff); g = h & 0xf0000000; if (g){ @@ -322,8 +361,6 @@ pmt_to_complex(pmt_t x) // Pairs //////////////////////////////////////////////////////////////////////////// -const pmt_t PMT_NIL = pmt_t(new pmt_null()); // singleton - pmt_null::pmt_null() {} pmt_pair::pmt_pair(pmt_t car, pmt_t cdr) : d_car(car), d_cdr(cdr) {} @@ -599,6 +636,40 @@ pmt_dict_values(pmt_t dict) } //////////////////////////////////////////////////////////////////////////// +// Any +//////////////////////////////////////////////////////////////////////////// + +pmt_any::pmt_any(const boost::any &any) : d_any(any) {} + +bool +pmt_is_any(pmt_t obj) +{ + return obj->is_any(); +} + +pmt_t +pmt_make_any(const boost::any &any) +{ + return pmt_t(new pmt_any(any)); +} + +boost::any +pmt_any_ref(pmt_t obj) +{ + if (!obj->is_any()) + throw pmt_wrong_type("pmt_any_ref", obj); + return _any(obj)->ref(); +} + +void +pmt_any_set(pmt_t obj, const boost::any &any) +{ + if (!obj->is_any()) + throw pmt_wrong_type("pmt_any_set", obj); + _any(obj)->set(any); +} + +//////////////////////////////////////////////////////////////////////////// // General Functions //////////////////////////////////////////////////////////////////////////// @@ -689,14 +760,14 @@ pmt_assq(pmt_t obj, pmt_t alist) while (pmt_is_pair(alist)){ pmt_t p = pmt_car(alist); if (!pmt_is_pair(p)) // malformed alist - return PMT_BOOL_F; + return PMT_F; if (pmt_eq(obj, pmt_car(p))) return p; alist = pmt_cdr(alist); } - return PMT_BOOL_F; + return PMT_F; } pmt_t @@ -705,14 +776,14 @@ pmt_assv(pmt_t obj, pmt_t alist) while (pmt_is_pair(alist)){ pmt_t p = pmt_car(alist); if (!pmt_is_pair(p)) // malformed alist - return PMT_BOOL_F; + return PMT_F; if (pmt_eqv(obj, pmt_car(p))) return p; alist = pmt_cdr(alist); } - return PMT_BOOL_F; + return PMT_F; } pmt_t @@ -721,14 +792,14 @@ pmt_assoc(pmt_t obj, pmt_t alist) while (pmt_is_pair(alist)){ pmt_t p = pmt_car(alist); if (!pmt_is_pair(p)) // malformed alist - return PMT_BOOL_F; + return PMT_F; if (pmt_equal(obj, pmt_car(p))) return p; alist = pmt_cdr(alist); } - return PMT_BOOL_F; + return PMT_F; } pmt_t @@ -805,7 +876,7 @@ pmt_memq(pmt_t obj, pmt_t list) return list; list = pmt_cdr(list); } - return PMT_BOOL_F; + return PMT_F; } pmt_t @@ -816,7 +887,7 @@ pmt_memv(pmt_t obj, pmt_t list) return list; list = pmt_cdr(list); } - return PMT_BOOL_F; + return PMT_F; } pmt_t @@ -827,7 +898,7 @@ pmt_member(pmt_t obj, pmt_t list) return list; list = pmt_cdr(list); } - return PMT_BOOL_F; + return PMT_F; } bool @@ -865,3 +936,62 @@ 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)))); } + +pmt_t +pmt_caar(pmt_t pair) +{ + return (pmt_car(pmt_car(pair))); +} + +pmt_t +pmt_cadr(pmt_t pair) +{ + return pmt_car(pmt_cdr(pair)); +} + +pmt_t +pmt_cdar(pmt_t pair) +{ + return pmt_cdr(pmt_car(pair)); +} + +pmt_t +pmt_cddr(pmt_t pair) +{ + return pmt_cdr(pmt_cdr(pair)); +} + +pmt_t +pmt_caddr(pmt_t pair) +{ + return pmt_car(pmt_cdr(pmt_cdr(pair))); +} + +pmt_t +pmt_cadddr(pmt_t pair) +{ + return pmt_car(pmt_cdr(pmt_cdr(pmt_cdr(pair)))); +} + +bool +pmt_is_eof_object(pmt_t obj) +{ + return pmt_eq(obj, PMT_EOF); +} + +void +pmt_dump_sizeof() +{ + printf("sizeof(pmt_t) = %3zd\n", sizeof(pmt_t)); + printf("sizeof(pmt_base) = %3zd\n", sizeof(pmt_base)); + printf("sizeof(pmt_bool) = %3zd\n", sizeof(pmt_bool)); + printf("sizeof(pmt_symbol) = %3zd\n", sizeof(pmt_symbol)); + printf("sizeof(pmt_integer) = %3zd\n", sizeof(pmt_integer)); + printf("sizeof(pmt_real) = %3zd\n", sizeof(pmt_real)); + printf("sizeof(pmt_complex) = %3zd\n", sizeof(pmt_complex)); + printf("sizeof(pmt_null) = %3zd\n", sizeof(pmt_null)); + printf("sizeof(pmt_pair) = %3zd\n", sizeof(pmt_pair)); + printf("sizeof(pmt_vector) = %3zd\n", sizeof(pmt_vector)); + printf("sizeof(pmt_dict) = %3zd\n", sizeof(pmt_dict)); + printf("sizeof(pmt_uniform_vector) = %3zd\n", sizeof(pmt_uniform_vector)); +} diff --git a/pmt/src/lib/pmt.h b/pmt/src/lib/pmt.h index 030637c4d..dcf1ce668 100644 --- a/pmt/src/lib/pmt.h +++ b/pmt/src/lib/pmt.h @@ -24,10 +24,11 @@ #define INCLUDED_PMT_H #include <boost/shared_ptr.hpp> +#include <boost/any.hpp> #include <complex> #include <string> #include <stdint.h> -#include <iostream> +#include <iosfwd> #include <stdexcept> /*! @@ -82,8 +83,8 @@ public: * I.e., there is a single false value, #f. * ------------------------------------------------------------------------ */ -extern const pmt_t PMT_BOOL_T; //< #t : boolean true constant -extern const pmt_t PMT_BOOL_F; //< #f : boolean false constant +extern const pmt_t PMT_T; //< #t : boolean true constant +extern const pmt_t PMT_F; //< #f : boolean false constant //! Return true if obj is #t or #f, else return false. bool pmt_is_bool(pmt_t obj); @@ -97,7 +98,7 @@ bool pmt_is_false(pmt_t obj); //! Return #f is val is false, else return #t. pmt_t pmt_from_bool(bool val); -//! Return true if val is PMT_BOOL_T, return false when val is PMT_BOOL_F, +//! Return true if val is PMT_T, return false when val is PMT_F, // else raise wrong_type exception. bool pmt_to_bool(pmt_t val); @@ -225,6 +226,13 @@ void pmt_set_car(pmt_t pair, pmt_t value); //! Stores \p value in the cdr field of \p pair. void pmt_set_cdr(pmt_t pair, pmt_t value); +pmt_t pmt_caar(pmt_t pair); +pmt_t pmt_cadr(pmt_t pair); +pmt_t pmt_cdar(pmt_t pair); +pmt_t pmt_cddr(pmt_t pair); +pmt_t pmt_caddr(pmt_t pair); +pmt_t pmt_cadddr(pmt_t pair); + /* * ------------------------------------------------------------------------ * Vectors @@ -414,6 +422,28 @@ pmt_t pmt_dict_values(pmt_t dict); /* * ------------------------------------------------------------------------ + * Any (wraps boost::any -- can be used to wrap pretty much anything) + * + * Cannot be serialized or used across process boundaries. + * See http://www.boost.org/doc/html/any.html + * ------------------------------------------------------------------------ + */ + +//! Return true if \p obj is an any +bool pmt_is_any(pmt_t obj); + +//! make an any +pmt_t pmt_make_any(const boost::any &any); + +//! Return underlying boost::any +boost::any pmt_any_ref(pmt_t obj); + +//! Store \p any in \p obj +void pmt_any_set(pmt_t obj, const boost::any &any); + + +/* + * ------------------------------------------------------------------------ * General functions * ------------------------------------------------------------------------ */ @@ -618,11 +648,14 @@ std::ostream& operator<<(std::ostream &os, pmt_t obj); /*! * \brief Write portable byte-serial representation of \p obj to \p sink */ -void pmt_serialize(pmt_t obj, std::ostream &sink); +bool pmt_serialize(pmt_t obj, std::streambuf &sink); /*! * \brief Create obj from portable byte-serial representation */ -pmt_t pmt_deserialize(std::istream &source); +pmt_t pmt_deserialize(std::streambuf &source); + + +void pmt_dump_sizeof(); // debugging #endif /* INCLUDED_PMT_H */ diff --git a/pmt/src/lib/pmt_int.h b/pmt/src/lib/pmt_int.h index 458443eaf..e82ce50e2 100644 --- a/pmt/src/lib/pmt_int.h +++ b/pmt/src/lib/pmt_int.h @@ -31,6 +31,8 @@ * See pmt.h for the public interface */ +#define PMT_LOCAL_ALLOCATOR 0 // define to 0 or 1 + class pmt_base : boost::noncopyable { protected: pmt_base(){}; @@ -47,6 +49,7 @@ public: virtual bool is_pair() const { return false; } virtual bool is_vector() const { return false; } virtual bool is_dict() const { return false; } + virtual bool is_any() const { return false; } virtual bool is_uniform_vector() const { return false; } virtual bool is_u8vector() const { return false; } @@ -62,6 +65,10 @@ public: virtual bool is_c32vector() const { return false; } virtual bool is_c64vector() const { return false; } +# if (PMT_LOCAL_ALLOCATOR) + void *operator new(size_t); + void operator delete(void *, size_t); +#endif }; class pmt_bool : public pmt_base @@ -189,6 +196,20 @@ public: pmt_t values() const; }; +class pmt_any : public pmt_base +{ + boost::any d_any; + +public: + pmt_any(const boost::any &any); + //~pmt_any(); + + bool is_any() const { return true; } + const boost::any &ref() const { return d_any; } + void set(const boost::any &any) { d_any = any; } +}; + + class pmt_uniform_vector : public pmt_base { public: diff --git a/pmt/src/lib/pmt_pool.cc b/pmt/src/lib/pmt_pool.cc new file mode 100644 index 000000000..16ab9c61e --- /dev/null +++ b/pmt/src/lib/pmt_pool.cc @@ -0,0 +1,96 @@ +/* -*- 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 <pmt_pool.h> +#include <algorithm> +#include <stdint.h> + +static inline size_t +ROUNDUP(size_t x, size_t stride) +{ + return ((((x) + (stride) - 1)/(stride)) * (stride)); +} + +pmt_pool::pmt_pool(size_t itemsize, size_t alignment, size_t allocation_size) + : d_itemsize(ROUNDUP(itemsize, alignment)), + d_alignment(alignment), + d_allocation_size(std::max(allocation_size, 16 * itemsize)), + d_freelist(0) +{ +} + +pmt_pool::~pmt_pool() +{ + for (unsigned int i = 0; i < d_allocations.size(); i++){ + delete [] d_allocations[i]; + } +} + +void * +pmt_pool::malloc() +{ + omni_mutex_lock l(d_mutex); + item *p; + + if (d_freelist){ // got something? + p = d_freelist; + d_freelist = p->d_next; + return p; + } + + // allocate a new chunk + char *alloc = new char[d_allocation_size + d_alignment - 1]; + d_allocations.push_back(alloc); + + // get the alignment we require + char *start = (char *)(((uintptr_t)alloc + d_alignment-1) & -d_alignment); + char *end = alloc + d_allocation_size + d_alignment - 1; + size_t n = (end - start) / d_itemsize; + + // link the new items onto the free list. + p = (item *) start; + for (size_t i = 0; i < n; i++){ + p->d_next = d_freelist; + d_freelist = p; + p = (item *)((char *) p + d_itemsize); + } + + // now return the first one + p = d_freelist; + d_freelist = p->d_next; + return p; +} + +void +pmt_pool::free(void *foo) +{ + if (!foo) + return; + + omni_mutex_lock l(d_mutex); + + item *p = (item *) foo; + p->d_next = d_freelist; + d_freelist = p; +} diff --git a/pmt/src/lib/pmt_pool.h b/pmt/src/lib/pmt_pool.h new file mode 100644 index 000000000..fd9cc0638 --- /dev/null +++ b/pmt/src/lib/pmt_pool.h @@ -0,0 +1,61 @@ +/* -*- 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_PMT_POOL_H +#define INCLUDED_PMT_POOL_H + +#include <cstddef> +#include <omnithread.h> +#include <vector> + +/*! + * \brief very simple thread-safe fixed-size allocation pool + * + * FIXME may want to go to global allocation with per-thread free list. + * This would eliminate virtually all lock contention. + */ +class pmt_pool { + + struct item { + struct item *d_next; + }; + + omni_mutex d_mutex; + + size_t d_itemsize; + size_t d_alignment; + size_t d_allocation_size; + item *d_freelist; + std::vector<char *> d_allocations; + +public: + /*! + * \param itemsize size in bytes of the items to be allocated. + * \param alignment alignment in bytes of all objects to be allocated (must be power-of-2). + * \param allocation_size number of bytes to allocate at a time from the underlying allocator. + */ + pmt_pool(size_t itemsize, size_t alignment = 16, size_t allocation_size = 4096); + ~pmt_pool(); + + void *malloc(); + void free(void *p); +}; + +#endif /* INCLUDED_PMT_POOL_H */ diff --git a/pmt/src/lib/pmt_serialize.cc b/pmt/src/lib/pmt_serialize.cc new file mode 100644 index 000000000..45f688be5 --- /dev/null +++ b/pmt/src/lib/pmt_serialize.cc @@ -0,0 +1,353 @@ +/* -*- 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 <vector> +#include <pmt.h> +#include "pmt_int.h" +#include "pmt_serial_tags.h" + +static pmt_t parse_pair(std::streambuf &sb); + +// ---------------------------------------------------------------- +// output primitives +// ---------------------------------------------------------------- + +static bool +serialize_untagged_u8(unsigned int i, std::streambuf &sb) +{ + return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof(); +} + +// always writes big-endian +static bool +serialize_untagged_u16(unsigned int i, std::streambuf &sb) +{ + sb.sputc((i >> 8) & 0xff); + return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof(); +} + +// always writes big-endian +static bool +serialize_untagged_u32(unsigned int i, std::streambuf &sb) +{ + sb.sputc((i >> 24) & 0xff); + sb.sputc((i >> 16) & 0xff); + sb.sputc((i >> 8) & 0xff); + return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof(); +} + +#if 0 +// always writes big-endian +static bool +serialize_untagged_u64(uint64_t i, std::streambuf &sb) +{ + sb.sputc((i >> 56) & 0xff); + sb.sputc((i >> 48) & 0xff); + sb.sputc((i >> 40) & 0xff); + sb.sputc((i >> 32) & 0xff); + sb.sputc((i >> 24) & 0xff); + sb.sputc((i >> 16) & 0xff); + sb.sputc((i >> 8) & 0xff); + return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof(); +} +#endif + +// ---------------------------------------------------------------- +// input primitives +// ---------------------------------------------------------------- + + +// always reads big-endian +static bool +deserialize_untagged_u8(uint8_t *ip, std::streambuf &sb) +{ + std::streambuf::traits_type::int_type t; + int i; + + t = sb.sbumpc(); + i = t & 0xff; + + *ip = i; + return t != std::streambuf::traits_type::eof(); +} + +// always reads big-endian +static bool +deserialize_untagged_u16(uint16_t *ip, std::streambuf &sb) +{ + std::streambuf::traits_type::int_type t; + int i; + + t = sb.sbumpc(); + i = t & 0xff; + + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + + *ip = i; + return t != std::streambuf::traits_type::eof(); +} + +// always reads big-endian +static bool +deserialize_untagged_u32(uint32_t *ip, std::streambuf &sb) +{ + std::streambuf::traits_type::int_type t; + int i; + + t = sb.sbumpc(); + i = t & 0xff; + + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + + *ip = i; + return t != std::streambuf::traits_type::eof(); +} + +#if 0 +// always reads big-endian +static bool +deserialize_untagged_u64(uint64_t *ip, std::streambuf &sb) +{ + std::streambuf::traits_type::int_type t; + uint64_t i; + + t = sb.sbumpc(); + i = t & 0xff; + + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + + *ip = i; + return t != std::streambuf::traits_type::eof(); +} +#endif + +/* + * Write portable byte-serial representation of \p obj to \p sb + * + * N.B., Circular structures cause infinite recursion. + */ +bool +pmt_serialize(pmt_t obj, std::streambuf &sb) +{ + bool ok = true; + + tail_recursion: + + if (pmt_is_bool(obj)){ + if (pmt_eq(obj, PMT_T)) + return serialize_untagged_u8(PST_TRUE, sb); + else + return serialize_untagged_u8(PST_FALSE, sb); + } + + if (pmt_is_null(obj)) + return serialize_untagged_u8(PST_NULL, sb); + + if (pmt_is_symbol(obj)){ + const std::string s = pmt_symbol_to_string(obj); + size_t len = s.size(); + ok = serialize_untagged_u8(PST_SYMBOL, sb); + ok &= serialize_untagged_u16(len, sb); + for (size_t i = 0; i < len; i++) + ok &= serialize_untagged_u8(s[i], sb); + return ok; + } + + if (pmt_is_pair(obj)){ + ok = serialize_untagged_u8(PST_PAIR, sb); + ok &= pmt_serialize(pmt_car(obj), sb); + if (!ok) + return false; + obj = pmt_cdr(obj); + goto tail_recursion; + } + + if (pmt_is_number(obj)){ + + if (pmt_is_integer(obj)){ + long i = pmt_to_long(obj); + if (sizeof(long) > 4){ + if (i < -2147483647 || i > 2147483647) + throw pmt_notimplemented("pmt_serialize (64-bit integers)", obj); + } + ok = serialize_untagged_u8(PST_INT32, sb); + ok &= serialize_untagged_u32(i, sb); + return ok; + } + + if (pmt_is_real(obj)) + throw pmt_notimplemented("pmt_serialize (real)", obj); + + if (pmt_is_complex(obj)) + throw pmt_notimplemented("pmt_serialize (complex)", obj); + } + + if (pmt_is_vector(obj)) + throw pmt_notimplemented("pmt_serialize (vector)", obj); + + if (pmt_is_uniform_vector(obj)) + throw pmt_notimplemented("pmt_serialize (uniform-vector)", obj); + + if (pmt_is_dict(obj)) + throw pmt_notimplemented("pmt_serialize (dict)", obj); + + + throw pmt_notimplemented("pmt_serialize (?)", obj); +} + +/* + * Create obj from portable byte-serial representation + * + * Returns next obj from streambuf, or PMT_EOF at end of file. + * Throws exception on malformed input. + */ +pmt_t +pmt_deserialize(std::streambuf &sb) +{ + uint8_t tag; + //uint8_t u8; + uint16_t u16; + uint32_t u32; + //uint32_t u64; + static char tmpbuf[1024]; + + if (!deserialize_untagged_u8(&tag, sb)) + return PMT_EOF; + + switch (tag){ + case PST_TRUE: + return PMT_T; + + case PST_FALSE: + return PMT_F; + + case PST_NULL: + return PMT_NIL; + + case PST_SYMBOL: + if (!deserialize_untagged_u16(&u16, sb)) + goto error; + if (u16 > sizeof(tmpbuf)) + throw pmt_notimplemented("pmt_deserialize: very long symbol", + PMT_F); + if (sb.sgetn(tmpbuf, u16) != u16) + goto error; + return pmt_intern(std::string(tmpbuf, u16)); + + case PST_INT32: + if (!deserialize_untagged_u32(&u32, sb)) + goto error; + return pmt_from_long((int32_t) u32); + + case PST_PAIR: + return parse_pair(sb); + + case PST_DOUBLE: + case PST_COMPLEX: + case PST_VECTOR: + case PST_DICT: + case PST_UNIFORM_VECTOR: + case PST_COMMENT: + throw pmt_notimplemented("pmt_deserialize: tag value = ", + pmt_from_long(tag)); + + default: + throw pmt_exception("pmt_deserialize: malformed input stream, tag value = ", + pmt_from_long(tag)); + } + + error: + throw pmt_exception("pmt_deserialize: malformed input stream", PMT_F); +} + +/* + * This is a mostly non-recursive implementation that allows us to + * deserialize very long lists w/o exhausting the evaluation stack. + * + * On entry we've already eaten the PST_PAIR tag. + */ +pmt_t +parse_pair(std::streambuf &sb) +{ + uint8_t tag; + pmt_t val, expr, lastnptr, nptr; + + // + // Keep appending nodes until we get a non-PAIR cdr. + // + lastnptr = PMT_NIL; + while (1){ + expr = pmt_deserialize(sb); // read the car + + nptr = pmt_cons(expr, PMT_NIL); // build new cell + if (pmt_is_null(lastnptr)) + val = nptr; + else + pmt_set_cdr(lastnptr, nptr); + lastnptr = nptr; + + if (!deserialize_untagged_u8(&tag, sb)) // get tag of cdr + throw pmt_exception("pmt_deserialize: malformed input stream", PMT_F); + + if (tag == PST_PAIR) + continue; // keep on looping... + + if (tag == PST_NULL){ + expr = PMT_NIL; + break; + } + + // + // default: push tag back and use pmt_deserialize to get the cdr + // + sb.sungetc(); + expr = pmt_deserialize(sb); + break; + } + + // + // At this point, expr contains the value of the final cdr in the list. + // + pmt_set_cdr(lastnptr, expr); + return val; +} diff --git a/pmt/src/lib/qa_pmt_prims.cc b/pmt/src/lib/qa_pmt_prims.cc index cb687b0e1..4a665fe53 100644 --- a/pmt/src/lib/qa_pmt_prims.cc +++ b/pmt/src/lib/qa_pmt_prims.cc @@ -24,13 +24,14 @@ #include <cppunit/TestAssert.h> #include <pmt.h> #include <stdio.h> +#include <sstream> void qa_pmt_prims::test_symbols() { - CPPUNIT_ASSERT(!pmt_is_symbol(PMT_BOOL_T)); - CPPUNIT_ASSERT(!pmt_is_symbol(PMT_BOOL_F)); - CPPUNIT_ASSERT_THROW(pmt_symbol_to_string(PMT_BOOL_F), pmt_wrong_type); + CPPUNIT_ASSERT(!pmt_is_symbol(PMT_T)); + CPPUNIT_ASSERT(!pmt_is_symbol(PMT_F)); + CPPUNIT_ASSERT_THROW(pmt_symbol_to_string(PMT_F), pmt_wrong_type); pmt_t sym1 = pmt_string_to_symbol("test"); CPPUNIT_ASSERT(pmt_is_symbol(sym1)); @@ -76,13 +77,13 @@ void qa_pmt_prims::test_booleans() { pmt_t sym = pmt_string_to_symbol("test"); - CPPUNIT_ASSERT(pmt_is_bool(PMT_BOOL_T)); - CPPUNIT_ASSERT(pmt_is_bool(PMT_BOOL_F)); + CPPUNIT_ASSERT(pmt_is_bool(PMT_T)); + CPPUNIT_ASSERT(pmt_is_bool(PMT_F)); CPPUNIT_ASSERT(!pmt_is_bool(sym)); - CPPUNIT_ASSERT_EQUAL(pmt_from_bool(false), PMT_BOOL_F); - CPPUNIT_ASSERT_EQUAL(pmt_from_bool(true), PMT_BOOL_T); - CPPUNIT_ASSERT_EQUAL(false, pmt_to_bool(PMT_BOOL_F)); - CPPUNIT_ASSERT_EQUAL(true, pmt_to_bool(PMT_BOOL_T)); + CPPUNIT_ASSERT_EQUAL(pmt_from_bool(false), PMT_F); + CPPUNIT_ASSERT_EQUAL(pmt_from_bool(true), PMT_T); + CPPUNIT_ASSERT_EQUAL(false, pmt_to_bool(PMT_F)); + CPPUNIT_ASSERT_EQUAL(true, pmt_to_bool(PMT_T)); CPPUNIT_ASSERT_THROW(pmt_to_bool(sym), pmt_wrong_type); } @@ -91,10 +92,10 @@ qa_pmt_prims::test_integers() { pmt_t p1 = pmt_from_long(1); pmt_t m1 = pmt_from_long(-1); - CPPUNIT_ASSERT(!pmt_is_integer(PMT_BOOL_T)); + CPPUNIT_ASSERT(!pmt_is_integer(PMT_T)); CPPUNIT_ASSERT(pmt_is_integer(p1)); CPPUNIT_ASSERT(pmt_is_integer(m1)); - CPPUNIT_ASSERT_THROW(pmt_to_long(PMT_BOOL_T), pmt_wrong_type); + CPPUNIT_ASSERT_THROW(pmt_to_long(PMT_T), pmt_wrong_type); CPPUNIT_ASSERT_EQUAL(-1L, pmt_to_long(m1)); CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(p1)); } @@ -104,10 +105,10 @@ qa_pmt_prims::test_reals() { pmt_t p1 = pmt_from_double(1); pmt_t m1 = pmt_from_double(-1); - CPPUNIT_ASSERT(!pmt_is_real(PMT_BOOL_T)); + CPPUNIT_ASSERT(!pmt_is_real(PMT_T)); CPPUNIT_ASSERT(pmt_is_real(p1)); CPPUNIT_ASSERT(pmt_is_real(m1)); - CPPUNIT_ASSERT_THROW(pmt_to_double(PMT_BOOL_T), pmt_wrong_type); + CPPUNIT_ASSERT_THROW(pmt_to_double(PMT_T), pmt_wrong_type); CPPUNIT_ASSERT_EQUAL(-1.0, pmt_to_double(m1)); CPPUNIT_ASSERT_EQUAL(1.0, pmt_to_double(p1)); CPPUNIT_ASSERT_EQUAL(1.0, pmt_to_double(pmt_from_long(1))); @@ -118,10 +119,10 @@ qa_pmt_prims::test_complexes() { pmt_t p1 = pmt_make_rectangular(2, -3); pmt_t m1 = pmt_make_rectangular(-3, 2); - CPPUNIT_ASSERT(!pmt_is_complex(PMT_BOOL_T)); + CPPUNIT_ASSERT(!pmt_is_complex(PMT_T)); CPPUNIT_ASSERT(pmt_is_complex(p1)); CPPUNIT_ASSERT(pmt_is_complex(m1)); - CPPUNIT_ASSERT_THROW(pmt_to_complex(PMT_BOOL_T), pmt_wrong_type); + CPPUNIT_ASSERT_THROW(pmt_to_complex(PMT_T), pmt_wrong_type); CPPUNIT_ASSERT_EQUAL(std::complex<double>(2, -3), pmt_to_complex(p1)); CPPUNIT_ASSERT_EQUAL(std::complex<double>(-3, 2), pmt_to_complex(m1)); CPPUNIT_ASSERT_EQUAL(std::complex<double>(1.0, 0), pmt_to_complex(pmt_from_long(1))); @@ -242,7 +243,7 @@ qa_pmt_prims::test_misc() pmt_t alist = pmt_cons(p0, pmt_cons(p1, pmt_cons(p2, PMT_NIL))); CPPUNIT_ASSERT(pmt_eq(p1, pmt_assv(k1, alist))); - CPPUNIT_ASSERT(pmt_eq(PMT_BOOL_F, pmt_assv(k3, alist))); + CPPUNIT_ASSERT(pmt_eq(PMT_F, pmt_assv(k3, alist))); pmt_t keys = pmt_cons(k0, pmt_cons(k1, pmt_cons(k2, PMT_NIL))); pmt_t vals = pmt_cons(v0, pmt_cons(v1, pmt_cons(v2, PMT_NIL))); @@ -293,3 +294,102 @@ qa_pmt_prims::test_io() CPPUNIT_ASSERT_EQUAL(std::string("k0"), pmt_write_string(k0)); } + +// ------------------------------------------------------------------------ + +// class foo is used in test_any below. +// It can't be declared in the scope of test_any because of template +// namespace problems. + +class foo { +public: + double d_double; + int d_int; + foo(double d=0, int i=0) : d_double(d), d_int(i) {} +}; + +bool operator==(const foo &a, const foo &b) +{ + return a.d_double == b.d_double && a.d_int == b.d_int; +} + +std::ostream& operator<<(std::ostream &os, const foo obj) +{ + os << "<foo: " << obj.d_double << ", " << obj.d_int << ">"; + return os; +} + +void +qa_pmt_prims::test_any() +{ + boost::any a0; + boost::any a1; + boost::any a2; + + a0 = std::string("Hello!"); + a1 = 42; + a2 = foo(3.250, 21); + + pmt_t p0 = pmt_make_any(a0); + pmt_t p1 = pmt_make_any(a1); + pmt_t p2 = pmt_make_any(a2); + + CPPUNIT_ASSERT_EQUAL(std::string("Hello!"), + boost::any_cast<std::string>(pmt_any_ref(p0))); + + CPPUNIT_ASSERT_EQUAL(42, + boost::any_cast<int>(pmt_any_ref(p1))); + + CPPUNIT_ASSERT_EQUAL(foo(3.250, 21), + boost::any_cast<foo>(pmt_any_ref(p2))); +} + +// ------------------------------------------------------------------------ + +void +qa_pmt_prims::test_serialize() +{ + std::stringbuf sb; // fake channel + pmt_t a = pmt_intern("a"); + pmt_t b = pmt_intern("b"); + pmt_t c = pmt_intern("c"); + + sb.str(""); // reset channel to empty + + // write stuff to channel + + pmt_serialize(PMT_NIL, sb); + pmt_serialize(pmt_intern("foobarvia"), sb); + pmt_serialize(pmt_from_long(123456789), sb); + pmt_serialize(pmt_from_long(-123456789), sb); + pmt_serialize(pmt_cons(PMT_NIL, PMT_NIL), sb); + pmt_serialize(pmt_cons(a, b), sb); + pmt_serialize(pmt_list1(a), sb); + pmt_serialize(pmt_list2(a, b), sb); + pmt_serialize(pmt_list3(a, b, c), sb); + pmt_serialize(pmt_list3(a, pmt_list3(c, b, a), c), sb); + pmt_serialize(PMT_T, sb); + pmt_serialize(PMT_F, sb); + + // read it back + + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), PMT_NIL)); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_intern("foobarvia"))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_from_long(123456789))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_from_long(-123456789))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_cons(PMT_NIL, PMT_NIL))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_cons(a, b))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_list1(a))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_list2(a, b))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_list3(a, b, c))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_list3(a, pmt_list3(c, b, a), c))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), PMT_T)); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), PMT_F)); + + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), PMT_EOF)); // last item + + + // FIXME add tests for real, complex, vector, uniform-vector, dict + // FIXME add tests for malformed input too. + +} diff --git a/pmt/src/lib/qa_pmt_prims.h b/pmt/src/lib/qa_pmt_prims.h index 8d379c5af..a390343bd 100644 --- a/pmt/src/lib/qa_pmt_prims.h +++ b/pmt/src/lib/qa_pmt_prims.h @@ -38,7 +38,9 @@ class qa_pmt_prims : public CppUnit::TestCase { CPPUNIT_TEST(test_equivalence); CPPUNIT_TEST(test_misc); CPPUNIT_TEST(test_dict); + CPPUNIT_TEST(test_any); CPPUNIT_TEST(test_io); + CPPUNIT_TEST(test_serialize); CPPUNIT_TEST_SUITE_END(); private: @@ -52,7 +54,9 @@ class qa_pmt_prims : public CppUnit::TestCase { void test_equivalence(); void test_misc(); void test_dict(); + void test_any(); void test_io(); + void test_serialize(); }; #endif /* INCLUDED_QA_PMT_PRIMS_H */ diff --git a/pmt/src/scheme/Makefile.am b/pmt/src/scheme/Makefile.am new file mode 100644 index 000000000..7700a1fc0 --- /dev/null +++ b/pmt/src/scheme/Makefile.am @@ -0,0 +1,21 @@ +# +# 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. +# + +SUBDIRS = gnuradio diff --git a/pmt/src/scheme/gnuradio/Makefile.am b/pmt/src/scheme/gnuradio/Makefile.am new file mode 100644 index 000000000..12bc9b115 --- /dev/null +++ b/pmt/src/scheme/gnuradio/Makefile.am @@ -0,0 +1,32 @@ +# +# 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. +# + +#pkgdatadir = $(datadir)/gnuradio + +EXTRA_DIST = \ + gen-serial-tags.scm \ + pmt-serial-tags.scm \ + pmt-serialize.scm + + +# really scheme source files +pkgdata_DATA = \ + pmt-serial-tags.scm \ + pmt-serialize.scm diff --git a/pmt/src/scheme/gnuradio/gen-serial-tags.scm b/pmt/src/scheme/gnuradio/gen-serial-tags.scm new file mode 100755 index 000000000..5bcf8015a --- /dev/null +++ b/pmt/src/scheme/gnuradio/gen-serial-tags.scm @@ -0,0 +1,118 @@ +#!/usr/bin/guile \ +-e main -s +!# +;;; -*-scheme-*- +;;; +;;; 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. +;;; + +(use-modules (ice-9 format)) + +(defmacro when (pred . body) + `(if ,pred (begin ,@body) #f)) + +;; ---------------------------------------------------------------- + +(define (main args) + + (define (usage) + (format 0 + "usage: ~a <pmt-serial-tags.scm> <pmt_serial_tags.h>~%" + (car args))) + + (when (not (= (length args) 3)) + (usage) + (format 0 "args: ~s~%" args) + (exit 1)) + + (let ((i-file (open-input-file (cadr args))) + (h-file (open-output-file (caddr args)))) + + (write-header-comment h-file "// ") + (display "#ifndef INCLUDED_PMT_SERIAL_TAGS_H\n" h-file) + (display "#define INCLUDED_PMT_SERIAL_TAGS_H\n" h-file) + (newline h-file) + (display "enum pst_tags {\n" h-file) + + (for-each-in-file i-file + (lambda (form) + (let* ((name (cadr form)) + (c-name (string-upcase (c-ify name))) + (value (caddr form))) + ;;(format h-file "static const int ~a\t= 0x~x;~%" c-name value) + (format h-file " ~a\t= 0x~x,~%" c-name value)))) + + (display "};\n" h-file) + (display "#endif\n" h-file))) + +(define (c-ify name) + (list->string (map (lambda (c) + (if (eqv? c #\-) #\_ c)) + (string->list (symbol->string name))))) + + +(define (write-header-comment o-port prefix) + (for-each (lambda (comment) + (format o-port "~a~a~%" prefix comment)) + header-comment)) + +(define header-comment + '( + "" + "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." + "" + "" + "THIS FILE IS MACHINE GENERATED FROM pmt-serial-tags.scm. DO NOT EDIT BY HAND." + "See pmt-serial-tags.scm for additional commentary." + "")) + + + +(define (for-each-in-file file f) + (let ((port (if (port? file) + file + (open-input-file file)))) + (letrec + ((loop + (lambda (port form) + (cond ((eof-object? form) + (when (not (eq? port file)) + (close-input-port port)) + #t) + (else + (f form) + (set! form #f) ; for GC + (loop port (read port))))))) + (loop port (read port))))) diff --git a/pmt/src/scheme/gnuradio/macros-etc.scm b/pmt/src/scheme/gnuradio/macros-etc.scm new file mode 100644 index 000000000..518c1ffe1 --- /dev/null +++ b/pmt/src/scheme/gnuradio/macros-etc.scm @@ -0,0 +1,50 @@ +;;; -*- scheme -*- +;;; +;;; 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. +;;; + +(define-module (gnuradio macros-etc) + :export (atom? when unless for-each-in-file)) + +(define (atom? obj) + (not (pair? obj))) + +(defmacro when (pred . body) + `(if ,pred (begin ,@body) #f)) + +(defmacro unless (pred . body) + `(if (not ,pred) (begin ,@body) #f)) + + +(define (for-each-in-file file f) + (let ((port (if (port? file) + file + (open-input-file file)))) + (letrec + ((loop + (lambda (port form) + (cond ((eof-object? form) + (when (not (eq? port file)) + (close-input-port port)) + #t) + (else + (f form) + (set! form #f) ; for GC + (loop port (read port))))))) + (loop port (read port))))) diff --git a/pmt/src/scheme/gnuradio/pmt-serial-tags.scm b/pmt/src/scheme/gnuradio/pmt-serial-tags.scm new file mode 100644 index 000000000..4dd183034 --- /dev/null +++ b/pmt/src/scheme/gnuradio/pmt-serial-tags.scm @@ -0,0 +1,75 @@ +;;; -*-scheme-*- +;;; +;;; 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 (define 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. +;;; + +;;; definitions of tag values used for marshalling pmt data + +(define pst-true #x00) +(define pst-false #x01) +(define pst-symbol #x02) ; untagged-int16 n; followed by n bytes of symbol name +(define pst-int32 #x03) +(define pst-double #x04) +(define pst-complex #x05) ; complex<double>: real, imag +(define pst-null #x06) +(define pst-pair #x07) ; followed by two objects +(define pst-vector #x08) ; untagged-int32 n; followed by n objects +(define pst-dict #x09) ; untagged-int32 n; followed by n key/value tuples + +(define pst-uniform-vector #x0a) + +;; u8, s8, u16, s16, u32, s32, u64, s64, f32, f64, c32, c64 +;; +;; untagged-uint8 tag +;; untagged-uint8 uvi (define uniform vector info, see below) +;; untagged-int32 n-items +;; untagged-uint8 npad +;; npad bytes of zeros to align binary data +;; n-items binary numeric items +;; +;; uvi: +;; +-+-+-+-+-+-+-+-+ +;; |B| subtype | +;; +-+-+-+-+-+-+-+-+ +;; +;; B == 0, numeric data is little-endian. +;; B == 1, numeric data is big-endian. + + (define uvi-endian-mask #x80) + (define uvi-subtype-mask #x7f) + + (define uvi-little-endian #x00) + (define uvi-big-endian #x80) + + (define uvi-u8 #x00) + (define uvi-s8 #x01) + (define uvi-u16 #x02) + (define uvi-s16 #x03) + (define uvi-u32 #x04) + (define uvi-s32 #x05) + (define uvi-u64 #x06) + (define uvi-s64 #x07) + (define uvi-f32 #x08) + (define uvi-f64 #x09) + (define uvi-c32 #x0a) + (define uvi-c64 #x0b) + + +(define pst-comment #x3b) ; ascii ';' +(define pst-comment-end #x0a) ; ascii '\n' diff --git a/pmt/src/scheme/gnuradio/pmt-serialize.scm b/pmt/src/scheme/gnuradio/pmt-serialize.scm new file mode 100644 index 000000000..a39f9cf50 --- /dev/null +++ b/pmt/src/scheme/gnuradio/pmt-serialize.scm @@ -0,0 +1,48 @@ +;;; +;;; 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. +;;; + +;;; An implementation of pmt_serialize in scheme. +;;; Currently handles only symbols and pairs. They're all we need for now. + +(define-module (gnuradio pmt-serialize) + :export (pmt-serialize)) + +(load-from-path "gnuradio/pmt-serial-tags") + +(define (pmt-serialize obj put-byte) + (define (put-u16 x) + (put-byte (logand (ash x -8) #xff)) + (put-byte (logand x #xff))) + + (cond ((null? obj) + (put-byte pst-null)) + ((symbol? obj) + (let* ((sym-as-bytes (map char->integer (string->list (symbol->string obj)))) + (len (length sym-as-bytes))) + (put-byte pst-symbol) + (put-u16 len) + (for-each put-byte sym-as-bytes))) + + ((pair? obj) + (put-byte pst-pair) + (pmt-serialize (car obj) put-byte) + (pmt-serialize (cdr obj) put-byte)) + (else + (throw 'not-implemented "pmt-serialize" obj)))) |