summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.common12
-rw-r--r--config/grc_mblock.m410
-rw-r--r--config/grc_pmt.m410
-rw-r--r--config/grc_usrp.m414
-rw-r--r--configure.ac7
-rw-r--r--gnuradio-core/src/python/bin/Makefile.am2
-rw-r--r--mblock/README4
-rw-r--r--mblock/src/Makefile.am2
-rw-r--r--mblock/src/lib/Makefile.am51
-rw-r--r--mblock/src/lib/benchmark_send.cc (renamed from mblock/src/lib/mb_runtime_placeholder.h)39
-rw-r--r--mblock/src/lib/getres.cc32
-rw-r--r--mblock/src/lib/mb_class_registry.cc (renamed from mblock/src/lib/mb_runtime_thread_per_mblock.cc)44
-rw-r--r--mblock/src/lib/mb_class_registry.h51
-rw-r--r--mblock/src/lib/mb_exception.cc19
-rw-r--r--mblock/src/lib/mb_exception.h26
-rw-r--r--mblock/src/lib/mb_gettid.cc53
-rw-r--r--mblock/src/lib/mb_gettid.h (renamed from mblock/src/lib/mb_runtime_thread_per_mblock.h)18
-rw-r--r--mblock/src/lib/mb_mblock.cc104
-rw-r--r--mblock/src/lib/mb_mblock.h136
-rw-r--r--mblock/src/lib/mb_mblock_impl.cc76
-rw-r--r--mblock/src/lib/mb_mblock_impl.h26
-rw-r--r--mblock/src/lib/mb_message.cc41
-rw-r--r--mblock/src/lib/mb_message.h17
-rw-r--r--mblock/src/lib/mb_msg_accepter_msgq.cc46
-rw-r--r--mblock/src/lib/mb_msg_accepter_msgq.h39
-rw-r--r--mblock/src/lib/mb_msg_queue.cc19
-rw-r--r--mblock/src/lib/mb_msg_queue.h14
-rw-r--r--mblock/src/lib/mb_port.cc3
-rw-r--r--mblock/src/lib/mb_port.h12
-rw-r--r--mblock/src/lib/mb_port_simple.cc23
-rw-r--r--mblock/src/lib/mb_port_simple.h10
-rw-r--r--mblock/src/lib/mb_protocol_class.cc23
-rw-r--r--mblock/src/lib/mb_protocol_class.h10
-rw-r--r--mblock/src/lib/mb_runtime.cc5
-rw-r--r--mblock/src/lib/mb_runtime.h34
-rw-r--r--mblock/src/lib/mb_runtime_base.cc (renamed from mblock/src/lib/mb_runtime_placeholder.cc)40
-rw-r--r--mblock/src/lib/mb_runtime_base.h78
-rw-r--r--mblock/src/lib/mb_runtime_nop.cc32
-rw-r--r--mblock/src/lib/mb_runtime_nop.h16
-rw-r--r--mblock/src/lib/mb_runtime_thread_per_block.cc349
-rw-r--r--mblock/src/lib/mb_runtime_thread_per_block.h84
-rw-r--r--mblock/src/lib/mb_time.cc84
-rw-r--r--mblock/src/lib/mb_time.h89
-rw-r--r--mblock/src/lib/mb_timer_queue.cc63
-rw-r--r--mblock/src/lib/mb_timer_queue.h73
-rw-r--r--mblock/src/lib/mb_worker.cc178
-rw-r--r--mblock/src/lib/mb_worker.h106
-rw-r--r--mblock/src/lib/mbi_runtime_lock.h4
-rw-r--r--mblock/src/lib/qa_bitset.cc493
-rw-r--r--mblock/src/lib/qa_bitset.mbh61
-rw-r--r--mblock/src/lib/qa_disconnect.cc238
-rw-r--r--mblock/src/lib/qa_mblock.cc4
-rw-r--r--mblock/src/lib/qa_mblock_prims.cc128
-rw-r--r--mblock/src/lib/qa_mblock_send.cc92
-rw-r--r--mblock/src/lib/qa_mblock_sys.cc271
-rw-r--r--mblock/src/lib/qa_mblock_sys.h45
-rw-r--r--mblock/src/lib/qa_timeouts.cc292
-rw-r--r--mblock/src/lib/qa_timeouts.h43
-rw-r--r--mblock/src/scheme/Makefile.am21
-rw-r--r--mblock/src/scheme/gnuradio/Makefile.am19
-rwxr-xr-xmblock/src/scheme/gnuradio/compile-mbh.scm231
-rw-r--r--omnithread/omnithread.h4
-rw-r--r--omnithread/posix.cc12
-rw-r--r--pmt/src/Makefile.am4
-rw-r--r--pmt/src/lib/Makefile.am17
-rw-r--r--pmt/src/lib/pmt.cc170
-rw-r--r--pmt/src/lib/pmt.h45
-rw-r--r--pmt/src/lib/pmt_int.h21
-rw-r--r--pmt/src/lib/pmt_pool.cc96
-rw-r--r--pmt/src/lib/pmt_pool.h61
-rw-r--r--pmt/src/lib/pmt_serialize.cc353
-rw-r--r--pmt/src/lib/qa_pmt_prims.cc132
-rw-r--r--pmt/src/lib/qa_pmt_prims.h4
-rw-r--r--pmt/src/scheme/Makefile.am21
-rw-r--r--pmt/src/scheme/gnuradio/Makefile.am32
-rwxr-xr-xpmt/src/scheme/gnuradio/gen-serial-tags.scm118
-rw-r--r--pmt/src/scheme/gnuradio/macros-etc.scm50
-rw-r--r--pmt/src/scheme/gnuradio/pmt-serial-tags.scm75
-rw-r--r--pmt/src/scheme/gnuradio/pmt-serialize.scm48
-rw-r--r--usrp/doc/inband-signaling-usb-host237
-rwxr-xr-xusrp/fpga/inband_lib/chan_fifo_reader.v197
-rwxr-xr-xusrp/fpga/inband_lib/data_packet_fifo.v128
-rwxr-xr-xusrp/fpga/inband_lib/tx_buffer_inband.v183
-rwxr-xr-xusrp/fpga/inband_lib/usb_fifo_reader.v135
-rwxr-xr-xusrp/fpga/inband_lib/usb_packet_fifo.v112
-rwxr-xr-xusrp/fpga/inband_lib/usb_packet_fifo2.v119
-rwxr-xr-xusrp/fpga/megacells/fifo_512.bsf116
-rwxr-xr-xusrp/fpga/megacells/fifo_512.cmp31
-rwxr-xr-xusrp/fpga/megacells/fifo_512.inc32
-rwxr-xr-xusrp/fpga/megacells/fifo_512.v180
-rwxr-xr-xusrp/fpga/megacells/fifo_512_bb.v131
-rw-r--r--usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf12
-rw-r--r--usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v16
-rw-r--r--usrp/host/apps/Makefile.am10
-rw-r--r--usrp/host/lib/Makefile.am130
-rw-r--r--usrp/host/lib/dxc-io-assignments.gnumericbin3251 -> 0 bytes
-rw-r--r--usrp/host/lib/inband/Makefile.am92
-rwxr-xr-xusrp/host/lib/inband/dump_packets.py65
-rwxr-xr-xusrp/host/lib/inband/gen_test_packets.py87
-rw-r--r--usrp/host/lib/inband/qa_inband.cc35
-rw-r--r--usrp/host/lib/inband/qa_inband.h35
-rw-r--r--usrp/host/lib/inband/qa_inband_packet_prims.cc161
-rw-r--r--usrp/host/lib/inband/qa_inband_packet_prims.h41
-rw-r--r--usrp/host/lib/inband/qa_inband_usrp_server.cc455
-rw-r--r--usrp/host/lib/inband/qa_inband_usrp_server.h42
-rw-r--r--usrp/host/lib/inband/test_inband.cc36
-rw-r--r--usrp/host/lib/inband/usb_packet.py115
-rw-r--r--usrp/host/lib/inband/usrp_inband_usb_packet.h149
-rw-r--r--usrp/host/lib/inband/usrp_server.cc394
-rw-r--r--usrp/host/lib/inband/usrp_server.h82
-rw-r--r--usrp/host/lib/inband/usrp_server.mbh256
-rw-r--r--usrp/host/lib/legacy/Makefile.am153
-rw-r--r--usrp/host/lib/legacy/README_OSX (renamed from usrp/host/lib/README_OSX)0
-rw-r--r--usrp/host/lib/legacy/ad9862.h (renamed from usrp/host/lib/ad9862.h)0
-rwxr-xr-xusrp/host/lib/legacy/check_data.py (renamed from usrp/host/lib/check_data.py)0
-rw-r--r--usrp/host/lib/legacy/circular_buffer.h (renamed from usrp/host/lib/circular_buffer.h)0
-rw-r--r--usrp/host/lib/legacy/circular_linked_list.h (renamed from usrp/host/lib/circular_linked_list.h)0
-rw-r--r--usrp/host/lib/legacy/darwin_libusb.h (renamed from usrp/host/lib/darwin_libusb.h)0
-rwxr-xr-xusrp/host/lib/legacy/dump_data.py (renamed from usrp/host/lib/dump_data.py)0
-rw-r--r--usrp/host/lib/legacy/fusb.cc (renamed from usrp/host/lib/fusb.cc)0
-rw-r--r--usrp/host/lib/legacy/fusb.h (renamed from usrp/host/lib/fusb.h)0
-rw-r--r--usrp/host/lib/legacy/fusb_darwin.cc (renamed from usrp/host/lib/fusb_darwin.cc)0
-rw-r--r--usrp/host/lib/legacy/fusb_darwin.h (renamed from usrp/host/lib/fusb_darwin.h)0
-rw-r--r--usrp/host/lib/legacy/fusb_generic.cc (renamed from usrp/host/lib/fusb_generic.cc)0
-rw-r--r--usrp/host/lib/legacy/fusb_generic.h (renamed from usrp/host/lib/fusb_generic.h)0
-rw-r--r--usrp/host/lib/legacy/fusb_linux.cc (renamed from usrp/host/lib/fusb_linux.cc)0
-rw-r--r--usrp/host/lib/legacy/fusb_linux.h (renamed from usrp/host/lib/fusb_linux.h)0
-rw-r--r--usrp/host/lib/legacy/fusb_ra_wb.cc (renamed from usrp/host/lib/fusb_ra_wb.cc)0
-rw-r--r--usrp/host/lib/legacy/fusb_ra_wb.h (renamed from usrp/host/lib/fusb_ra_wb.h)0
-rw-r--r--usrp/host/lib/legacy/fusb_sysconfig_darwin.cc (renamed from usrp/host/lib/fusb_sysconfig_darwin.cc)0
-rw-r--r--usrp/host/lib/legacy/fusb_sysconfig_generic.cc (renamed from usrp/host/lib/fusb_sysconfig_generic.cc)0
-rw-r--r--usrp/host/lib/legacy/fusb_sysconfig_linux.cc (renamed from usrp/host/lib/fusb_sysconfig_linux.cc)0
-rw-r--r--usrp/host/lib/legacy/fusb_sysconfig_ra_wb.cc (renamed from usrp/host/lib/fusb_sysconfig_ra_wb.cc)0
-rw-r--r--usrp/host/lib/legacy/fusb_sysconfig_win32.cc (renamed from usrp/host/lib/fusb_sysconfig_win32.cc)0
-rw-r--r--usrp/host/lib/legacy/fusb_win32.cc (renamed from usrp/host/lib/fusb_win32.cc)0
-rw-r--r--usrp/host/lib/legacy/fusb_win32.h (renamed from usrp/host/lib/fusb_win32.h)0
-rwxr-xr-xusrp/host/lib/legacy/gen_usrp_dbid.py (renamed from usrp/host/lib/gen_usrp_dbid.py)0
-rw-r--r--usrp/host/lib/legacy/md5.c (renamed from usrp/host/lib/md5.c)0
-rw-r--r--usrp/host/lib/legacy/md5.h (renamed from usrp/host/lib/md5.h)0
-rw-r--r--usrp/host/lib/legacy/mld_threads.h (renamed from usrp/host/lib/mld_threads.h)0
-rw-r--r--usrp/host/lib/legacy/rate_to_regval.h (renamed from usrp/host/lib/rate_to_regval.h)0
-rw-r--r--usrp/host/lib/legacy/std_paths.h.in (renamed from usrp/host/lib/std_paths.h.in)0
-rw-r--r--usrp/host/lib/legacy/usrp_basic.cc (renamed from usrp/host/lib/usrp_basic.cc)2
-rw-r--r--usrp/host/lib/legacy/usrp_basic.h (renamed from usrp/host/lib/usrp_basic.h)0
-rw-r--r--usrp/host/lib/legacy/usrp_bytesex.h (renamed from usrp/host/lib/usrp_bytesex.h)31
-rw-r--r--usrp/host/lib/legacy/usrp_config.cc (renamed from usrp/host/lib/usrp_config.cc)0
-rw-r--r--usrp/host/lib/legacy/usrp_config.h (renamed from usrp/host/lib/usrp_config.h)0
-rw-r--r--usrp/host/lib/legacy/usrp_dbid.dat (renamed from usrp/host/lib/usrp_dbid.dat)0
-rw-r--r--usrp/host/lib/legacy/usrp_local_sighandler.cc (renamed from usrp/host/lib/usrp_local_sighandler.cc)0
-rw-r--r--usrp/host/lib/legacy/usrp_local_sighandler.h (renamed from usrp/host/lib/usrp_local_sighandler.h)0
-rw-r--r--usrp/host/lib/legacy/usrp_prims.cc (renamed from usrp/host/lib/usrp_prims.cc)0
-rw-r--r--usrp/host/lib/legacy/usrp_prims.h (renamed from usrp/host/lib/usrp_prims.h)0
-rw-r--r--usrp/host/lib/legacy/usrp_slots.h (renamed from usrp/host/lib/usrp_slots.h)0
-rw-r--r--usrp/host/lib/legacy/usrp_standard.cc (renamed from usrp/host/lib/usrp_standard.cc)0
-rw-r--r--usrp/host/lib/legacy/usrp_standard.h (renamed from usrp/host/lib/usrp_standard.h)0
-rw-r--r--usrp/host/swig/Makefile.am2
156 files changed, 8724 insertions, 707 deletions
diff --git a/Makefile.common b/Makefile.common
index 35ff20395..3906542b5 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -73,14 +73,19 @@ GNURADIO_CORE_LA = $(top_builddir)/gnuradio-core/src/lib/libgnuradio-core.la
GNURADIO_I = $(top_srcdir)/gnuradio-core/src/lib/swig/gnuradio.i
# How to link in the USRP library from inside the tree
-USRP_INCLUDES = -I$(top_srcdir)/usrp/host/lib \
+USRP_INCLUDES = -I$(top_srcdir)/usrp/host/lib/legacy \
+ -I$(top_srcdir)/usrp/host/lib/inband \
-I$(top_srcdir)/usrp/firmware/include
-USRP_LA = $(top_builddir)/usrp/host/lib/libusrp.la
+USRP_LA = $(top_builddir)/usrp/host/lib/legacy/libusrp.la
# How to link the PMT library from inside the tree
PMT_INCLUDES = -I$(top_srcdir)/pmt/src/lib
PMT_LA = $(top_builddir)/pmt/src/lib/libpmt.la
+# How to link the mblock library from inside the tree
+MBLOCK_INCLUDES = -I$(top_srcdir)/mblock/src/lib
+MBLOCK_LA = $(top_builddir)/mblock/src/lib/libmblock.la
+
# This used to be set in configure.ac but is now defined here for all
# Makefiles when this fragment is included.
STD_DEFINES_AND_INCLUDES=$(DEFINES) $(OMNITHREAD_INCLUDES) $(GNURADIO_INCLUDES) $(BOOST_CFLAGS)
@@ -88,3 +93,6 @@ STD_DEFINES_AND_INCLUDES=$(DEFINES) $(OMNITHREAD_INCLUDES) $(GNURADIO_INCLUDES)
# Fix for BSD make not defining $(RM). We define it now in configure.ac
# using AM_PATH_PROG, but now here have to add a -f to be like GNU make
RM=$(RM_PROG) -f
+
+RUN_GUILE = GUILE_LOAD_PATH="@abs_top_srcdir@/pmt/src/scheme:@abs_top_srcdir@/mblock/src/scheme" @GUILE@ -e main -s
+COMPILE_MBH = $(RUN_GUILE) $(top_srcdir)/mblock/src/scheme/gnuradio/compile-mbh.scm
diff --git a/config/grc_mblock.m4 b/config/grc_mblock.m4
index 6e4bc4afe..d5020a65b 100644
--- a/config/grc_mblock.m4
+++ b/config/grc_mblock.m4
@@ -24,7 +24,9 @@ AC_DEFUN([GRC_MBLOCK],[
mblock/Makefile \
mblock/doc/Makefile \
mblock/src/Makefile \
- mblock/src/lib/Makefile
+ mblock/src/lib/Makefile \
+ mblock/src/scheme/Makefile \
+ mblock/src/scheme/gnuradio/Makefile \
])
passed=yes
@@ -48,6 +50,12 @@ AC_DEFUN([GRC_MBLOCK],[
fi
done
+ AC_PATH_PROG(GUILE,guile)
+ if test "$GUILE" = "" ; then
+ AC_MSG_RESULT([Component mblock requires guile, which was not found.])
+ passed=no
+ fi
+
GRC_BUILD_CONDITIONAL([mblock],[
dnl run_tests is created from run_tests.in. Make it executable.
dnl AC_CONFIG_COMMANDS([run_tests_mblock], [chmod +x mblock/src/python/run_tests])
diff --git a/config/grc_pmt.m4 b/config/grc_pmt.m4
index 57d912bfd..5e2487190 100644
--- a/config/grc_pmt.m4
+++ b/config/grc_pmt.m4
@@ -24,10 +24,18 @@ AC_DEFUN([GRC_PMT],[
pmt/Makefile \
pmt/doc/Makefile \
pmt/src/Makefile \
- pmt/src/lib/Makefile
+ pmt/src/lib/Makefile \
+ pmt/src/scheme/Makefile \
+ pmt/src/scheme/gnuradio/Makefile \
])
passed=yes
+ AC_PATH_PROG(GUILE,guile)
+ if test "$GUILE" = "" ; then
+ AC_MSG_RESULT([Component pmt requires guile, which was not found.])
+ passed=no
+ fi
+
GRC_BUILD_CONDITIONAL([pmt],[
dnl run_tests is created from run_tests.in. Make it executable.
dnl AC_CONFIG_COMMANDS([run_tests_pmt], [chmod +x pmt/src/python/run_tests])
diff --git a/config/grc_usrp.m4 b/config/grc_usrp.m4
index a7c0cf138..e0fe60f47 100644
--- a/config/grc_usrp.m4
+++ b/config/grc_usrp.m4
@@ -30,7 +30,9 @@ AC_DEFUN([GRC_USRP],[
usrp/host/Makefile \
usrp/host/misc/Makefile \
usrp/host/lib/Makefile \
- usrp/host/lib/std_paths.h \
+ usrp/host/lib/inband/Makefile \
+ usrp/host/lib/legacy/Makefile \
+ usrp/host/lib/legacy/std_paths.h \
usrp/host/swig/Makefile \
usrp/host/apps/Makefile \
usrp/firmware/Makefile \
@@ -54,6 +56,16 @@ AC_DEFUN([GRC_USRP],[
AC_CHECK_FUNCS([sigaction snprintf])
passed=yes
+ # Don't do usrp if mblock skipped
+ # There *has* to be a better way to check if a value is in a string
+ for dir in $skipped_dirs
+ do
+ if test "$dir" = "mblock"; then
+ AC_MSG_RESULT([Component usrp requires mblock, which is not being built.])
+ passed=no
+ fi
+ done
+
USRP_LIBUSB([],[passed=no;AC_MSG_RESULT([Unable to configure USB dependency.])])
USRP_SET_FUSB_TECHNIQUE([],[passed=no;AC_MSG_RESULT([Unable to set fast USB technique.])])
USRP_SDCC([2.4.0],[],[passed=no;AC_MSG_RESULT([Unable to find firmware compiler.])])
diff --git a/configure.ac b/configure.ac
index 418c78c01..22aaa2a01 100644
--- a/configure.ac
+++ b/configure.ac
@@ -114,7 +114,7 @@ AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(fcntl.h limits.h strings.h time.h sys/ioctl.h sys/time.h unistd.h)
AC_CHECK_HEADERS(linux/ppdev.h sys/mman.h sys/select.h sys/types.h)
-AC_CHECK_HEADERS(sys/resource.h stdint.h sched.h signal.h)
+AC_CHECK_HEADERS(sys/resource.h stdint.h sched.h signal.h sys/syscall.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -131,6 +131,7 @@ AC_FUNC_VPRINTF
AC_CHECK_FUNCS([mmap select socket strcspn strerror strspn getpagesize sysconf])
AC_CHECK_FUNCS([snprintf gettimeofday nanosleep sched_setscheduler])
AC_CHECK_FUNCS([modf sqrt sigaction sigprocmask])
+AC_CHECK_FUNCS([sched_setaffinity])
AC_CHECK_LIB(m, sincos, [AC_DEFINE([HAVE_SINCOS],[1],[Define to 1 if your system has `sincos'.])])
AC_CHECK_LIB(m, sincosf,[AC_DEFINE([HAVE_SINCOSF],[1],[Define to 1 if your system has `sincosf'.])])
@@ -198,6 +199,8 @@ AC_ARG_ENABLE(
build_dirs="config"
GRC_OMNITHREAD dnl must come before gnuradio-core and mblock
GRC_GNURADIO_CORE
+GRC_PMT
+GRC_MBLOCK dnl this must come after GRC_PMT
GRC_USRP
GRC_GR_USRP dnl this must come after GRC_USRP
GRC_GR_AUDIO_ALSA
@@ -216,8 +219,6 @@ GRC_GR_TRELLIS
GRC_GR_VIDEO_SDL
GRC_GR_QTGUI
GRC_GR_WXGUI
-GRC_PMT
-GRC_MBLOCK dnl this must come after GRC_PMT
GRC_GR_SOUNDER dnl this must come after GRC_USRP
GRC_GNURADIO_EXAMPLES dnl must come last
diff --git a/gnuradio-core/src/python/bin/Makefile.am b/gnuradio-core/src/python/bin/Makefile.am
index 296132ec7..d4df51273 100644
--- a/gnuradio-core/src/python/bin/Makefile.am
+++ b/gnuradio-core/src/python/bin/Makefile.am
@@ -24,7 +24,7 @@ include $(top_srcdir)/Makefile.common
EXTRA_DIST = microtune.py
-bin_SCRIPTS = \
+noinst_SCRIPTS = \
microtune.py
CLEANFILES = *.pyc
diff --git a/mblock/README b/mblock/README
index ca91edfaa..130073afe 100644
--- a/mblock/README
+++ b/mblock/README
@@ -1,5 +1,5 @@
#
-# Copyright 2006 Free Software Foundation, Inc.
+# Copyright 2006,2007 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -20,3 +20,5 @@
#
The "Message block" implementation, a work in progress...
+
+http://gnuradio.org/trac/wiki/MessageBlocks
diff --git a/mblock/src/Makefile.am b/mblock/src/Makefile.am
index bcbab2455..c6c2fcc75 100644
--- a/mblock/src/Makefile.am
+++ b/mblock/src/Makefile.am
@@ -19,4 +19,4 @@
# Boston, MA 02110-1301, USA.
#
-SUBDIRS = lib
+SUBDIRS = lib scheme
diff --git a/mblock/src/lib/Makefile.am b/mblock/src/lib/Makefile.am
index 6273e16d2..604f97246 100644
--- a/mblock/src/lib/Makefile.am
+++ b/mblock/src/lib/Makefile.am
@@ -28,28 +28,41 @@ TESTS = test_mblock
lib_LTLIBRARIES = libmblock.la libmblock-qa.la
EXTRA_DIST = \
- README.locking
+ README.locking \
+ qa_bitset.mbh
+BUILT_SOURCES = \
+ qa_bitset_mbh.cc
+
+qa_bitset_mbh.cc : qa_bitset.mbh
+ $(COMPILE_MBH) qa_bitset.mbh qa_bitset_mbh.cc
+
# These are the source files that go into the mblock shared library
libmblock_la_SOURCES = \
+ mb_class_registry.cc \
mb_connection.cc \
mb_endpoint.cc \
mb_exception.cc \
+ mb_gettid.cc \
mb_mblock.cc \
mb_mblock_impl.cc \
mb_message.cc \
mb_msg_accepter.cc \
+ mb_msg_accepter_msgq.cc \
mb_msg_accepter_smp.cc \
mb_msg_queue.cc \
mb_port.cc \
mb_port_simple.cc \
mb_protocol_class.cc \
mb_runtime.cc \
+ mb_runtime_base.cc \
mb_runtime_nop.cc \
- mb_runtime_placeholder.cc \
- mb_runtime_thread_per_mblock.cc \
- mb_util.cc
+ mb_runtime_thread_per_block.cc \
+ mb_time.cc \
+ mb_timer_queue.cc \
+ mb_util.cc \
+ mb_worker.cc
# magic flags
@@ -62,19 +75,20 @@ libmblock_la_LIBADD = \
-lstdc++
include_HEADERS = \
+ mb_class_registry.h \
mb_common.h \
mb_exception.h \
+ mb_gettid.h \
mb_mblock.h \
mb_message.h \
mb_msg_accepter.h \
+ mb_msg_accepter_msgq.h \
mb_msg_queue.h \
mb_port.h \
mb_port_simple.h \
mb_protocol_class.h \
mb_runtime.h \
- mb_runtime_nop.h \
- mb_runtime_placeholder.h \
- mb_runtime_thread_per_mblock.h \
+ mb_time.h \
mb_util.h
@@ -83,18 +97,30 @@ noinst_HEADERS = \
mb_endpoint.h \
mb_mblock_impl.h \
mb_msg_accepter_smp.h \
+ mb_runtime_base.h \
+ mb_runtime_nop.h \
+ mb_runtime_thread_per_block.h \
+ mb_timer_queue.h \
+ mb_worker.h \
mbi_runtime_lock.h \
qa_mblock.h \
qa_mblock_prims.h \
- qa_mblock_send.h
+ qa_mblock_send.h \
+ qa_mblock_sys.h \
+ qa_timeouts.h
# Build the qa code into its own library
libmblock_qa_la_SOURCES = \
+ qa_bitset.cc \
+ qa_bitset_mbh.cc \
+ qa_disconnect.cc \
qa_mblock.cc \
qa_mblock_prims.cc \
- qa_mblock_send.cc
+ qa_mblock_send.cc \
+ qa_mblock_sys.cc \
+ qa_timeouts.cc
# magic flags
@@ -107,9 +133,14 @@ libmblock_qa_la_LIBADD = \
-lstdc++
-noinst_PROGRAMS = test_mblock
+noinst_PROGRAMS = \
+ test_mblock \
+ benchmark_send
test_mblock_SOURCES = test_mblock.cc
test_mblock_LDADD = libmblock-qa.la
+benchmark_send_SOURCES = benchmark_send.cc
+benchmark_send_LDADD = libmblock-qa.la
+
CLEANFILES = $(BUILT_SOURCES) *.pyc
diff --git a/mblock/src/lib/mb_runtime_placeholder.h b/mblock/src/lib/benchmark_send.cc
index b55d39f94..c9ebe57c3 100644
--- a/mblock/src/lib/mb_runtime_placeholder.h
+++ b/mblock/src/lib/benchmark_send.cc
@@ -18,33 +18,28 @@
* 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_PLACEHOLDER_H
-#define INCLUDED_MB_RUNTIME_PLACEHOLDER_H
#include <mb_runtime.h>
+#include <iostream>
-/*!
- * \brief Concrete runtime that serves as a placeholder until the real
- * runtime is known.
- *
- * The singleton instance of this class is installed in the d_runtime
- * instance variable of each mb_mblock_impl at construction time.
- * Having a valid instance of runtime removes the "pre runtime::run"
- * corner case, and allows us to lock and unlock the big runtime lock
- * even though there's no "real runtime" yet.
- */
-class mb_runtime_placeholder : public mb_runtime
+int
+main(int argc, char **argv)
{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ long nmsgs = 1000000;
+ long batch_size = 100;
-public:
- mb_runtime_placeholder();
- ~mb_runtime_placeholder();
+ pmt_t arg = pmt_list2(pmt_from_long(nmsgs), // # of messages to send through pipe
+ pmt_from_long(batch_size));
- //! throws mbe_not_implemented
- bool run(mb_mblock_sptr top);
+ rt->run("top", "qa_bitset_top", arg, &result);
- //! Return the placeholder singleton
- static mb_runtime *singleton();
-};
+ if (!pmt_equal(PMT_T, result)){
+ std::cerr << "benchmark_send: incorrect result";
+ return 1;
+ }
-#endif /* INCLUDED_MB_RUNTIME_PLACEHOLDER_H */
+ return 0;
+}
diff --git a/mblock/src/lib/getres.cc b/mblock/src/lib/getres.cc
new file mode 100644
index 000000000..c05ba792a
--- /dev/null
+++ b/mblock/src/lib/getres.cc
@@ -0,0 +1,32 @@
+#include <time.h>
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+ bool ok = true;
+ struct timespec ts;
+ int r;
+
+ r = clock_getres(CLOCK_REALTIME, &ts);
+ if (r != 0){
+ perror("clock_getres(CLOCK_REALTIME, ...)");
+ ok = false;
+ }
+ else
+ printf("clock_getres(CLOCK_REALTIME, ...) => %11.9f\n",
+ (double) ts.tv_sec + ts.tv_nsec * 1e-9);
+
+
+ r = clock_getres(CLOCK_MONOTONIC, &ts);
+ if (r != 0){
+ perror("clock_getres(CLOCK_MONOTONIC, ...");
+ ok = false;
+ }
+ else
+ printf("clock_getres(CLOCK_MONOTONIC, ...) => %11.9f\n",
+ (double) ts.tv_sec + ts.tv_nsec * 1e-9);
+
+
+ return ok == true ? 0 : 1;
+}
diff --git a/mblock/src/lib/mb_runtime_thread_per_mblock.cc b/mblock/src/lib/mb_class_registry.cc
index 925dcdc45..9eee93618 100644
--- a/mblock/src/lib/mb_runtime_thread_per_mblock.cc
+++ b/mblock/src/lib/mb_class_registry.cc
@@ -22,44 +22,26 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-#include <mb_runtime_thread_per_mblock.h>
-#include <mb_mblock.h>
-#include <mb_mblock_impl.h>
+#include <mb_class_registry.h>
+#include <map>
+static std::map<std::string, mb_mblock_maker_t> s_registry;
-mb_runtime_thread_per_mblock::mb_runtime_thread_per_mblock()
-{
- // nop for now
-}
-
-mb_runtime_thread_per_mblock::~mb_runtime_thread_per_mblock()
+bool
+mb_class_registry::register_maker(const std::string &name, mb_mblock_maker_t maker)
{
- // nop for now
+ s_registry[name] = maker;
+ return true;
}
bool
-mb_runtime_thread_per_mblock::run(mb_mblock_sptr top)
+mb_class_registry::lookup_maker(const std::string &name, mb_mblock_maker_t *maker)
{
- class initial_visitor : public mb_visitor
- {
- mb_runtime *d_rt;
-
- public:
- initial_visitor(mb_runtime *rt) : d_rt(rt) {}
- bool operator()(mb_mblock *mblock, const std::string &path)
- {
- mblock->impl()->set_runtime(d_rt);
- mblock->set_instance_name(path);
- mblock->init_fsm();
- return true;
- }
- };
-
- initial_visitor visitor(this);
-
- d_top = top; // remember top of tree
-
- d_top->walk_tree(&visitor);
+ if (s_registry.count(name) == 0){ // not registered
+ *maker = (mb_mblock_maker_t) 0;
+ return false;
+ }
+ *maker = s_registry[name];
return true;
}
diff --git a/mblock/src/lib/mb_class_registry.h b/mblock/src/lib/mb_class_registry.h
new file mode 100644
index 000000000..b6e63d38b
--- /dev/null
+++ b/mblock/src/lib/mb_class_registry.h
@@ -0,0 +1,51 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_MB_CLASS_REGISTRY_H
+#define INCLUDED_MB_CLASS_REGISTRY_H
+
+#include <mb_common.h>
+
+//! conceptually, pointer to constructor
+typedef mb_mblock_sptr (*mb_mblock_maker_t)(mb_runtime *runtime,
+ const std::string &instance_name,
+ pmt_t user_arg);
+
+/*
+ * \brief Maintain mapping between mblock class_name and factory (maker)
+ */
+class mb_class_registry : public boost::noncopyable {
+public:
+ static bool register_maker(const std::string &name, mb_mblock_maker_t maker);
+ static bool lookup_maker(const std::string &name, mb_mblock_maker_t *maker);
+};
+
+template<class mblock>
+mb_mblock_sptr mb_mblock_maker(mb_runtime *runtime,
+ const std::string &instance_name,
+ pmt_t user_arg)
+{
+ return mb_mblock_sptr(new mblock(runtime, instance_name, user_arg));
+}
+
+#define REGISTER_MBLOCK_CLASS(name) \
+ bool __RBC__ ## name = mb_class_registry::register_maker(#name, &mb_mblock_maker<name>)
+
+#endif /* INCLUDED_MB_CLASS_REGISTRY_H */
diff --git a/mblock/src/lib/mb_exception.cc b/mblock/src/lib/mb_exception.cc
index 4d4ca70b1..23dfbd9fe 100644
--- a/mblock/src/lib/mb_exception.cc
+++ b/mblock/src/lib/mb_exception.cc
@@ -38,6 +38,11 @@ mbe_not_implemented::mbe_not_implemented(mb_mblock *mb, const std::string &msg)
{
}
+mbe_no_such_class::mbe_no_such_class(mb_mblock *mb, const std::string &class_name)
+ : mbe_base(mb, "No such class: " + class_name)
+{
+}
+
mbe_no_such_component::mbe_no_such_component(mb_mblock *mb, const std::string &component_name)
: mbe_base(mb, "No such component: " + component_name)
{
@@ -85,3 +90,17 @@ mbe_invalid_port_type::mbe_invalid_port_type(mb_mblock *mb,
: mbe_base(mb, "Invalid port type for connection: " + mb_util::join_names(comp_name, port_name))
{
}
+
+mbe_mblock_failed::mbe_mblock_failed(mb_mblock *mb,
+ const std::string &msg)
+ : mbe_base(mb, "Message block failed: " + msg)
+{
+}
+
+mbe_terminate::mbe_terminate()
+{
+}
+
+mbe_exit::mbe_exit()
+{
+}
diff --git a/mblock/src/lib/mb_exception.h b/mblock/src/lib/mb_exception.h
index 40abd1c96..183f7089c 100644
--- a/mblock/src/lib/mb_exception.h
+++ b/mblock/src/lib/mb_exception.h
@@ -38,6 +38,11 @@ public:
mbe_not_implemented(mb_mblock *mb, const std::string &msg);
};
+class mbe_no_such_class : public mbe_base
+{
+public:
+ mbe_no_such_class(mb_mblock *, const std::string &class_name);
+};
class mbe_no_such_component : public mbe_base
{
@@ -57,6 +62,7 @@ public:
mbe_no_such_port(mb_mblock *, const std::string &port_name);
};
+
class mbe_duplicate_port : public mbe_base
{
public:
@@ -87,6 +93,26 @@ public:
const std::string &port_name);
};
+class mbe_mblock_failed : public mbe_base
+{
+public:
+ mbe_mblock_failed(mb_mblock *, const std::string &msg);
+};
+
+// not derived from mbe_base to simplify try/catch
+class mbe_terminate
+{
+public:
+ mbe_terminate();
+};
+
+// not derived from mbe_base to simplify try/catch
+class mbe_exit
+{
+public:
+ mbe_exit();
+};
+
#endif /* INCLUDED_MB_EXCEPTION_H */
diff --git a/mblock/src/lib/mb_gettid.cc b/mblock/src/lib/mb_gettid.cc
new file mode 100644
index 000000000..4f6b3a567
--- /dev/null
+++ b/mblock/src/lib/mb_gettid.cc
@@ -0,0 +1,53 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <mb_gettid.h>
+
+#define NEED_STUB
+
+#if defined(HAVE_SYS_SYSCALL_H) && defined(HAVE_UNISTD_H)
+
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#if defined(SYS_gettid)
+#undef NEED_STUB
+
+int mb_gettid()
+{
+ return syscall(SYS_gettid);
+}
+
+#endif
+#endif
+
+#if defined(NEED_STUB)
+
+int
+mb_gettid()
+{
+ return 0;
+}
+
+#endif
diff --git a/mblock/src/lib/mb_runtime_thread_per_mblock.h b/mblock/src/lib/mb_gettid.h
index cef756ecd..d06276f56 100644
--- a/mblock/src/lib/mb_runtime_thread_per_mblock.h
+++ b/mblock/src/lib/mb_gettid.h
@@ -18,23 +18,9 @@
* 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_THREAD_PER_MBLOCK_H
-#define INCLUDED_MB_RUNTIME_THREAD_PER_MBLOCK_H
-
-#include <mb_runtime.h>
/*!
- * \brief Concrete runtime that uses a single thread for all work.
+ * \brief Return Linux taskid, or 0 if not available
*/
-class mb_runtime_thread_per_mblock : public mb_runtime
-{
- mb_mblock_sptr d_top; // top mblock
-
-public:
- mb_runtime_thread_per_mblock();
- ~mb_runtime_thread_per_mblock();
-
- bool run(mb_mblock_sptr top);
-};
+int mb_gettid();
-#endif /* INCLUDED_MB_RUNTIME_THREAD_PER_MBLOCK_H */
diff --git a/mblock/src/lib/mb_mblock.cc b/mblock/src/lib/mb_mblock.cc
index 9b8658f21..afff1a928 100644
--- a/mblock/src/lib/mb_mblock.cc
+++ b/mblock/src/lib/mb_mblock.cc
@@ -25,29 +25,36 @@
#include <mb_mblock.h>
#include <mb_mblock_impl.h>
+#include <mb_runtime.h>
+#include <mb_exception.h>
+#include <iostream>
+static pmt_t s_sys_port = pmt_intern("%sys-port");
+static pmt_t s_halt = pmt_intern("%halt");
+
mb_visitor::~mb_visitor()
{
// nop base case for virtual destructor.
}
-mb_mblock::mb_mblock()
- : d_impl(mb_mblock_impl_sptr(new mb_mblock_impl(this)))
+mb_mblock::mb_mblock(mb_runtime *runtime,
+ const std::string &instance_name,
+ pmt_t user_arg)
+ : d_impl(mb_mblock_impl_sptr(
+ new mb_mblock_impl(dynamic_cast<mb_runtime_base*>(runtime),
+ this, instance_name)))
{
}
mb_mblock::~mb_mblock()
{
- disconnect_all();
-
- // FIXME more?
}
void
-mb_mblock::init_fsm()
+mb_mblock::initial_transition()
{
// default implementation does nothing
}
@@ -58,6 +65,36 @@ mb_mblock::handle_message(mb_message_sptr msg)
// default implementation does nothing
}
+
+void
+mb_mblock::main_loop()
+{
+ while (1){
+ mb_message_sptr msg;
+ try {
+ while (1){
+ msg = impl()->msgq().get_highest_pri_msg();
+
+ // check for %halt from %sys-port
+ if (pmt_eq(msg->port_id(), s_sys_port) && pmt_eq(msg->signal(), s_halt))
+ exit();
+
+ handle_message(msg);
+ }
+ }
+ catch (pmt_exception e){
+ std::cerr << "\nmb_mblock::main_loop: ignored pmt_exception: "
+ << e.what()
+ << "\nin mblock instance \"" << instance_name()
+ << "\" while handling message:"
+ << "\n port_id = " << msg->port_id()
+ << "\n signal = " << msg->signal()
+ << "\n data = " << msg->data()
+ << "\n metatdata = " << msg->metadata() << std::endl;
+ }
+ }
+}
+
////////////////////////////////////////////////////////////////////////
// Forward other methods to implementation class //
////////////////////////////////////////////////////////////////////////
@@ -74,9 +111,11 @@ mb_mblock::define_port(const std::string &port_name_string,
void
mb_mblock::define_component(const std::string &component_name,
- mb_mblock_sptr component)
+ const std::string &class_name,
+ pmt_t user_arg)
+
{
- d_impl->define_component(component_name, component);
+ d_impl->define_component(component_name, class_name, user_arg);
}
void
@@ -97,7 +136,7 @@ mb_mblock::disconnect(const std::string &comp_name1, const std::string &port_nam
}
void
-mb_mblock::disconnect_component(const std::string component_name)
+mb_mblock::disconnect_component(const std::string &component_name)
{
d_impl->disconnect_component(component_name);
}
@@ -115,9 +154,9 @@ mb_mblock::nconnections() const
}
bool
-mb_mblock::walk_tree(mb_visitor *visitor, const std::string &path)
+mb_mblock::walk_tree(mb_visitor *visitor)
{
- return d_impl->walk_tree(visitor, path);
+ return d_impl->walk_tree(visitor);
}
std::string
@@ -127,7 +166,7 @@ mb_mblock::instance_name() const
}
void
-mb_mblock::set_instance_name(const std::string name)
+mb_mblock::set_instance_name(const std::string &name)
{
d_impl->set_instance_name(name);
}
@@ -139,7 +178,7 @@ mb_mblock::class_name() const
}
void
-mb_mblock::set_class_name(const std::string name)
+mb_mblock::set_class_name(const std::string &name)
{
d_impl->set_class_name(name);
}
@@ -149,3 +188,42 @@ mb_mblock::parent() const
{
return d_impl->mblock_parent();
}
+
+void
+mb_mblock::exit()
+{
+ throw mbe_exit(); // adios...
+}
+
+void
+mb_mblock::shutdown_all(pmt_t result)
+{
+ d_impl->runtime()->request_shutdown(result);
+}
+
+pmt_t
+mb_mblock::schedule_one_shot_timeout(const mb_time &abs_time, pmt_t user_data)
+{
+ mb_msg_accepter_sptr accepter = impl()->make_accepter(s_sys_port);
+ return d_impl->runtime()->schedule_one_shot_timeout(abs_time, user_data,
+ accepter);
+}
+
+pmt_t
+mb_mblock::schedule_periodic_timeout(const mb_time &first_abs_time,
+ const mb_time &delta_time,
+ pmt_t user_data)
+{
+ mb_msg_accepter_sptr accepter = impl()->make_accepter(s_sys_port);
+ return d_impl->runtime()->schedule_periodic_timeout(first_abs_time,
+ delta_time,
+ user_data,
+ accepter);
+}
+
+void
+mb_mblock::cancel_timeout(pmt_t handle)
+{
+ d_impl->runtime()->cancel_timeout(handle);
+}
+
diff --git a/mblock/src/lib/mb_mblock.h b/mblock/src/lib/mb_mblock.h
index 594920f91..6d471c3db 100644
--- a/mblock/src/lib/mb_mblock.h
+++ b/mblock/src/lib/mb_mblock.h
@@ -24,6 +24,7 @@
#include <mb_common.h>
#include <mb_message.h>
#include <mb_port.h>
+#include <mb_time.h>
/*!
@@ -34,7 +35,7 @@ class mb_visitor
{
public:
virtual ~mb_visitor();
- virtual bool operator()(mb_mblock *mblock, const std::string &path) = 0;
+ virtual bool operator()(mb_mblock *mblock) = 0;
};
// ----------------------------------------------------------------------
@@ -52,6 +53,7 @@ private:
friend class mb_runtime;
friend class mb_mblock_impl;
+ friend class mb_worker;
protected:
/*!
@@ -59,22 +61,29 @@ protected:
*
* 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.
+ * The top level mblock's constructor is run. That constructor
+ * (a) registers all of its ports using define_port, (b) registers any
+ * subcomponents it may have via the define_component method, and
+ * then (c) issues connect calls to wire its subcomponents together.
+ *
+ * \param runtime the runtime associated with this mblock
+ * \param instance_name specify the name of this instance
+ * (for debugging, NUMA mapping, etc)
+ * \param user_arg argument passed by user to constructor
+ * (ignored by the mb_mblock base class)
*/
- mb_mblock();
+ mb_mblock(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
public:
/*!
* \brief Called by the runtime system to execute the initial
* transition of the finite state machine.
*
- * Override this to initialize your finite state machine.
+ * This method is called by the runtime after all blocks are
+ * constructed and before the first message is delivered. Override
+ * this to initialize your finite state machine.
*/
- virtual void init_fsm();
+ virtual void initial_transition();
protected:
/*!
@@ -113,11 +122,13 @@ protected:
* 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.
+ * \param class_name The class of the instance that is to be created.
+ * \param user_arg The argument to pass to the constructor of the component.
*/
void
define_component(const std::string &component_name,
- mb_mblock_sptr component);
+ const std::string &class_name,
+ pmt_t user_arg = PMT_NIL);
/*!
* \brief connect endpoint_1 to endpoint_2
@@ -160,7 +171,7 @@ protected:
* \param component_name component to disconnect
*/
void
- disconnect_component(const std::string component_name);
+ disconnect_component(const std::string &component_name);
/*!
* \brief disconnect all connections to all components
@@ -175,8 +186,47 @@ protected:
nconnections() const;
//! Set the class name
- void set_class_name(const std::string name);
+ void set_class_name(const std::string &name);
+
+ /*!
+ * \brief Tell runtime that we are done.
+ *
+ * This method does not return.
+ */
+ void exit();
+ /*!
+ * \brief Ask runtime to execute the shutdown procedure for all blocks.
+ *
+ * \param result sets value of \p result output argument of runtime->run(...)
+ *
+ * The runtime first sends a maximum priority %shutdown message to
+ * all blocks. All blocks should handle the %shutdown message,
+ * perform whatever clean up is required, and call this->exit();
+ *
+ * After a period of time (~100ms), any blocks which haven't yet
+ * called this->exit() are sent a maximum priority %halt message.
+ * %halt is detected in main_loop, and this->exit() is called.
+ *
+ * After an additional period of time (~100ms), any blocks which
+ * still haven't yet called this->exit() are sent a SIG<FOO> (TBD)
+ * signal, which will blow them out of any blocking system calls and
+ * raise an mbe_terminate exception. The default top-level
+ * runtime-provided exception handler will call this->exit() to
+ * finish the process.
+ *
+ * runtime->run(...) returns when all blocks have called exit.
+ */
+ void shutdown_all(pmt_t result);
+
+ /*!
+ * \brief main event dispatching loop
+ *
+ * Although it is possible to override this, the default implementation
+ * should work for virtually all cases.
+ */
+ virtual void main_loop();
+
public:
virtual ~mb_mblock();
@@ -187,18 +237,74 @@ public:
std::string class_name() const;
//! Set the instance name of this block.
- void set_instance_name(const std::string name);
+ void set_instance_name(const std::string &name);
//! Return the parent of this mblock, or 0 if we're the top-level block.
mb_mblock *parent() const;
/*!
+ * \brief Schedule a "one shot" timeout.
+ *
+ * \param abs_time the absolute time at which the timeout should fire
+ * \param user_data the data passed in the %timeout message.
+ *
+ * When the timeout fires, a message will be sent to the mblock.
+ *
+ * The message will have port_id = %sys-port, signal = %timeout,
+ * data = user_data, metadata = the handle returned from
+ * schedule_one_shot_timeout, pri = MB_PRI_BEST.
+ *
+ * \returns a handle that can be used in cancel_timeout, and is passed
+ * as the metadata field of the generated %timeout message.
+ *
+ * To cancel a pending timeout, call cancel_timeout.
+ */
+ pmt_t
+ schedule_one_shot_timeout(const mb_time &abs_time, pmt_t user_data);
+
+ /*!
+ * \brief Schedule a periodic timeout.
+ *
+ * \param first_abs_time The absolute time at which the first timeout should fire.
+ * \param delta_time The relative delay between the first and successive timeouts.
+ * \param user_data the data passed in the %timeout message.
+ *
+ * When the timeout fires, a message will be sent to the mblock, and a
+ * new timeout will be scheduled for previous absolute time + delta_time.
+ *
+ * The message will have port_id = %sys-port, signal = %timeout,
+ * data = user_data, metadata = the handle returned from
+ * schedule_one_shot_timeout, pri = MB_PRI_BEST.
+ *
+ * \returns a handle that can be used in cancel_timeout, and is passed
+ * as the metadata field of the generated %timeout message.
+ *
+ * To cancel a pending timeout, call cancel_timeout.
+ */
+ pmt_t
+ schedule_periodic_timeout(const mb_time &first_abs_time,
+ const mb_time &delta_time,
+ pmt_t user_data);
+
+ /*!
+ * \brief Attempt to cancel a pending timeout.
+ *
+ * Note that this only stops a future timeout from firing. It is
+ * possible that a timeout may have already fired and enqueued a
+ * %timeout message, but that that message has not yet been seen by
+ * handle_message.
+ *
+ * \param handle returned from schedule_one_shot_timeout or schedule_periodic_timeout.
+ */
+ void cancel_timeout(pmt_t handle);
+
+ /*!
* \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="top");
+ walk_tree(mb_visitor *visitor);
//! \implementation
diff --git a/mblock/src/lib/mb_mblock_impl.cc b/mblock/src/lib/mb_mblock_impl.cc
index 1a9e50146..02cbb548d 100644
--- a/mblock/src/lib/mb_mblock_impl.cc
+++ b/mblock/src/lib/mb_mblock_impl.cc
@@ -30,8 +30,8 @@
#include <mb_exception.h>
#include <mb_util.h>
#include <mb_msg_accepter_smp.h>
-#include <mb_runtime_placeholder.h>
#include <mbi_runtime_lock.h>
+#include <iostream>
static pmt_t s_self = pmt_intern("self");
@@ -52,9 +52,10 @@ mb_mblock_impl::comp_is_defined(const std::string &name)
////////////////////////////////////////////////////////////////////////
-mb_mblock_impl::mb_mblock_impl(mb_mblock *mb)
- : d_mb(mb), d_mb_parent(0), d_runtime(mb_runtime_placeholder::singleton()),
- d_instance_name("<unknown>"), d_class_name("mblock")
+mb_mblock_impl::mb_mblock_impl(mb_runtime_base *runtime, mb_mblock *mb,
+ const std::string &instance_name)
+ : d_runtime(runtime), d_mb(mb), d_mb_parent(0),
+ d_instance_name(instance_name), d_class_name("mblock")
{
}
@@ -85,15 +86,28 @@ mb_mblock_impl::define_port(const std::string &port_name,
void
mb_mblock_impl::define_component(const std::string &name,
- mb_mblock_sptr component)
+ const std::string &class_name,
+ pmt_t user_arg)
{
- mbi_runtime_lock l(this);
+ {
+ mbi_runtime_lock l(this);
+
+ if (comp_is_defined(name)) // check for duplicate name
+ throw mbe_duplicate_component(d_mb, name);
+ }
- if (comp_is_defined(name)) // check for duplicate name
- throw mbe_duplicate_component(d_mb, name);
+ // We ask the runtime to create the component so that it can worry about
+ // mblock placement on a NUMA machine or on a distributed multicomputer
- component->d_impl->d_mb_parent = d_mb; // set component's parent link
- d_comp_map[name] = component;
+ mb_mblock_sptr component =
+ d_runtime->create_component(instance_name() + "/" + name,
+ class_name, user_arg);
+ {
+ mbi_runtime_lock l(this);
+
+ component->d_impl->d_mb_parent = d_mb; // set component's parent link
+ d_comp_map[name] = component;
+ }
}
void
@@ -125,6 +139,7 @@ mb_mblock_impl::disconnect(const std::string &comp_name1,
mbi_runtime_lock l(this);
d_conn_table.disconnect(comp_name1, port_name1, comp_name2, port_name2);
+ invalidate_all_port_caches();
}
void
@@ -133,6 +148,7 @@ mb_mblock_impl::disconnect_component(const std::string component_name)
mbi_runtime_lock l(this);
d_conn_table.disconnect_component(component_name);
+ invalidate_all_port_caches();
}
void
@@ -141,6 +157,7 @@ mb_mblock_impl::disconnect_all()
mbi_runtime_lock l(this);
d_conn_table.disconnect_all();
+ invalidate_all_port_caches();
}
int
@@ -220,26 +237,25 @@ mb_mblock_impl::endpoints_are_compatible(const mb_endpoint &ep0,
}
bool
-mb_mblock_impl::walk_tree(mb_visitor *visitor, const std::string &path)
+mb_mblock_impl::walk_tree(mb_visitor *visitor)
{
- if (!(*visitor)(d_mb, path))
+ if (!(*visitor)(d_mb))
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)))
+ if (!(it->second->walk_tree(visitor)))
return false;
return true;
}
mb_msg_accepter_sptr
-mb_mblock_impl::make_accepter(const std::string port_name)
+mb_mblock_impl::make_accepter(pmt_t port_name)
{
// FIXME this should probably use some kind of configurable factory
mb_msg_accepter *ma =
- new mb_msg_accepter_smp(d_mb->shared_from_this(),
- pmt_intern(port_name));
+ new mb_msg_accepter_smp(d_mb->shared_from_this(), port_name);
return mb_msg_accepter_sptr(ma);
}
@@ -281,3 +297,31 @@ mb_mblock_impl::set_class_name(const std::string &name)
d_class_name = name;
}
+/*
+ * This is the "Big Hammer" port cache invalidator.
+ * It invalidates _all_ of the port caches in the entire mblock tree.
+ * It's overkill, but was simple to code.
+ */
+void
+mb_mblock_impl::invalidate_all_port_caches()
+{
+ class invalidator : public mb_visitor
+ {
+ public:
+ bool operator()(mb_mblock *mblock)
+ {
+ mb_mblock_impl_sptr impl = mblock->impl();
+ mb_port_map_t::iterator it = impl->d_port_map.begin();
+ mb_port_map_t::iterator end = impl->d_port_map.end();
+ for (; it != end; ++it)
+ it->second->invalidate_cache();
+ return true;
+ }
+ };
+
+ invalidator visitor;
+
+ // Always true, except in early QA code
+ if (runtime()->top())
+ runtime()->top()->walk_tree(&visitor);
+}
diff --git a/mblock/src/lib/mb_mblock_impl.h b/mblock/src/lib/mb_mblock_impl.h
index fc0fa6943..03ad414ea 100644
--- a/mblock/src/lib/mb_mblock_impl.h
+++ b/mblock/src/lib/mb_mblock_impl.h
@@ -22,6 +22,7 @@
#define INCLUDED_MB_MBLOCK_IMPL_H
#include <mb_mblock.h>
+#include <mb_runtime_base.h>
#include <mb_connection.h>
#include <mb_msg_queue.h>
#include <list>
@@ -37,9 +38,9 @@ typedef std::map<std::string, mb_mblock_sptr> mb_comp_map_t;
*/
class mb_mblock_impl : boost::noncopyable
{
+ mb_runtime_base *d_runtime; // pointer to runtime
mb_mblock *d_mb; // pointer to our associated mblock
mb_mblock *d_mb_parent; // pointer to our parent
- mb_runtime *d_runtime; // pointer to runtime
std::string d_instance_name; // hierarchical name
std::string d_class_name; // name of this (derived) class
@@ -51,7 +52,8 @@ class mb_mblock_impl : boost::noncopyable
mb_msg_queue d_msgq; // incoming messages for us
public:
- mb_mblock_impl(mb_mblock *mb);
+ mb_mblock_impl(mb_runtime_base *runtime, mb_mblock *mb,
+ const std::string &instance_name);
~mb_mblock_impl();
/*!
@@ -79,11 +81,13 @@ public:
* 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.
+ * \param class_name The class of the instance that is to be created.
+ * \param user_arg The argument to pass to the constructor of the component.
*/
void
define_component(const std::string &component_name,
- mb_mblock_sptr component);
+ const std::string &class_name,
+ pmt_t user_arg);
/*!
* \brief connect endpoint_1 to endpoint_2
@@ -141,10 +145,10 @@ public:
nconnections();
bool
- walk_tree(mb_visitor *visitor, const std::string &path="");
+ walk_tree(mb_visitor *visitor);
mb_msg_accepter_sptr
- make_accepter(const std::string port_name);
+ make_accepter(pmt_t port_name);
mb_msg_queue &
msgq() { return d_msgq; }
@@ -183,10 +187,10 @@ public:
mb_mblock_sptr component(const std::string &comp_name);
//! Return the runtime instance
- mb_runtime *runtime() { return d_runtime; }
+ mb_runtime_base *runtime() { return d_runtime; }
//! Set the runtime instance
- void set_runtime(mb_runtime *runtime) { d_runtime = runtime; }
+ void set_runtime(mb_runtime_base *runtime) { d_runtime = runtime; }
/*
* Our implementation methods
@@ -210,6 +214,12 @@ private:
endpoints_are_compatible(const mb_endpoint &ep0,
const mb_endpoint &ep1);
+ /*!
+ * \brief walk mblock tree and invalidate all port resolution caches.
+ * \implementation
+ */
+ void
+ invalidate_all_port_caches();
};
diff --git a/mblock/src/lib/mb_message.cc b/mblock/src/lib/mb_message.cc
index 23803726a..14e349924 100644
--- a/mblock/src/lib/mb_message.cc
+++ b/mblock/src/lib/mb_message.cc
@@ -23,6 +23,34 @@
#include <config.h>
#endif
#include <mb_message.h>
+#include <stdio.h>
+#include <pmt_pool.h>
+
+static const int CACHE_LINE_SIZE = 64; // good guess
+
+
+#if MB_MESSAGE_LOCAL_ALLOCATOR
+
+static pmt_pool global_msg_pool(sizeof(mb_message), CACHE_LINE_SIZE);
+
+void *
+mb_message::operator new(size_t size)
+{
+ void *p = global_msg_pool.malloc();
+
+ // fprintf(stderr, "mb_message::new p = %p\n", p);
+ assert((reinterpret_cast<intptr_t>(p) & (CACHE_LINE_SIZE - 1)) == 0);
+ return p;
+}
+
+void
+mb_message::operator delete(void *p, size_t size)
+{
+ global_msg_pool.free(p);
+}
+
+#endif
+
mb_message_sptr
mb_make_message(pmt_t signal, pmt_t data, pmt_t metadata, mb_pri_t priority)
@@ -40,3 +68,16 @@ mb_message::~mb_message()
{
// NOP
}
+
+std::ostream&
+operator<<(std::ostream& os, const mb_message &msg)
+{
+ os << "<msg: signal=" << msg.signal()
+ << " port_id=" << msg.port_id()
+ << " data=" << msg.data()
+ << " metadata=" << msg.metadata()
+ << " pri=" << msg.priority()
+ << ">";
+
+ return os;
+}
diff --git a/mblock/src/lib/mb_message.h b/mblock/src/lib/mb_message.h
index 95440f8b7..6132866e2 100644
--- a/mblock/src/lib/mb_message.h
+++ b/mblock/src/lib/mb_message.h
@@ -22,6 +22,9 @@
#define INCLUDED_MB_MESSAGE_H
#include <mb_common.h>
+#include <iosfwd>
+
+#define MB_MESSAGE_LOCAL_ALLOCATOR 0 // define to 0 or 1
class mb_message;
typedef boost::shared_ptr<mb_message> mb_message_sptr;
@@ -66,6 +69,20 @@ public:
pmt_t port_id() const { return d_port_id; }
void set_port_id(pmt_t port_id){ d_port_id = port_id; }
+
+#if (MB_MESSAGE_LOCAL_ALLOCATOR)
+ void *operator new(size_t);
+ void operator delete(void *, size_t);
+#endif
};
+std::ostream& operator<<(std::ostream& os, const mb_message &msg);
+
+inline
+std::ostream& operator<<(std::ostream& os, const mb_message_sptr msg)
+{
+ os << *(msg.get());
+ return os;
+}
+
#endif /* INCLUDED_MB_MESSAGE_H */
diff --git a/mblock/src/lib/mb_msg_accepter_msgq.cc b/mblock/src/lib/mb_msg_accepter_msgq.cc
new file mode 100644
index 000000000..990491fcc
--- /dev/null
+++ b/mblock/src/lib/mb_msg_accepter_msgq.cc
@@ -0,0 +1,46 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <mb_msg_accepter_msgq.h>
+#include <mb_message.h>
+
+pmt_t s_sys_port = pmt_intern("%sys-port");
+
+mb_msg_accepter_msgq::mb_msg_accepter_msgq(mb_msg_queue *msgq)
+ : d_msgq(msgq)
+{
+}
+
+mb_msg_accepter_msgq::~mb_msg_accepter_msgq()
+{
+}
+
+void
+mb_msg_accepter_msgq::operator()(pmt_t signal, pmt_t data,
+ pmt_t metadata, mb_pri_t priority)
+{
+ mb_message_sptr msg = mb_make_message(signal, data, metadata, priority);
+ msg->set_port_id(s_sys_port);
+ d_msgq->insert(msg);
+}
diff --git a/mblock/src/lib/mb_msg_accepter_msgq.h b/mblock/src/lib/mb_msg_accepter_msgq.h
new file mode 100644
index 000000000..f598c7304
--- /dev/null
+++ b/mblock/src/lib/mb_msg_accepter_msgq.h
@@ -0,0 +1,39 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_MB_MSG_ACCEPTER_MSGQ_H
+#define INCLUDED_MB_MSG_ACCEPTER_MSGQ_H
+
+#include <mb_msg_accepter.h>
+#include <mb_msg_queue.h>
+
+/*!
+ * \brief Concrete class that accepts messages and inserts them into a message queue.
+ */
+class mb_msg_accepter_msgq : public mb_msg_accepter {
+ mb_msg_queue *d_msgq;
+
+public:
+ mb_msg_accepter_msgq(mb_msg_queue *msgq);
+ ~mb_msg_accepter_msgq();
+ void operator()(pmt_t signal, pmt_t data, pmt_t metadata, mb_pri_t priority);
+};
+
+#endif /* INCLUDED_MB_MSG_ACCEPTER_MSGQ_H */
diff --git a/mblock/src/lib/mb_msg_queue.cc b/mblock/src/lib/mb_msg_queue.cc
index 79e245ad6..c687e8760 100644
--- a/mblock/src/lib/mb_msg_queue.cc
+++ b/mblock/src/lib/mb_msg_queue.cc
@@ -83,7 +83,7 @@ mb_msg_queue::get_highest_pri_msg_helper()
}
}
- return mb_message_sptr(); // equivalent of a zero pointer
+ return mb_message_sptr(); // eqv to a zero pointer
}
@@ -109,3 +109,20 @@ mb_msg_queue::get_highest_pri_msg()
}
}
+mb_message_sptr
+mb_msg_queue::get_highest_pri_msg_timedwait(const mb_time &abs_time)
+{
+ unsigned long secs = abs_time.d_secs;
+ unsigned long nsecs = abs_time.d_nsecs;
+
+ omni_mutex_lock l(d_mutex);
+
+ while (1){
+ mb_message_sptr msg = get_highest_pri_msg_helper();
+ if (msg) // Got one; return it
+ return msg;
+
+ if (!d_not_empty.timedwait(secs, nsecs)) // timed out
+ return mb_message_sptr(); // eqv to zero pointer
+ }
+}
diff --git a/mblock/src/lib/mb_msg_queue.h b/mblock/src/lib/mb_msg_queue.h
index 7977b7d80..4f805ea8f 100644
--- a/mblock/src/lib/mb_msg_queue.h
+++ b/mblock/src/lib/mb_msg_queue.h
@@ -23,6 +23,7 @@
#include <mb_common.h>
#include <omnithread.h>
+#include <mb_time.h>
/*!
* \brief priority queue for mblock messages
@@ -63,6 +64,19 @@ public:
* If the queue is empty, this call blocks until it can return a message.
*/
mb_message_sptr get_highest_pri_msg();
+
+ /*
+ * \brief Delete highest pri message from the queue and return it.
+ * If the queue is empty, this call blocks until it can return a message
+ * or real-time exceeds the absolute time, abs_time.
+ *
+ * \param abs_time specifies the latest absolute time to wait until.
+ * \sa mb_time::time
+ *
+ * \returns a valid mb_message_sptr, or the equivalent of a zero pointer
+ * if the call timed out while waiting.
+ */
+ mb_message_sptr get_highest_pri_msg_timedwait(const mb_time &abs_time);
};
#endif /* INCLUDED_MB_MSG_QUEUE_H */
diff --git a/mblock/src/lib/mb_port.cc b/mblock/src/lib/mb_port.cc
index b265db2dc..28bb402d8 100644
--- a/mblock/src/lib/mb_port.cc
+++ b/mblock/src/lib/mb_port.cc
@@ -31,7 +31,8 @@ mb_port::mb_port(mb_mblock *mblock,
const std::string &protocol_class_name,
bool conjugated,
mb_port::port_type_t port_type)
- : d_port_name(port_name), d_conjugated(conjugated), d_port_type(port_type),
+ : d_port_name(port_name), d_port_symbol(pmt_intern(port_name)),
+ d_conjugated(conjugated), d_port_type(port_type),
d_mblock(mblock)
{
pmt_t pc = mb_protocol_class_lookup(pmt_intern(protocol_class_name));
diff --git a/mblock/src/lib/mb_port.h b/mblock/src/lib/mb_port.h
index 3c3e96368..3fdd25aff 100644
--- a/mblock/src/lib/mb_port.h
+++ b/mblock/src/lib/mb_port.h
@@ -40,6 +40,7 @@ public:
private:
std::string d_port_name;
+ pmt_t d_port_symbol; // the port_name as a pmt symbol
pmt_t d_protocol_class;
bool d_conjugated;
port_type_t d_port_type;
@@ -58,6 +59,7 @@ protected:
public:
std::string port_name() const { return d_port_name; }
+ pmt_t port_symbol() const { return d_port_symbol; }
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; }
@@ -77,9 +79,15 @@ public:
*/
virtual void
send(pmt_t signal,
- pmt_t data = PMT_NIL,
- pmt_t metadata = PMT_NIL,
+ pmt_t data = PMT_F,
+ pmt_t metadata = PMT_F,
mb_pri_t priority = MB_PRI_DEFAULT) = 0;
+
+ /*
+ * \brief Invalidate any cached peer resolutions
+ * \implementation
+ */
+ virtual void invalidate_cache() = 0;
};
#endif /* INCLUDED_MB_PORT_H */
diff --git a/mblock/src/lib/mb_port_simple.cc b/mblock/src/lib/mb_port_simple.cc
index 80cb65efb..cbfb0f27f 100644
--- a/mblock/src/lib/mb_port_simple.cc
+++ b/mblock/src/lib/mb_port_simple.cc
@@ -37,7 +37,8 @@ mb_port_simple::mb_port_simple(mb_mblock *mblock,
const std::string &protocol_class_name,
bool conjugated,
mb_port::port_type_t port_type)
- : mb_port(mblock, port_name, protocol_class_name, conjugated, port_type)
+ : mb_port(mblock, port_name, protocol_class_name, conjugated, port_type),
+ d_cache_valid(false)
{
}
@@ -67,6 +68,9 @@ mb_port_simple::find_accepter(mb_port_simple *start)
mb_endpoint peer_ep;
mb_msg_accepter_sptr r;
+ if (start->d_cache_valid)
+ return start->d_cached_accepter;
+
mbi_runtime_lock l(p->mblock());
// Set up initial context.
@@ -78,6 +82,8 @@ mb_port_simple::find_accepter(mb_port_simple *start)
case mb_port::EXTERNAL: // binding is in parent's name space
context = p->mblock()->parent();
+ if (!context) // can't be bound if there's no parent
+ return mb_msg_accepter_sptr(); // not bound
break;
default:
@@ -97,7 +103,11 @@ mb_port_simple::find_accepter(mb_port_simple *start)
case mb_port::INTERNAL: // Terminate here.
case mb_port::EXTERNAL:
r = pp->make_accepter();
- // FIXME cache the result
+
+ // cache the result
+
+ start->d_cached_accepter = r;
+ start->d_cache_valid = true;
return r;
case mb_port::RELAY: // Traverse to other side of relay port.
@@ -130,5 +140,12 @@ mb_port_simple::find_accepter(mb_port_simple *start)
mb_msg_accepter_sptr
mb_port_simple::make_accepter()
{
- return d_mblock->impl()->make_accepter(port_name());
+ return d_mblock->impl()->make_accepter(port_symbol());
+}
+
+void
+mb_port_simple::invalidate_cache()
+{
+ d_cache_valid = false;
+ d_cached_accepter.reset();
}
diff --git a/mblock/src/lib/mb_port_simple.h b/mblock/src/lib/mb_port_simple.h
index 5cfbd3dc0..9bfe0eaf7 100644
--- a/mblock/src/lib/mb_port_simple.h
+++ b/mblock/src/lib/mb_port_simple.h
@@ -28,6 +28,9 @@
*/
class mb_port_simple : public mb_port
{
+ bool d_cache_valid;
+ mb_msg_accepter_sptr d_cached_accepter;
+
protected:
static mb_msg_accepter_sptr
find_accepter(mb_port_simple *start);
@@ -57,6 +60,13 @@ public:
pmt_t data = PMT_NIL,
pmt_t metadata = PMT_NIL,
mb_pri_t priority = MB_PRI_DEFAULT);
+
+ /*
+ * \brief Invalidate any cached peer resolutions
+ * \implementation
+ */
+ void invalidate_cache();
+
};
#endif /* INCLUDED_MB_PORT_SIMPLE_H */
diff --git a/mblock/src/lib/mb_protocol_class.cc b/mblock/src/lib/mb_protocol_class.cc
index f3eeb6035..a11017fa9 100644
--- a/mblock/src/lib/mb_protocol_class.cc
+++ b/mblock/src/lib/mb_protocol_class.cc
@@ -24,6 +24,7 @@
#endif
#include <mb_protocol_class.h>
+#include <iostream>
static pmt_t s_ALL_PROTOCOL_CLASSES = PMT_NIL;
@@ -80,3 +81,25 @@ mb_protocol_class_lookup(pmt_t name)
return PMT_NIL;
}
+
+mb_protocol_class_init::mb_protocol_class_init(const char *data, size_t len)
+{
+ std::stringbuf sb;
+ sb.str(std::string(data, len));
+
+ while (1){
+ pmt_t obj = pmt_deserialize(sb);
+
+ if (0){
+ pmt_write(obj, std::cout);
+ std::cout << std::endl;
+ }
+
+ if (pmt_is_eof_object(obj))
+ return;
+
+ mb_make_protocol_class(pmt_nth(0, obj), // protocol-class name
+ pmt_nth(1, obj), // list of incoming msg names
+ pmt_nth(2, obj)); // list of outgoing msg names
+ }
+}
diff --git a/mblock/src/lib/mb_protocol_class.h b/mblock/src/lib/mb_protocol_class.h
index f4382ada1..60b87709d 100644
--- a/mblock/src/lib/mb_protocol_class.h
+++ b/mblock/src/lib/mb_protocol_class.h
@@ -39,4 +39,14 @@ pmt_t mb_protocol_class_outgoing(pmt_t pc); //< return outgoing message set
pmt_t mb_protocol_class_lookup(pmt_t name); //< lookup an existing protocol class by name
+
+/*!
+ * \brief Initialize one or more protocol class from a serialized description.
+ * Used by machine generated code.
+ */
+class mb_protocol_class_init {
+public:
+ mb_protocol_class_init(const char *data, size_t len);
+};
+
#endif /* INCLUDED_MB_PROTOCOL_CLASS_H */
diff --git a/mblock/src/lib/mb_runtime.cc b/mblock/src/lib/mb_runtime.cc
index 34a0af358..7f3b78678 100644
--- a/mblock/src/lib/mb_runtime.cc
+++ b/mblock/src/lib/mb_runtime.cc
@@ -24,15 +24,16 @@
#endif
#include <mb_runtime.h>
-#include <mb_runtime_thread_per_mblock.h>
+#include <mb_runtime_thread_per_block.h>
mb_runtime_sptr
mb_make_runtime()
{
- return mb_runtime_sptr(new mb_runtime_thread_per_mblock());
+ return mb_runtime_sptr(new mb_runtime_thread_per_block());
}
mb_runtime::~mb_runtime()
{
// nop
}
+
diff --git a/mblock/src/lib/mb_runtime.h b/mblock/src/lib/mb_runtime.h
index 0929e30dc..a804af06f 100644
--- a/mblock/src/lib/mb_runtime.h
+++ b/mblock/src/lib/mb_runtime.h
@@ -37,40 +37,32 @@ mb_runtime_sptr mb_make_runtime();
class mb_runtime : boost::noncopyable,
public boost::enable_shared_from_this<mb_runtime>
{
- omni_mutex d_brl; // big runtime lock (avoid using this if possible...)
+protected:
+ mb_mblock_sptr d_top;
public:
mb_runtime(){}
virtual ~mb_runtime();
/*!
- * \brief Run the mblock hierarchy rooted at \p top
+ * \brief Construct and run the specified mblock hierarchy.
*
* This routine turns into the m-block scheduler, and
* blocks until the system is shutdown.
*
- * \param top top-level mblock
+ * \param name name of the top-level mblock (conventionally "top")
+ * \param class_name The class of the top-level mblock to create.
+ * \param user_arg The argument to pass to the top-level mblock constructor
+ *
* \returns true if the system ran successfully.
*/
- virtual bool run(mb_mblock_sptr top) = 0;
-
-
- // ----------------------------------------------------------------
- // Stuff from here down is really private to the implementation...
- // ----------------------------------------------------------------
-
- /*!
- * \brief lock the big runtime lock
- * \implementation
- */
- inline void lock() { d_brl.lock(); }
-
- /*!
- * \brief unlock the big runtime lock
- * \implementation
- */
- inline void unlock() { d_brl.unlock(); }
+ virtual bool run(const std::string &instance_name,
+ const std::string &class_name,
+ pmt_t user_arg,
+ pmt_t *result = 0) = 0;
+ // QA only...
+ mb_mblock_sptr top() { return d_top; }
};
#endif /* INCLUDED_MB_RUNTIME_H */
diff --git a/mblock/src/lib/mb_runtime_placeholder.cc b/mblock/src/lib/mb_runtime_base.cc
index 5ce7cc2ac..104b6afcc 100644
--- a/mblock/src/lib/mb_runtime_placeholder.cc
+++ b/mblock/src/lib/mb_runtime_base.cc
@@ -22,36 +22,36 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-#include <mb_runtime_placeholder.h>
-#include <mb_mblock.h>
-#include <mb_exception.h>
-
-
-static mb_runtime *s_singleton = 0;
+#include <mb_runtime_base.h>
+/*
+ * Default nop implementations...
+ */
-mb_runtime_placeholder::mb_runtime_placeholder()
+void
+mb_runtime_base::request_shutdown(pmt_t result)
{
- // nop
}
-mb_runtime_placeholder::~mb_runtime_placeholder()
+pmt_t
+mb_runtime_base::schedule_one_shot_timeout(const mb_time &abs_time,
+ pmt_t user_data,
+ mb_msg_accepter_sptr accepter)
{
- // nop
+ return PMT_F;
}
-bool
-mb_runtime_placeholder::run(mb_mblock_sptr top)
+pmt_t
+mb_runtime_base::schedule_periodic_timeout(const mb_time &first_abs_time,
+ const mb_time &delta_time,
+ pmt_t user_data,
+ mb_msg_accepter_sptr accepter)
{
- throw mbe_not_implemented(top.get(), "mb_runtime_placeholder::run");
+ return PMT_F;
}
-mb_runtime *
-mb_runtime_placeholder::singleton()
+void
+mb_runtime_base::cancel_timeout(pmt_t handle)
{
- if (s_singleton)
- return s_singleton;
-
- s_singleton = new mb_runtime_placeholder();
- return s_singleton;
}
+
diff --git a/mblock/src/lib/mb_runtime_base.h b/mblock/src/lib/mb_runtime_base.h
new file mode 100644
index 000000000..cb76e4503
--- /dev/null
+++ b/mblock/src/lib/mb_runtime_base.h
@@ -0,0 +1,78 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef INCLUDED_MB_RUNTIME_BASE_H
+#define INCLUDED_MB_RUNTIME_BASE_H
+
+#include <mb_runtime.h>
+#include <omnithread.h>
+#include <mb_time.h>
+
+/*
+ * \brief This is the runtime class used by the implementation.
+ */
+class mb_runtime_base : public mb_runtime
+{
+ omni_mutex d_brl; // big runtime lock (avoid using this if possible...)
+
+protected:
+ mb_msg_accepter_sptr d_accepter;
+
+public:
+
+ /*!
+ * \brief lock the big runtime lock
+ * \implementation
+ */
+ inline void lock() { d_brl.lock(); }
+
+ /*!
+ * \brief unlock the big runtime lock
+ * \implementation
+ */
+ inline void unlock() { d_brl.unlock(); }
+
+ virtual void request_shutdown(pmt_t result);
+
+ virtual mb_mblock_sptr
+ create_component(const std::string &instance_name,
+ const std::string &class_name,
+ pmt_t user_arg) = 0;
+
+ virtual pmt_t
+ schedule_one_shot_timeout(const mb_time &abs_time, pmt_t user_data,
+ mb_msg_accepter_sptr accepter);
+
+ virtual pmt_t
+ schedule_periodic_timeout(const mb_time &first_abs_time,
+ const mb_time &delta_time,
+ pmt_t user_data,
+ mb_msg_accepter_sptr accepter);
+ virtual void
+ cancel_timeout(pmt_t handle);
+
+ mb_msg_accepter_sptr
+ accepter() { return d_accepter; }
+
+};
+
+
+#endif /* INCLUDED_MB_RUNTIME_BASE_H */
diff --git a/mblock/src/lib/mb_runtime_nop.cc b/mblock/src/lib/mb_runtime_nop.cc
index a19f0793a..bcae1ebd5 100644
--- a/mblock/src/lib/mb_runtime_nop.cc
+++ b/mblock/src/lib/mb_runtime_nop.cc
@@ -24,6 +24,8 @@
#endif
#include <mb_runtime_nop.h>
#include <mb_mblock.h>
+#include <mb_class_registry.h>
+#include <mb_exception.h>
mb_runtime_sptr
mb_make_runtime_nop()
@@ -42,23 +44,41 @@ mb_runtime_nop::~mb_runtime_nop()
// nop for now
}
+
bool
-mb_runtime_nop::run(mb_mblock_sptr top)
+mb_runtime_nop::run(const std::string &instance_name,
+ const std::string &class_name,
+ pmt_t user_arg, pmt_t *result)
{
class initial_visitor : public mb_visitor
{
public:
- bool operator()(mb_mblock *mblock, const std::string &path)
+ bool operator()(mb_mblock *mblock)
{
- mblock->set_instance_name(path);
- mblock->init_fsm();
+ mblock->initial_transition();
return true;
}
};
- initial_visitor visitor;
+ initial_visitor visitor;
+
+ if (result)
+ *result = PMT_T;
- top->walk_tree(&visitor);
+ d_top = create_component(instance_name, class_name, user_arg);
+ d_top->walk_tree(&visitor);
return true;
}
+
+mb_mblock_sptr
+mb_runtime_nop::create_component(const std::string &instance_name,
+ const std::string &class_name,
+ pmt_t user_arg)
+{
+ mb_mblock_maker_t maker;
+ if (!mb_class_registry::lookup_maker(class_name, &maker))
+ throw mbe_no_such_class(0, class_name + " (in " + instance_name + ")");
+
+ return maker(this, instance_name, user_arg);
+}
diff --git a/mblock/src/lib/mb_runtime_nop.h b/mblock/src/lib/mb_runtime_nop.h
index dc7887991..d7fe105bd 100644
--- a/mblock/src/lib/mb_runtime_nop.h
+++ b/mblock/src/lib/mb_runtime_nop.h
@@ -21,7 +21,7 @@
#ifndef INCLUDED_MB_RUNTIME_NOP_H
#define INCLUDED_MB_RUNTIME_NOP_H
-#include <mb_runtime.h>
+#include <mb_runtime_base.h>
/*!
* \brief Public constructor (factory) for mb_runtime_nop objects.
@@ -31,14 +31,22 @@ mb_runtime_sptr mb_make_runtime_nop();
/*!
* \brief Concrete runtime that does nothing. Used only during early QA tests.
*/
-class mb_runtime_nop : public mb_runtime
+class mb_runtime_nop : public mb_runtime_base
{
-
public:
mb_runtime_nop();
~mb_runtime_nop();
- bool run(mb_mblock_sptr top);
+ bool run(const std::string &instance_name,
+ const std::string &class_name,
+ pmt_t user_arg,
+ pmt_t *result);
+
+protected:
+ mb_mblock_sptr
+ create_component(const std::string &instance_name,
+ const std::string &class_name,
+ pmt_t user_arg);
};
#endif /* INCLUDED_MB_RUNTIME_NOP_H */
diff --git a/mblock/src/lib/mb_runtime_thread_per_block.cc b/mblock/src/lib/mb_runtime_thread_per_block.cc
new file mode 100644
index 000000000..7ad87aa23
--- /dev/null
+++ b/mblock/src/lib/mb_runtime_thread_per_block.cc
@@ -0,0 +1,349 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <mb_runtime_thread_per_block.h>
+#include <mb_mblock.h>
+#include <mb_mblock_impl.h>
+#include <mb_class_registry.h>
+#include <mb_exception.h>
+#include <mb_worker.h>
+#include <omnithread.h>
+#include <iostream>
+#include <mb_msg_accepter_msgq.h>
+
+
+static pmt_t s_halt = pmt_intern("%halt");
+static pmt_t s_sys_port = pmt_intern("%sys-port");
+static pmt_t s_shutdown = pmt_intern("%shutdown");
+static pmt_t s_request_shutdown = pmt_intern("%request-shutdown");
+static pmt_t s_worker_state_changed = pmt_intern("%worker-state-changed");
+static pmt_t s_timeout = pmt_intern("%timeout");
+static pmt_t s_request_timeout = pmt_intern("%request-timeout");
+static pmt_t s_cancel_timeout = pmt_intern("%cancel-timeout");
+static pmt_t s_send_halt = pmt_intern("send-halt");
+static pmt_t s_exit_now = pmt_intern("exit-now");
+
+static void
+send_sys_msg(mb_msg_queue &msgq, pmt_t signal,
+ pmt_t data = PMT_F, pmt_t metadata = PMT_F,
+ mb_pri_t priority = MB_PRI_BEST)
+{
+ mb_message_sptr msg = mb_make_message(signal, data, metadata, priority);
+ msg->set_port_id(s_sys_port);
+ msgq.insert(msg);
+}
+
+
+mb_runtime_thread_per_block::mb_runtime_thread_per_block()
+ : d_shutdown_in_progress(false),
+ d_shutdown_result(PMT_T)
+{
+ d_accepter = mb_msg_accepter_sptr(new mb_msg_accepter_msgq(&d_msgq));
+}
+
+mb_runtime_thread_per_block::~mb_runtime_thread_per_block()
+{
+ // FIXME iterate over workers and ensure that they are dead.
+
+ if (!d_workers.empty())
+ std::cerr << "\nmb_runtime_thread_per_block: dtor (# workers = "
+ << d_workers.size() << ")\n";
+}
+
+void
+mb_runtime_thread_per_block::request_shutdown(pmt_t result)
+{
+ (*accepter())(s_request_shutdown, result, PMT_F, MB_PRI_BEST);
+}
+
+bool
+mb_runtime_thread_per_block::run(const std::string &instance_name,
+ const std::string &class_name,
+ pmt_t user_arg, pmt_t *result)
+{
+ if (result) // set it to something now, in case we throw
+ *result = PMT_F;
+
+ // reset the shutdown state
+ d_shutdown_in_progress = false;
+ d_shutdown_result = PMT_T;
+
+ assert(d_workers.empty());
+
+ while (!d_timer_queue.empty()) // ensure timer queue is empty
+ d_timer_queue.pop();
+
+ /*
+ * Create the top-level component, and recursively all of its
+ * subcomponents.
+ */
+ d_top = create_component(instance_name, class_name, user_arg);
+
+ try {
+ run_loop();
+ }
+ catch (...){
+ d_top.reset();
+ throw;
+ }
+
+ if (result)
+ *result = d_shutdown_result;
+
+ d_top.reset();
+ return true;
+}
+
+void
+mb_runtime_thread_per_block::run_loop()
+{
+ while (1){
+ mb_message_sptr msg;
+
+ if (d_timer_queue.empty()) // Any timeouts pending?
+ msg = d_msgq.get_highest_pri_msg(); // Nope. Block forever.
+
+ else {
+ mb_timeout_sptr to = d_timer_queue.top(); // Yep. Get earliest timeout.
+
+ // wait for a msg or the timeout...
+ msg = d_msgq.get_highest_pri_msg_timedwait(to->d_when);
+
+ if (!msg){ // We timed out.
+ d_timer_queue.pop(); // Remove timeout from timer queue.
+
+ // send the %timeout msg
+ (*to->d_accepter)(s_timeout, to->d_user_data, to->handle(), MB_PRI_BEST);
+
+ if (to->d_is_periodic){
+ to->d_when = to->d_when + to->d_delta; // update time of next firing
+ d_timer_queue.push(to); // push it back into the queue
+ }
+ continue;
+ }
+ }
+
+ pmt_t signal = msg->signal();
+
+ if (pmt_eq(signal, s_worker_state_changed)){ // %worker-state-changed
+ omni_mutex_lock l1(d_workers_mutex);
+ reap_dead_workers();
+ if (d_workers.empty()) // no work left to do...
+ return;
+ }
+ else if (pmt_eq(signal, s_request_shutdown)){ // %request-shutdown
+ if (!d_shutdown_in_progress){
+ d_shutdown_in_progress = true;
+ d_shutdown_result = msg->data();
+
+ // schedule a timeout for ourselves...
+ schedule_one_shot_timeout(mb_time::time(0.100), s_send_halt, d_accepter);
+ send_all_sys_msg(s_shutdown);
+ }
+ }
+ else if (pmt_eq(signal, s_request_timeout)){ // %request-timeout
+ mb_timeout_sptr to =
+ boost::any_cast<mb_timeout_sptr>(pmt_any_ref(msg->data()));
+ d_timer_queue.push(to);
+ }
+ else if (pmt_eq(signal, s_cancel_timeout)){ // %cancel-timeout
+ d_timer_queue.cancel(msg->data());
+ }
+ else if (pmt_eq(signal, s_timeout)
+ && pmt_eq(msg->data(), s_send_halt)){ // %timeout, send-halt
+
+ // schedule another timeout for ourselves...
+ schedule_one_shot_timeout(mb_time::time(0.100), s_exit_now, d_accepter);
+ send_all_sys_msg(s_halt);
+ }
+ else if (pmt_eq(signal, s_timeout)
+ && pmt_eq(msg->data(), s_exit_now)){ // %timeout, exit-now
+
+ // We only get here if we've sent all workers %shutdown followed
+ // by %halt, and one or more of them is still alive. They must
+ // be blocked in the kernel. FIXME We could add one more step:
+ // pthread_kill(...) but for now, we'll just ignore them...
+ return;
+ }
+ else {
+ std::cerr << "mb_runtime_thread_per_block: unhandled msg: " << msg << std::endl;
+ }
+ }
+}
+
+void
+mb_runtime_thread_per_block::reap_dead_workers()
+{
+ // Already holding mutex
+ // omni_mutex_lock l1(d_workers_mutex);
+
+ for (worker_iter_t wi = d_workers.begin(); wi != d_workers.end(); ){
+ bool is_dead;
+
+ // We can't join while holding the worker mutex, since that would
+ // attempt to destroy the mutex we're holding (omnithread's join
+ // deletes the omni_thread object after the pthread_join
+ // completes) Instead, we lock just long enough to figure out if
+ // the worker is dead.
+ {
+ omni_mutex_lock l2((*wi)->d_mutex);
+ is_dead = (*wi)->d_state == mb_worker::TS_DEAD;
+ }
+
+ if (is_dead){
+ if (0)
+ std::cerr << "\nruntime: "
+ << "(" << (*wi)->id() << ") "
+ << (*wi)->d_mblock->instance_name() << " is TS_DEAD\n";
+ void *ignore;
+ (*wi)->join(&ignore);
+ wi = d_workers.erase(wi);
+ continue;
+ }
+ ++wi;
+ }
+}
+
+//
+// Create the thread, then create the component in the thread.
+// Return a pointer to the created mblock.
+//
+// Can be invoked from any thread
+//
+mb_mblock_sptr
+mb_runtime_thread_per_block::create_component(const std::string &instance_name,
+ const std::string &class_name,
+ pmt_t user_arg)
+{
+ mb_mblock_maker_t maker;
+ if (!mb_class_registry::lookup_maker(class_name, &maker))
+ throw mbe_no_such_class(0, class_name + " (in " + instance_name + ")");
+
+ // FIXME here's where we'd lookup NUMA placement requests & mblock
+ // priorities and communicate them to the worker we're creating...
+
+ // Create the worker thread
+ mb_worker *w =
+ new mb_worker(this, maker, instance_name, user_arg);
+
+ w->start_undetached(); // start it
+
+ // Wait for it to reach TS_RUNNING or TS_DEAD
+
+ bool is_dead;
+ mb_worker::cause_of_death_t why_dead;
+ {
+ omni_mutex_lock l(w->d_mutex);
+ while (!(w->d_state == mb_worker::TS_RUNNING
+ || w->d_state == mb_worker::TS_DEAD))
+ w->d_state_cond.wait();
+
+ is_dead = w->d_state == mb_worker::TS_DEAD;
+ why_dead = w->d_why_dead;
+ }
+
+ // If the worker failed to init (constructor or initial_transition
+ // raised an exception), reap the worker now and raise an exception.
+
+ if (is_dead && why_dead != mb_worker::RIP_EXIT){
+
+ void *ignore;
+ w->join(&ignore);
+
+ // FIXME with some work we ought to be able to propagate the
+ // exception from the worker.
+ throw mbe_mblock_failed(0, instance_name);
+ }
+
+ assert(w->d_mblock);
+
+ // Add w to the vector of workers, and return the mblock.
+ {
+ omni_mutex_lock l(d_workers_mutex);
+ d_workers.push_back(w);
+ }
+
+ if (0)
+ std::cerr << "\nruntime: created "
+ << "(" << w->id() << ") "
+ << w->d_mblock->instance_name() << "\n";
+
+ return w->d_mblock;
+}
+
+void
+mb_runtime_thread_per_block::send_all_sys_msg(pmt_t signal,
+ pmt_t data,
+ pmt_t metadata,
+ mb_pri_t priority)
+{
+ omni_mutex_lock l1(d_workers_mutex);
+
+ for (worker_iter_t wi = d_workers.begin(); wi != d_workers.end(); ++wi){
+ send_sys_msg((*wi)->d_mblock->impl()->msgq(),
+ signal, data, metadata, priority);
+ }
+}
+
+//
+// Can be invoked from any thread.
+// Sends a message to the runtime.
+//
+pmt_t
+mb_runtime_thread_per_block::schedule_one_shot_timeout
+ (const mb_time &abs_time,
+ pmt_t user_data,
+ mb_msg_accepter_sptr accepter)
+{
+ mb_timeout_sptr to(new mb_timeout(abs_time, user_data, accepter));
+ (*d_accepter)(s_request_timeout, pmt_make_any(to), PMT_F, MB_PRI_BEST);
+ return to->handle();
+}
+
+//
+// Can be invoked from any thread.
+// Sends a message to the runtime.
+//
+pmt_t
+mb_runtime_thread_per_block::schedule_periodic_timeout
+ (const mb_time &first_abs_time,
+ const mb_time &delta_time,
+ pmt_t user_data,
+ mb_msg_accepter_sptr accepter)
+{
+ mb_timeout_sptr to(new mb_timeout(first_abs_time, delta_time,
+ user_data, accepter));
+ (*d_accepter)(s_request_timeout, pmt_make_any(to), PMT_F, MB_PRI_BEST);
+ return to->handle();
+}
+
+//
+// Can be invoked from any thread.
+// Sends a message to the runtime.
+//
+void
+mb_runtime_thread_per_block::cancel_timeout(pmt_t handle)
+{
+ (*d_accepter)(s_cancel_timeout, handle, PMT_F, MB_PRI_BEST);
+}
diff --git a/mblock/src/lib/mb_runtime_thread_per_block.h b/mblock/src/lib/mb_runtime_thread_per_block.h
new file mode 100644
index 000000000..773b8b4e9
--- /dev/null
+++ b/mblock/src/lib/mb_runtime_thread_per_block.h
@@ -0,0 +1,84 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_MB_RUNTIME_THREAD_PER_BLOCK_H
+#define INCLUDED_MB_RUNTIME_THREAD_PER_BLOCK_H
+
+#include <mb_runtime_base.h>
+#include <mb_worker.h>
+#include <mb_msg_queue.h>
+#include <mb_timer_queue.h>
+
+/*!
+ * \brief Concrete runtime that uses a thread per mblock
+ * \implementation
+ *
+ * These are all implementation details.
+ */
+class mb_runtime_thread_per_block : public mb_runtime_base
+{
+public:
+ omni_mutex d_workers_mutex; // hold while manipulating d_workers
+ std::vector<mb_worker*> d_workers;
+ bool d_shutdown_in_progress;
+ pmt_t d_shutdown_result;
+ mb_msg_queue d_msgq;
+ mb_timer_queue d_timer_queue;
+
+ typedef std::vector<mb_worker*>::iterator worker_iter_t;
+
+ mb_runtime_thread_per_block();
+ ~mb_runtime_thread_per_block();
+
+ bool run(const std::string &instance_name,
+ const std::string &class_name,
+ pmt_t user_arg,
+ pmt_t *result);
+
+ void request_shutdown(pmt_t result);
+
+protected:
+ mb_mblock_sptr
+ create_component(const std::string &instance_name,
+ const std::string &class_name,
+ pmt_t user_arg);
+
+ pmt_t
+ schedule_one_shot_timeout(const mb_time &abs_time, pmt_t user_data,
+ mb_msg_accepter_sptr accepter);
+
+ pmt_t
+ schedule_periodic_timeout(const mb_time &first_abs_time,
+ const mb_time &delta_time,
+ pmt_t user_data,
+ mb_msg_accepter_sptr accepter);
+ void
+ cancel_timeout(pmt_t handle);
+
+private:
+ void reap_dead_workers();
+ void run_loop();
+
+ void send_all_sys_msg(pmt_t signal, pmt_t data = PMT_F,
+ pmt_t metadata = PMT_F,
+ mb_pri_t priority = MB_PRI_BEST);
+};
+
+#endif /* INCLUDED_MB_RUNTIME_THREAD_PER_BLOCK_H */
diff --git a/mblock/src/lib/mb_time.cc b/mblock/src/lib/mb_time.cc
new file mode 100644
index 000000000..73c86e4f4
--- /dev/null
+++ b/mblock/src/lib/mb_time.cc
@@ -0,0 +1,84 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <mb_time.h>
+#include <omnithread.h>
+#include <math.h>
+#include <assert.h>
+
+
+mb_time::mb_time(double real_secs)
+{
+ double floor_secs = floor(real_secs);
+ d_secs = (long) floor_secs;
+ d_nsecs = (long) ((real_secs - floor_secs) * 1e9); // always positive
+}
+
+mb_time
+mb_time::time(const mb_time &delta_t)
+{
+ unsigned long abs_sec, abs_nsec;
+ unsigned long rel_sec = delta_t.d_secs;
+ unsigned long rel_nsec = delta_t.d_nsecs;
+
+ omni_thread::get_time(&abs_sec, &abs_nsec, rel_sec, rel_nsec);
+ return mb_time(abs_sec, abs_nsec);
+}
+
+
+mb_time
+operator+(const mb_time &x, const mb_time &y)
+{
+ mb_time r(x.d_secs + y.d_secs, x.d_nsecs + y.d_nsecs);
+ while (r.d_nsecs >= 1000000000){
+ r.d_nsecs -= 1000000000;
+ r.d_secs++;
+ }
+ return r;
+}
+
+mb_time
+operator-(const mb_time &x, const mb_time &y)
+{
+ // assert(!(x < y));
+
+ mb_time r(x.d_secs - y.d_secs, x.d_nsecs - y.d_nsecs);
+ while (r.d_nsecs < 0){
+ r.d_nsecs += 1000000000;
+ r.d_secs--;
+ }
+ return r;
+}
+
+mb_time
+operator+(const mb_time &x, double y)
+{
+ return x + mb_time(y);
+}
+
+mb_time
+operator-(const mb_time &x, double y)
+{
+ return x - mb_time(y);
+}
diff --git a/mblock/src/lib/mb_time.h b/mblock/src/lib/mb_time.h
new file mode 100644
index 000000000..872304caa
--- /dev/null
+++ b/mblock/src/lib/mb_time.h
@@ -0,0 +1,89 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef INCLUDED_MB_TIME_H
+#define INCLUDED_MB_TIME_H
+
+struct mb_time {
+ long int d_secs; // seconds.
+ long int d_nsecs; // nanoseconds. Always in [0, 1e9-1]
+
+ mb_time() : d_secs(0), d_nsecs(0) {}
+ mb_time(long secs, long nanosecs=0) : d_secs(secs), d_nsecs(nanosecs) {}
+
+ // N.B., this only makes sense for differences between times.
+ // Double doesn't have enough bits to precisely represent an absolute time.
+ mb_time(double secs);
+
+ // N.B. This only makes sense for differences between times.
+ // Double doesn't have enough bits to precisely represent an absolute time.
+ double double_time() const { return (double)d_secs + d_nsecs * 1e-9; }
+
+ /*!
+ * \brief Return an absolute time suitable for use with
+ * schedule_one_shot_timeout & schedule_periodic_timeout
+ *
+ * The return value is the current time plus the given relative offset.
+ */
+ static mb_time time(const mb_time &relative_offset = mb_time());
+};
+
+
+inline static bool
+operator<(const mb_time &x, const mb_time &y)
+{
+ return ((x.d_secs < y.d_secs)
+ || (x.d_secs == y.d_secs && x.d_nsecs < y.d_nsecs));
+}
+
+inline static bool
+operator>(const mb_time &x, const mb_time &y)
+{
+ return ((x.d_secs > y.d_secs)
+ || (x.d_secs == y.d_secs && x.d_nsecs > y.d_nsecs));
+}
+
+inline static bool
+operator>=(const mb_time &x, const mb_time &y)
+{
+ return ((x.d_secs > y.d_secs)
+ || (x.d_secs == y.d_secs && x.d_nsecs >= y.d_nsecs));
+}
+
+inline static bool
+operator<=(const mb_time &x, const mb_time &y)
+{
+ return ((x.d_secs < y.d_secs)
+ || (x.d_secs == y.d_secs && x.d_nsecs <= y.d_nsecs));
+}
+
+inline static bool
+operator==(const mb_time &x, const mb_time &y)
+{
+ return (x.d_secs == y.d_secs && x.d_nsecs == y.d_nsecs);
+}
+
+
+mb_time operator+(const mb_time &x, const mb_time &y);
+mb_time operator+(const mb_time &x, double y);
+mb_time operator-(const mb_time &x, const mb_time &y);
+mb_time operator-(const mb_time &x, double y);
+
+#endif /* INCLUDED_MB_TIME_H */
diff --git a/mblock/src/lib/mb_timer_queue.cc b/mblock/src/lib/mb_timer_queue.cc
new file mode 100644
index 000000000..026035ec5
--- /dev/null
+++ b/mblock/src/lib/mb_timer_queue.cc
@@ -0,0 +1,63 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <mb_timer_queue.h>
+
+static pmt_t
+make_handle()
+{
+ static long counter = 0;
+ pmt_t n = pmt_from_long(counter++);
+ return pmt_list1(n); // guaranteed to be a unique object
+}
+
+// one-shot constructor
+mb_timeout::mb_timeout(const mb_time &abs_time,
+ pmt_t user_data, mb_msg_accepter_sptr accepter)
+ : d_when(abs_time), d_is_periodic(false),
+ d_user_data(user_data), d_handle(make_handle()), d_accepter(accepter)
+{
+}
+
+// periodic constructor
+mb_timeout::mb_timeout(const mb_time &first_abs_time, const mb_time &delta_time,
+ pmt_t user_data, mb_msg_accepter_sptr accepter)
+ : d_when(first_abs_time), d_delta(delta_time), d_is_periodic(true),
+ d_user_data(user_data), d_handle(make_handle()), d_accepter(accepter)
+{
+}
+
+void
+mb_timer_queue::cancel(pmt_t handle)
+{
+ container_type::iterator it;
+
+ for (it = c.begin(); it != c.end();){
+ if (pmt_equal((*it)->handle(), handle))
+ it = c.erase(it);
+ else
+ ++it;
+ }
+ std::make_heap(c.begin(), c.end(), comp);
+}
diff --git a/mblock/src/lib/mb_timer_queue.h b/mblock/src/lib/mb_timer_queue.h
new file mode 100644
index 000000000..a17688331
--- /dev/null
+++ b/mblock/src/lib/mb_timer_queue.h
@@ -0,0 +1,73 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef INCLUDED_MB_TIMER_QUEUE_H
+#define INCLUDED_MB_TIMER_QUEUE_H
+
+#include <mb_time.h>
+#include <vector>
+#include <queue>
+#include <pmt.h>
+#include <mb_msg_accepter.h>
+
+class mb_timeout {
+public:
+ mb_time d_when; // absolute time to fire timeout
+ mb_time d_delta; // if periodic, delta_t to next timeout
+ bool d_is_periodic; // true iff this is a periodic timeout
+ pmt_t d_user_data; // data from %timeout msg
+ pmt_t d_handle; // handle for cancellation
+ mb_msg_accepter_sptr d_accepter; // where to send the message
+
+ // one-shot constructor
+ mb_timeout(const mb_time &abs_time,
+ pmt_t user_data, mb_msg_accepter_sptr accepter);
+
+ // periodic constructor
+ mb_timeout(const mb_time &first_abs_time, const mb_time &delta_time,
+ pmt_t user_data, mb_msg_accepter_sptr accepter);
+
+ pmt_t handle() const { return d_handle; }
+};
+
+typedef boost::shared_ptr<mb_timeout> mb_timeout_sptr;
+
+
+//! Sort criterion for priority_queue
+class timeout_later
+{
+public:
+ bool operator() (const mb_timeout_sptr t1, const mb_timeout_sptr t2)
+ {
+ return t1->d_when > t2->d_when;
+ }
+};
+
+
+class mb_timer_queue : public std::priority_queue<mb_timeout_sptr,
+ std::vector<mb_timeout_sptr>,
+ timeout_later>
+{
+public:
+ void cancel(pmt_t handle);
+};
+
+#endif /* INCLUDED_MB_TIMER_QUEUE_H */
diff --git a/mblock/src/lib/mb_worker.cc b/mblock/src/lib/mb_worker.cc
new file mode 100644
index 000000000..8a9248443
--- /dev/null
+++ b/mblock/src/lib/mb_worker.cc
@@ -0,0 +1,178 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <mb_worker.h>
+#include <mb_runtime_thread_per_block.h>
+#include <mb_exception.h>
+#include <mb_mblock.h>
+#include <mb_gettid.h>
+#include <mb_msg_accepter.h>
+#include <iostream>
+#ifdef HAVE_SCHED_H
+#include <sched.h>
+#endif
+
+#define VERBOSE 0 // define to 0 or 1
+
+
+static pmt_t s_worker_state_changed = pmt_intern("%worker-state-changed");
+
+
+mb_worker::mb_worker(mb_runtime_thread_per_block *runtime,
+ mb_mblock_maker_t maker,
+ const std::string &instance_name,
+ pmt_t user_arg)
+ : omni_thread((void *) 0, PRIORITY_NORMAL),
+ d_runtime(runtime), d_maker(maker),
+ d_instance_name(instance_name), d_user_arg(user_arg),
+ d_state_cond(&d_mutex), d_state(TS_UNINITIALIZED),
+ d_why_dead(RIP_NOT_DEAD_YET)
+{
+}
+
+#if 0
+mb_worker::~mb_worker()
+{
+}
+#endif
+
+#ifdef HAVE_SCHED_SETAFFINITY
+static void
+set_affinity(const std::string &instance_name, const std::string &class_name)
+{
+ //static int counter = 0;
+ cpu_set_t mask;
+ CPU_ZERO(&mask);
+
+ if (0){
+
+ //CPU_SET(counter & 0x1, &mask);
+ //counter++;
+ CPU_SET(0, &mask);
+
+ int r = sched_setaffinity(mb_gettid(), sizeof(mask), &mask);
+ if (r == -1)
+ perror("sched_setaffinity");
+ }
+}
+#else
+static void
+set_affinity(const std::string &instance_name, const std::string &class_name)
+{
+}
+#endif
+
+void
+mb_worker::set_state(worker_state_t state)
+{
+ {
+ omni_mutex_lock l2(d_mutex);
+
+ d_state = state; // update our state
+ d_state_cond.broadcast(); // Notify everybody who cares...
+ }
+
+ // send msg to runtime, telling it something changed.
+ (*d_runtime->accepter())(s_worker_state_changed, PMT_F, PMT_F, MB_PRI_BEST);
+}
+
+void *
+mb_worker::run_undetached(void *ignored)
+{
+ // FIXME add pthread_sigmask stuff
+
+ //set_affinity(d_instance_name, d_class_name);
+ set_affinity(d_instance_name, "");
+
+ try {
+ worker_thread_top_level();
+ d_why_dead = RIP_EXIT;
+ }
+ catch (mbe_terminate){
+ d_why_dead = RIP_TERMINATE;
+ }
+ catch (mbe_exit){
+ d_why_dead = RIP_EXIT;
+ }
+ catch (std::logic_error e){
+ if (d_why_dead == RIP_NOT_DEAD_YET)
+ d_why_dead = RIP_UNHANDLED_EXCEPTION;
+
+ std::cerr << "\nmb_worker::run_undetached: unhandled exception:\n";
+ std::cerr << " " << e.what() << std::endl;
+ }
+ catch (...){
+ if (d_why_dead == RIP_NOT_DEAD_YET)
+ d_why_dead = RIP_UNHANDLED_EXCEPTION;
+ }
+
+ if (VERBOSE)
+ std::cerr << "\nrun_undetached: about to return, d_why_dead = "
+ << d_why_dead << std::endl;
+
+ set_state(TS_DEAD);
+ return 0;
+}
+
+void
+mb_worker::worker_thread_top_level()
+{
+ if (VERBOSE)
+ std::cerr << "worker_thread_top_level (enter):" << std::endl
+ << " instance_name: " << d_instance_name << std::endl
+ << " omnithread id: " << id() << std::endl
+ << " gettid: " << mb_gettid() << std::endl
+ << " getpid: " << getpid() << std::endl;
+
+ cause_of_death_t pending_cause_of_death = RIP_NOT_DEAD_YET;
+
+ try {
+ pending_cause_of_death = RIP_CTOR_EXCEPTION;
+ d_mblock = d_maker(d_runtime, d_instance_name, d_user_arg);
+
+ if (VERBOSE)
+ std::cerr << "worker_thread_top_level (post-construction):" << std::endl
+ << " instance_name: " << d_instance_name << std::endl;
+
+ pending_cause_of_death = RIP_INIT_EXCEPTION;
+ d_mblock->initial_transition();
+
+ if (VERBOSE)
+ std::cerr << "worker_thread_top_level (post-initial-transition):" << std::endl
+ << " instance_name: " << d_instance_name << std::endl;
+
+ set_state(TS_RUNNING);
+
+ pending_cause_of_death = RIP_UNHANDLED_EXCEPTION;
+ d_mblock->main_loop();
+ }
+ catch (...){
+ d_why_dead = pending_cause_of_death;
+ throw;
+ }
+
+ if (VERBOSE)
+ std::cerr << "worker_thread_top_level (exit):" << std::endl
+ << " instance_name: " << d_instance_name << std::endl;
+}
diff --git a/mblock/src/lib/mb_worker.h b/mblock/src/lib/mb_worker.h
new file mode 100644
index 000000000..b207f4db5
--- /dev/null
+++ b/mblock/src/lib/mb_worker.h
@@ -0,0 +1,106 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef INCLUDED_MB_WORKER_H
+#define INCLUDED_MB_WORKER_H
+
+#include <omnithread.h>
+#include <mb_common.h>
+#include <mb_class_registry.h>
+
+
+class mb_worker;
+//typedef boost::shared_ptr<mb_worker> mb_worker_sptr;
+
+class mb_runtime_thread_per_block;
+
+/*!
+ * \brief Worker thread for thread_per_block runtime
+ * \implementation
+ */
+class mb_worker : public omni_thread
+{
+public:
+ //! worker thread states
+ enum worker_state_t {
+ TS_UNINITIALIZED, // new, uninitialized
+ TS_RUNNING, // normal steady-state condition.
+ TS_DEAD // thread is dead
+ };
+
+ //! why we're dead
+ enum cause_of_death_t {
+ RIP_NOT_DEAD_YET, // not dead
+ RIP_EXIT, // normal exit
+ RIP_TERMINATE, // caught terminate exception
+ RIP_CTOR_EXCEPTION, // constructor raised an exception
+ RIP_INIT_EXCEPTION, // initial_transition rasised an exception
+ RIP_UNHANDLED_EXCEPTION // somebody (most likely handle_message) raised an exception
+ };
+
+ /*
+ * Args used by new thread to create mb_mblock
+ */
+ mb_runtime_thread_per_block *d_runtime;
+ mb_mblock_maker_t d_maker;
+ std::string d_instance_name;
+ pmt_t d_user_arg;
+
+ mb_mblock_sptr d_mblock; //< holds pointer to created mblock
+
+ /*!
+ * \brief General mutex for all these fields.
+ *
+ * They are accessed by both the main runtime thread and the newly
+ * created thread that runs the mblock's main loop.
+ */
+ omni_mutex d_mutex;
+ omni_condition d_state_cond; //< state change notifications
+ worker_state_t d_state;
+ cause_of_death_t d_why_dead;
+
+ mb_worker(mb_runtime_thread_per_block *runtime,
+ mb_mblock_maker_t maker,
+ const std::string &instance_name,
+ pmt_t user_arg);
+
+ // ~mb_worker();
+
+
+ /*!
+ * \brief This code runs as the top-level of the new thread
+ */
+ void worker_thread_top_level();
+
+ /*!
+ * \brief Invokes the top-level of the new thread (name kind of sucks)
+ */
+ void *run_undetached(void *arg);
+
+private:
+ // Neither d_mutex nor runtime->d_mutex may be held while calling this.
+ // It locks and unlocks them itself.
+ void set_state(worker_state_t state);
+};
+
+
+
+#endif /* INCLUDED_MB_WORKER_H */
diff --git a/mblock/src/lib/mbi_runtime_lock.h b/mblock/src/lib/mbi_runtime_lock.h
index 3138a7e1e..4174f6d54 100644
--- a/mblock/src/lib/mbi_runtime_lock.h
+++ b/mblock/src/lib/mbi_runtime_lock.h
@@ -48,9 +48,9 @@
*/
class mbi_runtime_lock : boost::noncopyable {
- mb_runtime *d_rt;
+ mb_runtime_base *d_rt;
public:
- mbi_runtime_lock(mb_runtime *rt) : d_rt(rt) { d_rt->lock(); }
+ mbi_runtime_lock(mb_runtime_base *rt) : d_rt(rt) { d_rt->lock(); }
mbi_runtime_lock(mb_mblock_impl *mi) : d_rt(mi->runtime()) { d_rt->lock(); }
mbi_runtime_lock(mb_mblock *mb) : d_rt(mb->impl()->runtime()) { d_rt->lock(); }
~mbi_runtime_lock(void) { d_rt->unlock(); }
diff --git a/mblock/src/lib/qa_bitset.cc b/mblock/src/lib/qa_bitset.cc
new file mode 100644
index 000000000..0acda8232
--- /dev/null
+++ b/mblock/src/lib/qa_bitset.cc
@@ -0,0 +1,493 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <mb_mblock.h>
+#include <mb_protocol_class.h>
+#include <mb_message.h>
+#include <mb_class_registry.h>
+#include <iostream>
+#include <sstream>
+#include <bitset>
+
+static pmt_t s_in = pmt_intern("in");
+static pmt_t s_out = pmt_intern("out");
+static pmt_t s_data = pmt_intern("data");
+static pmt_t s_start = pmt_intern("start");
+static pmt_t s_send_batch = pmt_intern("send-batch");
+static pmt_t s_long0 = pmt_from_long(0);
+
+static std::string
+str(long x)
+{
+ std::ostringstream s;
+ s << x;
+ return s.str();
+}
+
+/*!
+ * \brief mblock used for QA.
+ *
+ * Messages arriving on "in" consist of a pair containing a (long)
+ * message number in the car, and a (long) bitmap in the cdr. For
+ * each message received on "in", a new message is sent on "out". The
+ * new message is the same format as the input, but the bitmap in
+ * the cdr has a "1" or'd into it that corresponds to the bit number
+ * specified in the constructor.
+ *
+ * The bitmap can be used by the ultimate receiver to confirm
+ * traversal of a set of blocks, if the blocks are assigned unique bit
+ * numbers.
+ */
+class qa_bitset : public mb_mblock
+{
+ mb_port_sptr d_in;
+ mb_port_sptr d_out;
+ int d_bitno;
+
+public:
+ qa_bitset(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ void handle_message(mb_message_sptr msg);
+};
+
+qa_bitset::qa_bitset(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_bitno = pmt_to_long(user_arg); // The bit we are to set
+
+ d_in = define_port("in", "qa-bitset", false, mb_port::EXTERNAL);
+ d_out = define_port("out", "qa-bitset", true, mb_port::EXTERNAL);
+}
+
+void
+qa_bitset::handle_message(mb_message_sptr msg)
+{
+ if (pmt_eq(msg->port_id(), s_in) && pmt_eq(msg->signal(), s_data)){
+ d_out->send(s_data,
+ pmt_cons(pmt_car(msg->data()),
+ pmt_from_long((1L << d_bitno) | pmt_to_long(pmt_cdr(msg->data())))));
+ }
+}
+
+REGISTER_MBLOCK_CLASS(qa_bitset);
+
+// ------------------------------------------------------------------------
+
+/*!
+ * \brief mblock used for QA. Compose two qa_bitset mblocks.
+ */
+class qa_bitset2 : public mb_mblock
+{
+ mb_port_sptr d_in;
+ mb_port_sptr d_out;
+
+public:
+ qa_bitset2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+};
+
+qa_bitset2::qa_bitset2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ long bitno = pmt_to_long(user_arg); // The bit we are to set
+
+ d_in = define_port("in", "qa-bitset", false, mb_port::RELAY);
+ d_out = define_port("out", "qa-bitset", true, mb_port::RELAY);
+
+ define_component("bs0", "qa_bitset", pmt_from_long(bitno));
+ define_component("bs1", "qa_bitset", pmt_from_long(bitno + 1));
+ connect("self", "in", "bs0", "in");
+ connect("bs0", "out", "bs1", "in");
+ connect("bs1", "out", "self", "out");
+}
+
+REGISTER_MBLOCK_CLASS(qa_bitset2);
+
+// ------------------------------------------------------------------------
+
+/*!
+ * \brief mblock used for QA. Compose two qa_bitset2 mblocks.
+ */
+class qa_bitset4 : public mb_mblock
+{
+ mb_port_sptr d_in;
+ mb_port_sptr d_out;
+
+public:
+ qa_bitset4(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+};
+
+qa_bitset4::qa_bitset4(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ long bitno = pmt_to_long(user_arg); // The bit we are to set
+
+ d_in = define_port("in", "qa-bitset", false, mb_port::RELAY);
+ d_out = define_port("out", "qa-bitset", true, mb_port::RELAY);
+
+ define_component("bs0", "qa_bitset2", pmt_from_long(bitno));
+ define_component("bs1", "qa_bitset2", pmt_from_long(bitno + 2));
+ connect("self", "in", "bs0", "in");
+ connect("bs0", "out", "bs1", "in");
+ connect("bs1", "out", "self", "out");
+}
+
+REGISTER_MBLOCK_CLASS(qa_bitset4);
+
+// ------------------------------------------------------------------------
+
+/*!
+ * \brief mblock used for QA. Compose two qa_bitset4 mblocks.
+ */
+class qa_bitset8 : public mb_mblock
+{
+ mb_port_sptr d_in;
+ mb_port_sptr d_out;
+
+public:
+ qa_bitset8(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+};
+
+qa_bitset8::qa_bitset8(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ long bitno = pmt_to_long(user_arg); // The bit we are to set
+
+ d_in = define_port("in", "qa-bitset", false, mb_port::RELAY);
+ d_out = define_port("out", "qa-bitset", true, mb_port::RELAY);
+
+ define_component("bs0", "qa_bitset4", pmt_from_long(bitno));
+ define_component("bs1", "qa_bitset4", pmt_from_long(bitno + 4));
+ connect("self", "in", "bs0", "in");
+ connect("bs0", "out", "bs1", "in");
+ connect("bs1", "out", "self", "out");
+}
+
+REGISTER_MBLOCK_CLASS(qa_bitset8);
+
+// ------------------------------------------------------------------------
+
+/*!
+ * \brief mblock used for QA. Compose two qa_bitset8 mblocks.
+ */
+class qa_bitset16 : public mb_mblock
+{
+ mb_port_sptr d_in;
+ mb_port_sptr d_out;
+
+public:
+ qa_bitset16(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+};
+
+qa_bitset16::qa_bitset16(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ long bitno = pmt_to_long(user_arg); // The bit we are to set
+
+ d_in = define_port("in", "qa-bitset", false, mb_port::RELAY);
+ d_out = define_port("out", "qa-bitset", true, mb_port::RELAY);
+
+ define_component("bs0", "qa_bitset8", pmt_from_long(bitno));
+ define_component("bs1", "qa_bitset8", pmt_from_long(bitno + 8));
+ connect("self", "in", "bs0", "in");
+ connect("bs0", "out", "bs1", "in");
+ connect("bs1", "out", "self", "out");
+}
+
+REGISTER_MBLOCK_CLASS(qa_bitset16);
+
+// ------------------------------------------------------------------------
+
+/*!
+ * \brief mblock used for QA. Compose two qa_bitset16 mblocks.
+ */
+class qa_bitset32 : public mb_mblock
+{
+ mb_port_sptr d_in;
+ mb_port_sptr d_out;
+
+public:
+ qa_bitset32(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+};
+
+qa_bitset32::qa_bitset32(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ long bitno = pmt_to_long(user_arg); // The bit we are to set
+
+ d_in = define_port("in", "qa-bitset", false, mb_port::RELAY);
+ d_out = define_port("out", "qa-bitset", true, mb_port::RELAY);
+
+ define_component("bs0", "qa_bitset16", pmt_from_long(bitno));
+ define_component("bs1", "qa_bitset16", pmt_from_long(bitno + 16));
+ connect("self", "in", "bs0", "in");
+ connect("bs0", "out", "bs1", "in");
+ connect("bs1", "out", "self", "out");
+}
+
+REGISTER_MBLOCK_CLASS(qa_bitset32);
+
+// ------------------------------------------------------------------------
+
+class qa_bitset_src : public mb_mblock
+{
+ mb_port_sptr d_cs_top;
+ mb_port_sptr d_cs;
+
+ mb_port_sptr d_out;
+
+ long d_msg_number; // starting message number
+ long d_nmsgs_to_send; // # of messages to send
+ long d_batch_size; // # of messages to send per batch
+
+public:
+ qa_bitset_src(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ void handle_message(mb_message_sptr msg);
+
+protected:
+ void send_one();
+ void send_batch();
+};
+
+qa_bitset_src::qa_bitset_src(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_msg_number = pmt_to_long(pmt_nth(0, user_arg));
+ d_nmsgs_to_send = pmt_to_long(pmt_nth(1, user_arg));
+ d_batch_size = pmt_to_long(pmt_nth(2, user_arg));
+
+ d_cs_top = define_port("cs_top", "qa-bitset-cs", true, mb_port::EXTERNAL);
+ d_cs = define_port("cs", "qa-bitset-cs", true, mb_port::EXTERNAL);
+
+ d_out = define_port("out", "qa-bitset", true, mb_port::EXTERNAL);
+}
+
+void
+qa_bitset_src::handle_message(mb_message_sptr msg)
+{
+ if ((pmt_eq(msg->port_id(), d_cs_top->port_symbol())
+ || pmt_eq(msg->port_id(), d_cs->port_symbol()))
+ && pmt_eq(msg->signal(), s_send_batch)){
+ send_batch();
+ }
+}
+
+void
+qa_bitset_src::send_batch()
+{
+ for (int i = 0; i < d_batch_size; i++)
+ send_one();
+}
+
+void
+qa_bitset_src::send_one()
+{
+ if (d_nmsgs_to_send > 0){
+ pmt_t msg_number = pmt_from_long(d_msg_number++);
+ d_out->send(s_data, pmt_cons(msg_number, s_long0));
+ }
+ if (--d_nmsgs_to_send <= 0)
+ exit();
+}
+
+REGISTER_MBLOCK_CLASS(qa_bitset_src);
+
+// ------------------------------------------------------------------------
+
+class qa_bitset_sink : public mb_mblock
+{
+ // Maximum number of messages we can track
+ static const size_t MAX_MSGS = 1 * 1024 * 1024;
+
+ mb_port_sptr d_cs0;
+ mb_port_sptr d_cs1;
+ mb_port_sptr d_cs2;
+ mb_port_sptr d_cs3;
+
+ mb_port_sptr d_in0;
+ mb_port_sptr d_in1;
+ mb_port_sptr d_in2;
+ mb_port_sptr d_in3;
+
+ long d_nmsgs_to_recv; // # of messages to receive
+ long d_batch_size; // # of messages to receive per batch
+ uint32_t d_expected_mask;
+
+ std::bitset<MAX_MSGS> d_bitset;
+ long d_nrecvd;
+
+public:
+ qa_bitset_sink(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ void handle_message(mb_message_sptr msg);
+
+protected:
+ void receive_one(mb_message_sptr msg);
+};
+
+qa_bitset_sink::qa_bitset_sink(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_nrecvd(0)
+{
+ d_nmsgs_to_recv = pmt_to_long(pmt_nth(0, user_arg));
+ d_batch_size = pmt_to_long(pmt_nth(1, user_arg));
+ d_expected_mask = pmt_to_long(pmt_nth(2, user_arg));
+
+ if (d_nmsgs_to_recv > (long) MAX_MSGS)
+ throw std::out_of_range("qa_bitset_sink: nmsgs_to_recv is too big");
+
+ if (d_batch_size < 1)
+ throw std::out_of_range("qa_bitset_sink: batch_size must be >= 1");
+
+ d_cs0 = define_port("cs0", "qa-bitset-cs", true, mb_port::EXTERNAL);
+ d_cs1 = define_port("cs1", "qa-bitset-cs", true, mb_port::EXTERNAL);
+ d_cs2 = define_port("cs2", "qa-bitset-cs", true, mb_port::EXTERNAL);
+ d_cs3 = define_port("cs3", "qa-bitset-cs", true, mb_port::EXTERNAL);
+
+ d_in0 = define_port("in0", "qa-bitset", false, mb_port::EXTERNAL);
+ d_in1 = define_port("in1", "qa-bitset", false, mb_port::EXTERNAL);
+ d_in2 = define_port("in2", "qa-bitset", false, mb_port::EXTERNAL);
+ d_in3 = define_port("in3", "qa-bitset", false, mb_port::EXTERNAL);
+}
+
+void
+qa_bitset_sink::handle_message(mb_message_sptr msg)
+{
+ if ((pmt_eq(msg->port_id(), d_in0->port_symbol())
+ || pmt_eq(msg->port_id(), d_in1->port_symbol())
+ || pmt_eq(msg->port_id(), d_in2->port_symbol())
+ || pmt_eq(msg->port_id(), d_in3->port_symbol()))
+ && pmt_eq(msg->signal(), s_data)){
+
+ receive_one(msg);
+ }
+}
+
+void
+qa_bitset_sink::receive_one(mb_message_sptr msg)
+{
+ long msg_number = pmt_to_long(pmt_car(msg->data()));
+ uint32_t mask = pmt_to_long(pmt_cdr(msg->data()));
+
+ // std::cout << msg->data() << std::endl;
+
+ d_nrecvd++;
+ if (d_nrecvd % d_batch_size == d_batch_size - 1){
+ d_cs0->send(s_send_batch);
+ d_cs1->send(s_send_batch);
+ d_cs2->send(s_send_batch);
+ d_cs3->send(s_send_batch);
+ }
+
+ if (msg_number >= d_nmsgs_to_recv){
+ std::cerr << "qa_bitset_sink::receive_one: msg_number too big ("
+ << msg_number << ")\n";
+ shutdown_all(PMT_F);
+ return;
+ }
+ if (mask != d_expected_mask){
+ fprintf(stderr,
+ "qa_bitset_sink::receive_one: Wrong mask. Expected 0x%08x, got 0x%08x\n",
+ d_expected_mask, mask);
+ shutdown_all(PMT_F);
+ return;
+ }
+
+ if (d_bitset.test((size_t) msg_number)){
+ std::cerr << "qa_bitset_sink::receive_one: duplicate msg_number ("
+ << msg_number << ")\n";
+ shutdown_all(PMT_F);
+ return;
+ }
+
+ d_bitset.set((size_t) msg_number);
+ if (d_nrecvd == d_nmsgs_to_recv)
+ shutdown_all(PMT_T); // we're done!
+}
+
+REGISTER_MBLOCK_CLASS(qa_bitset_sink);
+
+// ------------------------------------------------------------------------
+
+class qa_bitset_top : public mb_mblock
+{
+ static const int NPIPES = 4;
+
+ std::vector<mb_port_sptr> d_cs;
+
+ long d_nmsgs; // # of messages to send
+ long d_batch_size; // # of messages to receive per batch
+
+public:
+ qa_bitset_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ void initial_transition();
+};
+
+qa_bitset_top::qa_bitset_top(mb_runtime *runtime,
+ const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_nmsgs = pmt_to_long(pmt_nth(0, user_arg));
+ d_nmsgs = (d_nmsgs / NPIPES) * NPIPES;
+ d_batch_size = pmt_to_long(pmt_nth(1, user_arg));
+
+ /*
+ * We build NPIPES sources which feed NPIPES pipelines, each of which
+ * consists of 8-mblocks. All pipelines feed into a single sink
+ * which keeps track the results.
+ */
+ for (int i = 0; i < NPIPES; i++){
+ d_cs.push_back(define_port("cs"+str(i), "qa-bitset-cs", false, mb_port::INTERNAL));
+
+ // sources of test messages
+ define_component("src"+str(i), "qa_bitset_src",
+ pmt_list3(pmt_from_long(i * d_nmsgs/NPIPES),
+ pmt_from_long(d_nmsgs/NPIPES),
+ pmt_from_long(d_batch_size)));
+
+ // 8-mblock processing pipelines
+ define_component("pipeline"+str(i), "qa_bitset8", pmt_from_long(0));
+ }
+
+ // sink for output of pipelines
+ define_component("sink", "qa_bitset_sink",
+ pmt_list3(pmt_from_long(d_nmsgs),
+ pmt_from_long(d_batch_size * NPIPES),
+ pmt_from_long(0x000000ff)));
+
+ for (int i = 0; i < NPIPES; i++){
+ connect("self", "cs"+str(i), "src"+str(i), "cs_top");
+ connect("src"+str(i), "out", "pipeline"+str(i), "in");
+ connect("src"+str(i), "cs", "sink", "cs"+str(i));
+ connect("pipeline"+str(i), "out", "sink", "in"+str(i));
+ }
+}
+
+void
+qa_bitset_top::initial_transition()
+{
+ for (int i = 0; i < NPIPES; i++){
+ d_cs[i]->send(s_send_batch); // prime the pump
+ d_cs[i]->send(s_send_batch);
+ }
+}
+
+REGISTER_MBLOCK_CLASS(qa_bitset_top);
diff --git a/mblock/src/lib/qa_bitset.mbh b/mblock/src/lib/qa_bitset.mbh
new file mode 100644
index 000000000..0b2df003e
--- /dev/null
+++ b/mblock/src/lib/qa_bitset.mbh
@@ -0,0 +1,61 @@
+;; -*- scheme -*- ; not really, but tells emacs how to format this
+;;
+;; 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.
+;;
+
+;; ----------------------------------------------------------------
+;; qa-bitset -- interface to mblock QA code
+;;
+
+(define-protocol-class qa-bitset
+
+ (:incoming
+
+ (data n bitmask)
+
+ )
+ )
+
+(define-protocol-class qa-bitset-cs
+
+ (:outgoing
+
+ (send-batch)
+
+ )
+ )
+
+;; ----------------------------------------------------------------
+;; qa-disconnect -- interface to mblock QA code
+;;
+
+(define-protocol-class qa-disconnect-cs
+
+ (:outgoing
+
+ (select-pipe n)
+
+ )
+
+ (:incoming
+
+ (ack n)
+
+ )
+ )
diff --git a/mblock/src/lib/qa_disconnect.cc b/mblock/src/lib/qa_disconnect.cc
new file mode 100644
index 000000000..cde8d6e5a
--- /dev/null
+++ b/mblock/src/lib/qa_disconnect.cc
@@ -0,0 +1,238 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <mb_mblock.h>
+#include <mb_protocol_class.h>
+#include <mb_message.h>
+#include <mb_class_registry.h>
+#include <iostream>
+#include <sstream>
+#include <bitset>
+
+static pmt_t s_in = pmt_intern("in");
+static pmt_t s_out = pmt_intern("out");
+static pmt_t s_data = pmt_intern("data");
+static pmt_t s_ack = pmt_intern("ack");
+static pmt_t s_select_pipe = pmt_intern("select-pipe");
+static pmt_t s_long0 = pmt_from_long(0);
+static pmt_t s_sys_port = pmt_intern("%sys-port");
+static pmt_t s_shutdown = pmt_intern("%shutdown");
+
+class qa_disconnect_mux : public mb_mblock
+{
+ mb_port_sptr d_in;
+ mb_port_sptr d_out;
+ mb_port_sptr d_cs;
+
+public:
+ qa_disconnect_mux(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+};
+
+qa_disconnect_mux::qa_disconnect_mux(mb_runtime *runtime,
+ const std::string &instance_name,
+ pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_in = define_port("in", "qa-bitset", false, mb_port::RELAY);
+ d_out = define_port("out", "qa-bitset", true, mb_port::RELAY);
+ d_cs = define_port("cs", "qa-disconnect-cs", true, mb_port::EXTERNAL);
+
+ define_component("pipeline0", "qa_bitset8", pmt_from_long(0));
+ define_component("pipeline1", "qa_bitset8", pmt_from_long(8));
+}
+
+void
+qa_disconnect_mux::initial_transition(){}
+
+void
+qa_disconnect_mux::handle_message(mb_message_sptr msg)
+{
+ if (pmt_eq(msg->port_id(), d_cs->port_symbol()) // select-pipe on cs
+ && pmt_eq(msg->signal(), s_select_pipe)){
+
+ long which_pipe = pmt_to_long(pmt_nth(0, msg->data()));
+
+ disconnect_component("pipeline0");
+ disconnect_component("pipeline1");
+
+ switch(which_pipe){
+
+ case 0:
+ connect("self", "in", "pipeline0", "in");
+ connect("self", "out", "pipeline0", "out");
+ break;
+
+ case 1:
+ connect("self", "in", "pipeline1", "in");
+ connect("self", "out", "pipeline1", "out");
+ break;
+ }
+
+ d_cs->send(s_ack, msg->data());
+ return;
+ }
+}
+
+REGISTER_MBLOCK_CLASS(qa_disconnect_mux);
+
+// ------------------------------------------------------------------------
+
+class qa_disconnect_top : public mb_mblock
+{
+ enum state_t {
+ UNINITIALIZED,
+ WAIT_FOR_ACK,
+ WAIT_FOR_DATA
+ };
+
+ state_t d_state;
+ int d_msg_number;
+ int d_nmsgs_to_send;
+
+ mb_port_sptr d_in;
+ mb_port_sptr d_out;
+ mb_port_sptr d_cs;
+
+ void check_pipe_send_next_msg();
+ void send_next_msg();
+ void select_pipe(int n);
+
+ // alternate pipes every 128 messages
+ static int which_pipe(int msg_number) { return (msg_number >> 7) & 0x1; }
+ bool time_to_switch() { return (d_msg_number & 0x7f) == 0; }
+
+public:
+ qa_disconnect_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+};
+
+qa_disconnect_top::qa_disconnect_top(mb_runtime *runtime,
+ const std::string &instance_name,
+ pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_state(UNINITIALIZED), d_msg_number(0)
+{
+ d_nmsgs_to_send = pmt_to_long(pmt_nth(0, user_arg));
+
+ d_in = define_port("in", "qa-bitset", false, mb_port::INTERNAL);
+ d_out = define_port("out", "qa-bitset", true, mb_port::INTERNAL);
+ d_cs = define_port("cs", "qa-disconnect-cs", false, mb_port::INTERNAL);
+
+ define_component("mux", "qa_disconnect_mux", PMT_F);
+
+ connect("self", "cs", "mux", "cs");
+ connect("self", "out", "mux", "in");
+ connect("self", "in", "mux", "out");
+}
+
+void
+qa_disconnect_top::initial_transition()
+{
+ check_pipe_send_next_msg();
+}
+
+void
+qa_disconnect_top::handle_message(mb_message_sptr msg)
+{
+ if (0)
+ std::cerr << "qa_disconnect_top::handle_msg state = "
+ << d_state << "\n msg = " << msg << std::endl;
+
+ if (pmt_eq(msg->port_id(), d_cs->port_symbol()) // ack on cs
+ && pmt_eq(msg->signal(), s_ack)
+ && d_state == WAIT_FOR_ACK){
+
+ send_next_msg();
+ return;
+ }
+
+ if (pmt_eq(msg->port_id(), d_in->port_symbol()) // data on in
+ && pmt_eq(msg->signal(), s_data)
+ && d_state == WAIT_FOR_DATA){
+
+ /*
+ * Confirm that msg passed through the pipe that we expect...
+ */
+ static const long expected_mask[2] = { 0x000000ff, 0x0000ff00 };
+
+ long msg_number = pmt_to_long(pmt_car(msg->data()));
+ long mask = pmt_to_long(pmt_cdr(msg->data()));
+
+ if (mask != expected_mask[which_pipe(msg_number)]){
+ fprintf(stderr, "\nqa_disconnect_top: wrong mask in msg_number = 0x%08lx\n",
+ msg_number);
+ fprintf(stderr, " expected = 0x%08lx, actual = 0x%08lx\n",
+ expected_mask[which_pipe(msg_number)], mask);
+ shutdown_all(PMT_F);
+ return;
+ }
+
+ if (msg_number == d_nmsgs_to_send - 1){ // we're done (and were successful)
+ shutdown_all(PMT_T);
+ return;
+ }
+
+ check_pipe_send_next_msg();
+ return;
+ }
+
+ if (pmt_eq(msg->port_id(), s_sys_port) // ignore %shutdown on %sys-port
+ && pmt_eq(msg->signal(), s_shutdown))
+ return;
+
+ std::cerr << "qa_disconnect_top: unhandled msg: state = "
+ << d_state << "\n msg = " << msg << std::endl;
+}
+
+void
+qa_disconnect_top::select_pipe(int n)
+{
+ d_cs->send(s_select_pipe, pmt_list1(pmt_from_long(n)));
+ d_state = WAIT_FOR_ACK;
+}
+
+void
+qa_disconnect_top::send_next_msg()
+{
+ d_state = WAIT_FOR_DATA;
+ if (d_msg_number == d_nmsgs_to_send) // we've sent all we're supposed to
+ return;
+
+ d_out->send(s_data, pmt_cons(pmt_from_long(d_msg_number), s_long0));
+ d_msg_number++;
+}
+
+void
+qa_disconnect_top::check_pipe_send_next_msg()
+{
+ if (time_to_switch())
+ select_pipe(which_pipe(d_msg_number));
+ else
+ send_next_msg();
+}
+
+REGISTER_MBLOCK_CLASS(qa_disconnect_top);
diff --git a/mblock/src/lib/qa_mblock.cc b/mblock/src/lib/qa_mblock.cc
index 4be4a23c3..cf4224544 100644
--- a/mblock/src/lib/qa_mblock.cc
+++ b/mblock/src/lib/qa_mblock.cc
@@ -27,6 +27,8 @@
#include <qa_mblock.h>
#include <qa_mblock_prims.h>
#include <qa_mblock_send.h>
+#include <qa_mblock_sys.h>
+#include <qa_timeouts.h>
CppUnit::TestSuite *
qa_mblock::suite()
@@ -35,6 +37,8 @@ qa_mblock::suite()
s->addTest (qa_mblock_prims::suite());
s->addTest (qa_mblock_send::suite());
+ s->addTest (qa_mblock_sys::suite());
+ s->addTest (qa_timeouts::suite());
return s;
}
diff --git a/mblock/src/lib/qa_mblock_prims.cc b/mblock/src/lib/qa_mblock_prims.cc
index 79ed5a21e..2995215fb 100644
--- a/mblock/src/lib/qa_mblock_prims.cc
+++ b/mblock/src/lib/qa_mblock_prims.cc
@@ -34,6 +34,7 @@
#include <mb_message.h>
#include <mb_mblock_impl.h>
#include <mb_msg_accepter.h>
+#include <mb_class_registry.h>
#include <stdio.h>
static pmt_t s_cs = pmt_intern("cs");
@@ -47,42 +48,49 @@ static pmt_t s_out = pmt_intern("out");
class dp_1 : public mb_mblock
{
public:
- dp_1();
+ dp_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
~dp_1();
};
-dp_1::dp_1()
+dp_1::dp_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
{
}
dp_1::~dp_1(){}
+REGISTER_MBLOCK_CLASS(dp_1);
+
// ----------------------------------------------------------------
class dp_2 : public mb_mblock
{
public:
- dp_2();
+ dp_2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
~dp_2();
};
-dp_2::dp_2()
+dp_2::dp_2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
{
define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);
}
dp_2::~dp_2(){}
+REGISTER_MBLOCK_CLASS(dp_2);
+
// ----------------------------------------------------------------
class dp_3 : public mb_mblock
{
public:
- dp_3();
+ dp_3(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
~dp_3();
};
-dp_3::dp_3()
+dp_3::dp_3(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
{
define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);
define_port("cs", "cs-protocol", false, mb_port::EXTERNAL); // duplicate def
@@ -90,19 +98,23 @@ dp_3::dp_3()
dp_3::~dp_3(){}
+REGISTER_MBLOCK_CLASS(dp_3);
+
// ----------------------------------------------------------------
void
qa_mblock_prims::test_define_ports()
{
- // std::vector<mb_port_sptr> intf;
-
- mb_mblock_sptr mb1 = mb_mblock_sptr(new dp_1());
- // intf = mb1->peer_interface();
- // CPPUNIT_ASSERT_EQUAL(size_t(0), intf.size());
+
+ mb_runtime_sptr rts = mb_make_runtime();
+ mb_runtime *rt = rts.get();
+
+ // Should work
+ mb_mblock_sptr mb1 = mb_mblock_sptr(new dp_1(rt, "top", PMT_F));
// raises runtime_error because of unknown protocol "cs-protocol"
- CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_2()), std::runtime_error);
+ CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_2(rt, "top", PMT_F)),
+ std::runtime_error);
// define the protocol class
pmt_t pc = mb_make_protocol_class(pmt_intern("cs-protocol"),
@@ -112,10 +124,11 @@ qa_mblock_prims::test_define_ports()
// std::cout << "pc = " << pc << '\n';
- mb_mblock_sptr mb2 = mb_mblock_sptr(new dp_2());
+ mb_mblock_sptr mb2 = mb_mblock_sptr(new dp_2(rt, "top", PMT_F));
// raises pmt_exception because of duplicate port definition of "cs"
- CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_3()), mbe_duplicate_port);
+ CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_3(rt, "top", PMT_F)),
+ mbe_duplicate_port);
}
// ================================================================
@@ -123,61 +136,74 @@ qa_mblock_prims::test_define_ports()
class dc_0 : public mb_mblock
{
public:
- dc_0();
+ dc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
~dc_0();
};
-dc_0::dc_0()
+dc_0::dc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
{
}
dc_0::~dc_0() {}
+REGISTER_MBLOCK_CLASS(dc_0);
+
// ----------------------------------------------------------------
class dc_ok : public mb_mblock
{
public:
- dc_ok();
+ dc_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
~dc_ok();
};
-dc_ok::dc_ok()
+dc_ok::dc_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
{
- 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()));
+ define_component("c0", "dc_0");
+ define_component("c1", "dc_0");
+ define_component("c2", "dc_0");
}
dc_ok::~dc_ok(){}
+REGISTER_MBLOCK_CLASS(dc_ok);
+
// ----------------------------------------------------------------
class dc_not_ok : public mb_mblock
{
public:
- dc_not_ok();
+ dc_not_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
~dc_not_ok();
};
-dc_not_ok::dc_not_ok()
- : mb_mblock()
+dc_not_ok::dc_not_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
{
- define_component("c0", mb_mblock_sptr(new dc_0()));
- define_component("c0", mb_mblock_sptr(new dc_0())); // duplicate name
+ define_component("c0", "dc_0");
+ define_component("c0", "dc_0"); // duplicate name
}
dc_not_ok::~dc_not_ok(){}
+REGISTER_MBLOCK_CLASS(dc_not_ok);
+
// ----------------------------------------------------------------
void
qa_mblock_prims::test_define_components()
{
- mb_mblock_sptr mb1 = mb_mblock_sptr(new dc_ok()); // OK
+ mb_runtime_sptr rts = mb_make_runtime();
+ mb_runtime *rt = rts.get();
+
+ // Should work
+ mb_mblock_sptr mb1 = mb_mblock_sptr(new dc_ok(rt, "top", PMT_F));
// raises pmt_exception because of duplicate component definition of "c0"
- CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dc_not_ok()), mbe_duplicate_component);
+ CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dc_not_ok(rt, "top", PMT_F)),
+ mbe_duplicate_component);
}
// ================================================================
@@ -185,7 +211,9 @@ qa_mblock_prims::test_define_components()
class tc_norm : public mb_mblock
{
public:
- tc_norm(){
+ tc_norm(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+ {
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);
@@ -197,22 +225,26 @@ public:
tc_norm::~tc_norm(){}
+REGISTER_MBLOCK_CLASS(tc_norm);
+
////////////////////////////////////////////////////////////////
class tc_0 : public mb_mblock
{
public:
- tc_0(){
+ tc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+ {
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()));
+ define_component("c0", "tc_norm");
+ define_component("c1", "tc_norm");
+ define_component("c2", "tc_norm");
+ define_component("c3", "tc_norm");
+ define_component("c4", "tc_norm");
+ define_component("c5", "tc_norm");
// OK
connect("c0", "norm", "c1", "conj");
@@ -284,14 +316,18 @@ public:
tc_0::~tc_0(){}
+REGISTER_MBLOCK_CLASS(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()));
+ tc_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+ {
+ define_component("c0", "tc_norm");
+ define_component("c1", "tc_norm");
connect("c0", "norm", "c1", "conj");
}
@@ -301,6 +337,8 @@ public:
tc_1::~tc_1(){}
+REGISTER_MBLOCK_CLASS(tc_1);
+
////////////////////////////////////////////////////////////////
void
@@ -315,7 +353,10 @@ qa_mblock_prims::test_connect()
pmt_list1(pmt_intern("in")), // in
pmt_list1(pmt_intern("out"))); // out
- mb_mblock_sptr mb0 = mb_mblock_sptr(new tc_0());
+ mb_runtime_sptr rts = mb_make_runtime();
+ mb_runtime *rt = rts.get();
+
+ mb_mblock_sptr mb0 = mb_mblock_sptr(new tc_0(rt, "top", PMT_F));
}
////////////////////////////////////////////////////////////////
@@ -377,11 +418,14 @@ qa_mblock_prims::test_msg_queue()
void
qa_mblock_prims::test_make_accepter()
{
+ mb_runtime_sptr rts = mb_make_runtime();
+ mb_runtime *rt = rts.get();
+
// create a block
- mb_mblock_sptr mb = mb_mblock_sptr(new dp_2());
+ mb_mblock_sptr mb = mb_mblock_sptr(new dp_2(rt, "top", PMT_F));
// use "internal use only" method...
- mb_msg_accepter_sptr accepter = mb->impl()->make_accepter("cs");
+ mb_msg_accepter_sptr accepter = mb->impl()->make_accepter(pmt_intern("cs"));
// Now push a few messages into it...
// signal data metadata pri
diff --git a/mblock/src/lib/qa_mblock_send.cc b/mblock/src/lib/qa_mblock_send.cc
index 46d6b6440..cd81709e2 100644
--- a/mblock/src/lib/qa_mblock_send.cc
+++ b/mblock/src/lib/qa_mblock_send.cc
@@ -35,6 +35,7 @@
#include <mb_message.h>
#include <mb_mblock_impl.h>
#include <mb_msg_accepter.h>
+#include <mb_class_registry.h>
#include <stdio.h>
static pmt_t s_data = pmt_intern("data");
@@ -57,6 +58,12 @@ define_protocol_classes()
}
+mb_mblock_sptr
+get_top(mb_runtime_sptr rts)
+{
+ return dynamic_cast<mb_runtime_nop *>(rts.get())->top();
+}
+
// ================================================================
// test_simple_routing
// ================================================================
@@ -70,12 +77,13 @@ class sr1 : public mb_mblock
mb_port_sptr d_p3;
public:
- sr1();
+ sr1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
~sr1();
- void init_fsm();
+ void initial_transition();
};
-sr1::sr1()
+sr1::sr1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
{
d_p1 = define_port("p1", "qa-send-cs", true, mb_port::EXTERNAL);
d_p2 = define_port("p2", "qa-send-cs", true, mb_port::EXTERNAL);
@@ -85,9 +93,9 @@ sr1::sr1()
sr1::~sr1(){}
void
-sr1::init_fsm()
+sr1::initial_transition()
{
- // std::cout << instance_name() << "[sr1]: init_fsm\n";
+ // std::cout << instance_name() << "[sr1]: initial_transition\n";
// send two messages to each port
pmt_t our_name = pmt_intern(instance_name());
@@ -98,6 +106,8 @@ sr1::init_fsm()
d_p2->send(s_status, pmt_list3(our_name, s_p2, pmt_from_long(1)));
}
+REGISTER_MBLOCK_CLASS(sr1);
+
// ----------------------------------------------------------------
// top-level container block for test_simple_routing
@@ -106,17 +116,18 @@ class sr0 : public mb_mblock
mb_port_sptr d_p0;
public:
- sr0();
+ sr0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
~sr0();
- void init_fsm();
+ void initial_transition();
};
-sr0::sr0()
+sr0::sr0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
{
d_p0 = define_port("p0", "qa-send-cs", false, mb_port::INTERNAL);
- define_component("mb1", mb_mblock_sptr(new sr1()));
- define_component("mb2", mb_mblock_sptr(new sr1()));
+ define_component("mb1", "sr1");
+ define_component("mb2", "sr1");
connect("self", "p0", "mb1", "p1");
connect("mb1", "p2", "mb2", "p3");
@@ -126,9 +137,9 @@ sr0::sr0()
sr0::~sr0(){}
void
-sr0::init_fsm()
+sr0::initial_transition()
{
- // std::cout << instance_name() << "[sr0]: init_fsm\n";
+ // std::cout << instance_name() << "[sr0]: initial_transition\n";
// send two messages to p0
pmt_t our_name = pmt_intern(instance_name());
@@ -136,6 +147,8 @@ sr0::init_fsm()
d_p0->send(s_control, pmt_list3(our_name, s_p0, pmt_from_long(1)));
}
+REGISTER_MBLOCK_CLASS(sr0);
+
// ----------------------------------------------------------------
/*
@@ -151,9 +164,10 @@ qa_mblock_send::test_simple_routing()
mb_message_sptr msg;
mb_runtime_sptr rt = mb_make_runtime_nop();
- mb_mblock_sptr mb0 = mb_mblock_sptr(new sr0());
- rt->run(mb0);
+ rt->run("top", "sr0", PMT_F);
+ mb_mblock_sptr mb0 = get_top(rt);
+
// Reach into the guts and see if the messages ended up where they should have
// mb0 should have received two messages sent from mb1 via its p1
@@ -238,12 +252,13 @@ class rr2 : public mb_mblock
mb_port_sptr d_p2;
public:
- rr2();
+ rr2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
~rr2();
- void init_fsm();
+ void initial_transition();
};
-rr2::rr2()
+rr2::rr2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
{
d_p1 = define_port("p1", "qa-send-cs", true, mb_port::EXTERNAL);
d_p2 = define_port("p2", "qa-send-cs", false, mb_port::EXTERNAL);
@@ -252,9 +267,9 @@ rr2::rr2()
rr2::~rr2(){}
void
-rr2::init_fsm()
+rr2::initial_transition()
{
- // std::cout << instance_name() << "[rr2]: init_fsm\n";
+ // std::cout << instance_name() << "[rr2]: initial_transition\n";
// send two messages via p1
pmt_t our_name = pmt_intern(instance_name());
@@ -262,6 +277,8 @@ rr2::init_fsm()
d_p1->send(s_status, pmt_list3(our_name, s_p1, pmt_from_long(1)));
}
+REGISTER_MBLOCK_CLASS(rr2);
+
// ----------------------------------------------------------------
// intermediate block for test_relay_routing
@@ -272,16 +289,17 @@ class rr1 : public mb_mblock
mb_port_sptr d_p2;
public:
- rr1();
+ rr1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
~rr1();
};
-rr1::rr1()
+rr1::rr1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
{
d_p1 = define_port("p1", "qa-send-cs", true, mb_port::RELAY);
d_p2 = define_port("p2", "qa-send-cs", false, mb_port::RELAY);
- define_component("c0", mb_mblock_sptr(new rr2()));
+ define_component("c0", "rr2");
connect("self", "p1", "c0", "p1");
connect("self", "p2", "c0", "p2");
@@ -289,6 +307,8 @@ rr1::rr1()
rr1::~rr1(){}
+REGISTER_MBLOCK_CLASS(rr1);
+
// ----------------------------------------------------------------
// top-level container for test_relay_routing
@@ -296,14 +316,15 @@ rr1::~rr1(){}
class rr0_a : public mb_mblock
{
public:
- rr0_a();
+ rr0_a(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
~rr0_a();
};
-rr0_a::rr0_a()
+rr0_a::rr0_a(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
{
- define_component("c0", mb_mblock_sptr(new rr1()));
- define_component("c1", mb_mblock_sptr(new rr2()));
+ define_component("c0", "rr1");
+ define_component("c1", "rr2");
connect("c0", "p1", "c1", "p2");
connect("c0", "p2", "c1", "p1");
@@ -311,6 +332,7 @@ rr0_a::rr0_a()
rr0_a::~rr0_a(){}
+REGISTER_MBLOCK_CLASS(rr0_a);
/*
* This tests basic message routing using RELAY and EXTERNAL ports.
@@ -323,8 +345,8 @@ qa_mblock_send::test_relay_routing_1()
mb_message_sptr msg;
mb_runtime_sptr rt = mb_make_runtime_nop();
- mb_mblock_sptr top = mb_mblock_sptr(new rr0_a());
- rt->run(top);
+ rt->run("top", "rr0_a", PMT_F);
+ mb_mblock_sptr top = get_top(rt);
// Reach into the guts and see if the messages ended up where they should have
@@ -377,14 +399,15 @@ qa_mblock_send::test_relay_routing_1()
class rr0_b : public mb_mblock
{
public:
- rr0_b();
+ rr0_b(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
~rr0_b();
};
-rr0_b::rr0_b()
+rr0_b::rr0_b(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
{
- define_component("c0", mb_mblock_sptr(new rr1()));
- define_component("c1", mb_mblock_sptr(new rr1()));
+ define_component("c0", "rr1");
+ define_component("c1", "rr1");
connect("c0", "p1", "c1", "p2");
connect("c0", "p2", "c1", "p1");
@@ -392,6 +415,7 @@ rr0_b::rr0_b()
rr0_b::~rr0_b(){}
+REGISTER_MBLOCK_CLASS(rr0_b);
/*
* This tests basic message routing using RELAY and EXTERNAL ports.
@@ -404,8 +428,8 @@ qa_mblock_send::test_relay_routing_2()
mb_message_sptr msg;
mb_runtime_sptr rt = mb_make_runtime_nop();
- mb_mblock_sptr top = mb_mblock_sptr(new rr0_b());
- rt->run(top);
+ rt->run("top", "rr0_b", PMT_F);
+ mb_mblock_sptr top = get_top(rt);
// Reach into the guts and see if the messages ended up where they should have
diff --git a/mblock/src/lib/qa_mblock_sys.cc b/mblock/src/lib/qa_mblock_sys.cc
new file mode 100644
index 000000000..a64f546c7
--- /dev/null
+++ b/mblock/src/lib/qa_mblock_sys.cc
@@ -0,0 +1,271 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006,2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qa_mblock_sys.h>
+#include <cppunit/TestAssert.h>
+#include <mb_mblock.h>
+#include <mb_runtime.h>
+#include <mb_runtime_nop.h> // QA only
+#include <mb_protocol_class.h>
+#include <mb_exception.h>
+#include <mb_msg_queue.h>
+#include <mb_message.h>
+#include <mb_mblock_impl.h>
+#include <mb_msg_accepter.h>
+#include <mb_class_registry.h>
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+
+
+static pmt_t s_data = pmt_intern("data");
+static pmt_t s_status = pmt_intern("status");
+static pmt_t s_control = pmt_intern("control");
+static pmt_t s_p0 = pmt_intern("p0");
+static pmt_t s_p1 = pmt_intern("p1");
+static pmt_t s_p2 = pmt_intern("p2");
+static pmt_t s_p3 = pmt_intern("p3");
+static pmt_t s_e1 = pmt_intern("e1");
+static pmt_t s_r1 = pmt_intern("r1");
+
+static void
+define_protocol_classes()
+{
+ mb_make_protocol_class(s_data, // name
+ pmt_list1(s_data), // incoming
+ pmt_list1(s_data)); // outgoing
+}
+
+
+// ================================================================
+// test_sys_1
+// ================================================================
+
+class sys_1 : public mb_mblock
+{
+ pmt_t d_user_arg;
+ mb_port_sptr d_data;
+
+public:
+ sys_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~sys_1();
+ void initial_transition();
+};
+
+sys_1::sys_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_user_arg(user_arg)
+{
+ d_data = define_port("data", "data", true, mb_port::EXTERNAL);
+}
+
+sys_1::~sys_1(){}
+
+void
+sys_1::initial_transition()
+{
+ shutdown_all(d_user_arg);
+}
+
+REGISTER_MBLOCK_CLASS(sys_1);
+
+void
+qa_mblock_sys::test_sys_1()
+{
+ define_protocol_classes();
+
+ pmt_t result;
+ pmt_t n1 = pmt_from_long(1);
+ pmt_t n2 = pmt_from_long(2);
+
+ mb_runtime_sptr rt1 = mb_make_runtime();
+
+#if 0
+ try {
+ rt1->run("top-1", "sys_1", n1, &result);
+ }
+ catch (omni_thread_fatal e){
+ std::cerr << "caught omni_thread_fatal: error = " << e.error
+ << ": " << strerror(e.error) << std::endl;
+ }
+ catch (omni_thread_invalid){
+ std::cerr << "caught omni_thread_invalid\n";
+ }
+#else
+ rt1->run("top-1", "sys_1", n1, &result);
+#endif
+ CPPUNIT_ASSERT(pmt_equal(n1, result));
+
+ // Execute run a second time, with the same rt, to ensure sanity.
+ rt1->run("top-2", "sys_1", n2, &result);
+ CPPUNIT_ASSERT(pmt_equal(n2, result));
+}
+
+// ================================================================
+// test_sys_2
+// ================================================================
+
+class squarer : public mb_mblock
+{
+ mb_port_sptr d_data;
+
+public:
+ squarer(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+
+ void handle_message(mb_message_sptr msg);
+};
+
+squarer::squarer(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_data = define_port("data", "data", true, mb_port::EXTERNAL);
+}
+
+void
+squarer::handle_message(mb_message_sptr msg)
+{
+ if (!pmt_eq(msg->signal(), s_data)) // we only handle the "data" message
+ return;
+
+ // long x -> (long x . long (x * x))
+
+ pmt_t x_pmt = msg->data();
+ long x = pmt_to_long(x_pmt);
+ d_data->send(s_data, pmt_cons(x_pmt, pmt_from_long(x * x)));
+}
+
+REGISTER_MBLOCK_CLASS(squarer);
+
+// ----------------------------------------------------------------
+
+class sys_2 : public mb_mblock
+{
+ mb_port_sptr d_data;
+
+public:
+ sys_2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+};
+
+sys_2::sys_2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_data = define_port("data", "data", true, mb_port::INTERNAL);
+ define_component("squarer", "squarer");
+ connect("self", "data", "squarer", "data");
+}
+
+void
+sys_2::initial_transition()
+{
+ // FIXME start timer to detect general failure
+
+ d_data->send(s_data, pmt_from_long(0)); // send initial message
+}
+
+void
+sys_2::handle_message(mb_message_sptr msg)
+{
+ if (!pmt_eq(msg->signal(), s_data)) // we only handle the "data" message
+ return;
+
+ // first check correctness of message
+
+ long x = pmt_to_long(pmt_car(msg->data()));
+ long y = pmt_to_long(pmt_cdr(msg->data()));
+
+ // std::cout << msg->data() << std::endl;
+
+ if (y != x * x){
+ std::cerr << "sys_2::handle_message: Expected y == x * x. Got y = "
+ << y << " for x = " << x << std::endl;
+
+ shutdown_all(PMT_F); // failed
+ }
+
+ if (x == 100)
+ shutdown_all(PMT_T); // done, OK
+ else
+ d_data->send(s_data, pmt_from_long(x + 1)); // send next request
+}
+
+REGISTER_MBLOCK_CLASS(sys_2);
+
+// ----------------------------------------------------------------
+
+void
+qa_mblock_sys::test_sys_2()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ // std::cerr << "qa_mblock_sys::test_sys_2 (enter)\n";
+
+ rt->run("top-sys-2", "sys_2", PMT_F, &result);
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
+
+// ================================================================
+// test_bitset_1
+// ================================================================
+
+void
+qa_mblock_sys::test_bitset_1()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ long nmsgs = 1000;
+ long batch_size = 8;
+
+ pmt_t arg = pmt_list2(pmt_from_long(nmsgs), // # of messages to send through pipe
+ pmt_from_long(batch_size));
+
+ rt->run("top", "qa_bitset_top", arg, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
+
+// ================================================================
+// test_disconnect
+// ================================================================
+
+void
+qa_mblock_sys::test_disconnect()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ long nmsgs = 10240;
+
+ pmt_t arg = pmt_list1(pmt_from_long(nmsgs)); // # of messages to send through pipe
+
+
+ rt->run("top", "qa_disconnect_top", arg, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
diff --git a/mblock/src/lib/qa_mblock_sys.h b/mblock/src/lib/qa_mblock_sys.h
new file mode 100644
index 000000000..87333818e
--- /dev/null
+++ b/mblock/src/lib/qa_mblock_sys.h
@@ -0,0 +1,45 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006,2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef INCLUDED_QA_MBLOCK_SYS_H
+#define INCLUDED_QA_MBLOCK_SYS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+class qa_mblock_sys : public CppUnit::TestCase {
+
+ CPPUNIT_TEST_SUITE(qa_mblock_sys);
+ CPPUNIT_TEST(test_sys_1);
+ CPPUNIT_TEST(test_sys_2);
+ CPPUNIT_TEST(test_bitset_1);
+ CPPUNIT_TEST(test_disconnect);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ void test_sys_1();
+ void test_sys_2();
+ void test_bitset_1();
+ void test_disconnect();
+};
+
+#endif /* INCLUDED_QA_MBLOCK_SYS_H */
+
diff --git a/mblock/src/lib/qa_timeouts.cc b/mblock/src/lib/qa_timeouts.cc
new file mode 100644
index 000000000..4439b6e8f
--- /dev/null
+++ b/mblock/src/lib/qa_timeouts.cc
@@ -0,0 +1,292 @@
+/* -*- 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 <qa_timeouts.h>
+#include <cppunit/TestAssert.h>
+#include <mb_mblock.h>
+#include <mb_runtime.h>
+#include <mb_protocol_class.h>
+#include <mb_exception.h>
+#include <mb_msg_queue.h>
+#include <mb_message.h>
+#include <mb_mblock_impl.h>
+#include <mb_msg_accepter.h>
+#include <mb_class_registry.h>
+#include <mb_timer_queue.h>
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+
+
+static pmt_t s_timeout = pmt_intern("%timeout");
+static pmt_t s_done = pmt_intern("done");
+
+
+// ------------------------------------------------------------------------
+// Exercise the priority queue used to implement timeouts.
+// ------------------------------------------------------------------------
+void
+qa_timeouts::test_timer_queue()
+{
+ mb_timer_queue tq;
+ mb_msg_accepter_sptr accepter;
+
+ mb_timeout_sptr t1000_000 =
+ mb_timeout_sptr(new mb_timeout(mb_time(1000,0), PMT_F, accepter));
+
+ mb_timeout_sptr t2000_000 =
+ mb_timeout_sptr(new mb_timeout(mb_time(2000,0), PMT_F, accepter));
+
+ mb_timeout_sptr t3000_000 =
+ mb_timeout_sptr(new mb_timeout(mb_time(3000,0), PMT_F, accepter));
+
+ mb_timeout_sptr t3000_125 =
+ mb_timeout_sptr(new mb_timeout(mb_time(3000,125), PMT_F, accepter));
+
+ mb_timeout_sptr t3000_250 =
+ mb_timeout_sptr(new mb_timeout(mb_time(3000,250), PMT_F, accepter));
+
+ mb_timeout_sptr t4000_000 =
+ mb_timeout_sptr(new mb_timeout(mb_time(4000,0), PMT_F, accepter));
+
+ // insert in pseudo-random order
+
+ tq.push(t3000_125);
+ tq.push(t1000_000);
+ tq.push(t4000_000);
+ tq.push(t3000_250);
+ tq.push(t2000_000);
+ tq.push(t3000_000);
+
+ CPPUNIT_ASSERT_EQUAL(t1000_000, tq.top());
+ tq.pop();
+
+ CPPUNIT_ASSERT_EQUAL(t2000_000, tq.top());
+ tq.pop();
+
+ CPPUNIT_ASSERT_EQUAL(t3000_000, tq.top());
+ tq.pop();
+
+ CPPUNIT_ASSERT_EQUAL(t3000_125, tq.top());
+ tq.pop();
+
+ CPPUNIT_ASSERT_EQUAL(t3000_250, tq.top());
+ tq.pop();
+
+ CPPUNIT_ASSERT_EQUAL(t4000_000, tq.top());
+ tq.pop();
+
+ CPPUNIT_ASSERT(tq.empty());
+
+ // insert in pseudo-random order
+
+ tq.push(t3000_000);
+ tq.push(t4000_000);
+ tq.push(t3000_125);
+ tq.push(t1000_000);
+ tq.push(t2000_000);
+ tq.push(t3000_250);
+
+ tq.cancel(t1000_000->handle());
+
+ CPPUNIT_ASSERT_EQUAL(t2000_000, tq.top());
+ tq.pop();
+
+ CPPUNIT_ASSERT_EQUAL(t3000_000, tq.top());
+ tq.pop();
+
+ tq.cancel(t3000_250->handle());
+
+ CPPUNIT_ASSERT_EQUAL(t3000_125, tq.top());
+ tq.pop();
+
+ CPPUNIT_ASSERT_EQUAL(t4000_000, tq.top());
+ tq.pop();
+
+ CPPUNIT_ASSERT(tq.empty());
+}
+
+// ------------------------------------------------------------------------
+// Test one-shot timeouts
+// ------------------------------------------------------------------------
+
+// FWIW, on SuSE 10.1 for x86-64, clock_getres returns 0.004 seconds.
+
+#define TIMING_MARGIN 0.010 // seconds
+
+class qa_timeouts_1_top : public mb_mblock
+{
+ int d_nleft;
+ int d_nerrors;
+ mb_time d_t0;
+
+public:
+ qa_timeouts_1_top(mb_runtime *runtime,
+ const std::string &instance_name, pmt_t user_arg);
+
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+};
+
+qa_timeouts_1_top::qa_timeouts_1_top(mb_runtime *runtime,
+ const std::string &instance_name,
+ pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_nleft(0), d_nerrors(0)
+{
+}
+
+void
+qa_timeouts_1_top::initial_transition()
+{
+ d_t0 = mb_time::time(); // now
+
+ schedule_one_shot_timeout(d_t0 + 0.200, pmt_from_double(0.200));
+ schedule_one_shot_timeout(d_t0 + 0.125, pmt_from_double(0.125));
+ schedule_one_shot_timeout(d_t0 + 0.075, pmt_from_double(0.075));
+ schedule_one_shot_timeout(d_t0 + 0.175, pmt_from_double(0.175));
+
+ d_nleft = 4;
+}
+
+void
+qa_timeouts_1_top::handle_message(mb_message_sptr msg)
+{
+ if (pmt_eq(msg->signal(), s_timeout)){
+ mb_time t_now = mb_time::time();
+ double expected_delta_t = pmt_to_double(msg->data());
+ double actual_delta_t = (t_now - d_t0).double_time();
+ double delta = expected_delta_t - actual_delta_t;
+
+ if (fabs(delta) > TIMING_MARGIN){
+ std::cerr << "qa_timeouts_1_top: expected_delta_t = " << expected_delta_t
+ << " actual_delta_t = " << actual_delta_t << std::endl;
+ d_nerrors++;
+ }
+
+ if (--d_nleft <= 0)
+ shutdown_all(d_nerrors == 0 ? PMT_T : PMT_F);
+ }
+}
+
+REGISTER_MBLOCK_CLASS(qa_timeouts_1_top);
+
+void
+qa_timeouts::test_timeouts_1()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ rt->run("top", "qa_timeouts_1_top", PMT_F, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
+
+// ------------------------------------------------------------------------
+// Test periodic timeouts
+// ------------------------------------------------------------------------
+
+class qa_timeouts_2_top : public mb_mblock
+{
+ int d_nhandled;
+ int d_nerrors;
+ double d_delta_t;
+ mb_time d_t0;
+
+public:
+ qa_timeouts_2_top(mb_runtime *runtime,
+ const std::string &instance_name, pmt_t user_arg);
+
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+};
+
+qa_timeouts_2_top::qa_timeouts_2_top(mb_runtime *runtime,
+ const std::string &instance_name,
+ pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg),
+ d_nhandled(0), d_nerrors(0), d_delta_t(0.075)
+{
+}
+
+void
+qa_timeouts_2_top::initial_transition()
+{
+ d_t0 = mb_time::time(); // now
+
+ schedule_periodic_timeout(d_t0 + d_delta_t, mb_time(d_delta_t), PMT_T);
+}
+
+void
+qa_timeouts_2_top::handle_message(mb_message_sptr msg)
+{
+ static const int NMSGS_TO_HANDLE = 5;
+
+ if (pmt_eq(msg->signal(), s_timeout)
+ && !pmt_eq(msg->data(), s_done)){
+
+ mb_time t_now = mb_time::time();
+
+ d_nhandled++;
+
+ double expected_delta_t = d_delta_t * d_nhandled;
+ double actual_delta_t = (t_now - d_t0).double_time();
+ double delta = expected_delta_t - actual_delta_t;
+
+ if (fabs(delta) > TIMING_MARGIN){
+ std::cerr << "qa_timeouts_2_top: expected_delta_t = " << expected_delta_t
+ << " actual_delta_t = " << actual_delta_t << std::endl;
+ d_nerrors++;
+ }
+
+ if (d_nhandled == NMSGS_TO_HANDLE){
+ cancel_timeout(msg->metadata()); // test cancel_timeout...
+ schedule_one_shot_timeout(d_t0 + (d_delta_t * (d_nhandled + 2)), s_done);
+ }
+ }
+
+ if (pmt_eq(msg->signal(), s_timeout)
+ && pmt_eq(msg->data(), s_done)){
+ if (d_nhandled != NMSGS_TO_HANDLE){
+ std::cerr << "qa_timeouts_2_top: d_nhandled = " << d_nhandled
+ << " expected d_nhandled = " << NMSGS_TO_HANDLE
+ << " (cancel_timeout didn't work)\n";
+ d_nerrors++;
+ }
+ shutdown_all(d_nerrors == 0 ? PMT_T : PMT_F);
+ }
+}
+
+REGISTER_MBLOCK_CLASS(qa_timeouts_2_top);
+
+void
+qa_timeouts::test_timeouts_2()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_NIL;
+
+ rt->run("top", "qa_timeouts_2_top", PMT_F, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
diff --git a/mblock/src/lib/qa_timeouts.h b/mblock/src/lib/qa_timeouts.h
new file mode 100644
index 000000000..736c4c2d9
--- /dev/null
+++ b/mblock/src/lib/qa_timeouts.h
@@ -0,0 +1,43 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006,2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef INCLUDED_QA_TIMEOUTS_H
+#define INCLUDED_QA_TIMEOUTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+class qa_timeouts : public CppUnit::TestCase {
+
+ CPPUNIT_TEST_SUITE(qa_timeouts);
+ CPPUNIT_TEST(test_timer_queue);
+ CPPUNIT_TEST(test_timeouts_1);
+ CPPUNIT_TEST(test_timeouts_2);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ void test_timer_queue();
+ void test_timeouts_1();
+ void test_timeouts_2();
+};
+
+#endif /* INCLUDED_QA_TIMEOUTS_H */
+
diff --git a/mblock/src/scheme/Makefile.am b/mblock/src/scheme/Makefile.am
new file mode 100644
index 000000000..7700a1fc0
--- /dev/null
+++ b/mblock/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/mblock/src/scheme/gnuradio/Makefile.am b/mblock/src/scheme/gnuradio/Makefile.am
new file mode 100644
index 000000000..f217f6852
--- /dev/null
+++ b/mblock/src/scheme/gnuradio/Makefile.am
@@ -0,0 +1,19 @@
+#
+# 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.
+#
diff --git a/mblock/src/scheme/gnuradio/compile-mbh.scm b/mblock/src/scheme/gnuradio/compile-mbh.scm
new file mode 100755
index 000000000..fbad90d7a
--- /dev/null
+++ b/mblock/src/scheme/gnuradio/compile-mbh.scm
@@ -0,0 +1,231 @@
+#!/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.
+;;
+
+;; usage: compile-mbh <input-file> <output-file>
+
+(use-modules (ice-9 getopt-long))
+(use-modules (ice-9 format))
+(use-modules (ice-9 pretty-print))
+;(use-modules (ice-9 slib))
+(use-modules (gnuradio pmt-serialize))
+(use-modules (gnuradio macros-etc))
+
+(debug-enable 'backtrace)
+
+;; ----------------------------------------------------------------
+
+(define (main args)
+
+ (define (usage)
+ (format 0 "usage: ~a input-file output-file~%" (car args)))
+
+ (when (not (= (length args) 3))
+ (usage)
+ (exit 1))
+
+ (let ((input-filename (cadr args))
+ (output-filename (caddr args)))
+ (if (compile-mbh-file input-filename output-filename)
+ (exit 0)
+ (exit 1))))
+
+
+;; ----------------------------------------------------------------
+;; constructor and accessors for protocol-class
+
+(define %protocol-class-tag (string->symbol "[PROTOCOL-CLASS-TAG]"))
+
+(define (make-protocol-class name incoming outgoing)
+ (vector %protocol-class-tag name incoming outgoing))
+
+(define (protocol-class? obj)
+ (and (vector? obj) (eq? %protocol-class-tag (vector-ref obj 0))))
+
+(define (protocol-class-name pc)
+ (vector-ref pc 1))
+
+(define (protocol-class-incoming pc)
+ (vector-ref pc 2))
+
+(define (protocol-class-outgoing pc)
+ (vector-ref pc 3))
+
+
+;; ----------------------------------------------------------------
+
+(define (syntax-error msg e)
+ (throw 'syntax-error msg e))
+
+(define (unrecognized-form form)
+ (syntax-error "Unrecognized form" form))
+
+
+(define (mbh-chk-length= e y n)
+ (cond ((and (null? y)(zero? n))
+ #f)
+ ((null? y)
+ (syntax-error "Expression has too few subexpressions" e))
+ ((atom? y)
+ (syntax-error (if (atom? e)
+ "List expected"
+ "Expression ends with `dotted' atom")
+ e))
+ ((zero? n)
+ (syntax-error "Expression has too many subexpressions" e))
+ (else
+ (mbh-chk-length= e (cdr y) (- n 1)))))
+
+(define (mbh-chk-length>= e y n)
+ (cond ((and (null? y)(< n 1))
+ #f)
+ ((atom? y)
+ (mbh-chk-length= e y -1))
+ (else
+ (mbh-chk-length>= e (cdr y) (- n 1)))))
+
+
+(define (compile-mbh-file input-filename output-filename)
+ (let ((i-port (open-input-file input-filename))
+ (o-port (open-output-file output-filename)))
+
+ (letrec
+ ((protocol-classes '()) ; alist
+
+ (lookup-protocol-class ; returns protocol-class or #f
+ (lambda (name)
+ (cond ((assq name protocol-classes) => cdr)
+ (else #f))))
+
+ (register-protocol-class
+ (lambda (pc)
+ (set! protocol-classes (acons (protocol-class-name pc)
+ pc protocol-classes))
+ pc))
+
+ (parse-top-level-form
+ (lambda (form)
+ (mbh-chk-length>= form form 1)
+ (case (car form)
+ ((define-protocol-class) (parse-define-protocol-class form))
+ (else (syntax-error form)))))
+
+ (parse-define-protocol-class
+ (lambda (form)
+ (mbh-chk-length>= form form 2)
+ ;; form => (define-protocol-class name
+ ;; (:include protocol-class-name)
+ ;; (:incoming list-of-msgs)
+ ;; (:outgoing list-of-msgs))
+ (let ((name (cadr form))
+ (incoming '())
+ (outgoing '()))
+ (if (lookup-protocol-class name)
+ (syntax-error "Duplicate protocol-class name" name))
+ (for-each
+ (lambda (sub-form)
+ (mbh-chk-length>= sub-form sub-form 1)
+ (case (car sub-form)
+ ((:include)
+ (mbh-chk-length>= sub-form sub-form 2)
+ (cond ((lookup-protocol-class (cadr sub-form)) =>
+ (lambda (pc)
+ (set! incoming (append incoming (protocol-class-incoming pc)))
+ (set! outgoing (append outgoing (protocol-class-outgoing pc)))))
+ (else
+ (syntax-error "Unknown protocol-class-name" (cadr sub-form)))))
+ ((:incoming)
+ (set! incoming (append incoming (cdr sub-form))))
+ ((:outgoing)
+ (set! outgoing (append outgoing (cdr sub-form))))
+ (else
+ (unrecognized-form (car sub-form)))))
+ (cddr form))
+
+ (register-protocol-class (make-protocol-class name incoming outgoing)))))
+
+ ) ; end of bindings
+
+ (for-each-in-file i-port parse-top-level-form)
+
+ ;; generate the output here...
+
+ (letrec ((classes (map cdr protocol-classes))
+ (so-stream (make-serial-output-stream))
+ (format-output-for-c++
+ (lambda (output)
+ (format o-port "//~%")
+ (format o-port "// Machine generated by compile-mbh from ~a~%" input-filename)
+ (format o-port "//~%")
+ (format o-port "// protocol-classes: ~{~a ~}~%" (map car protocol-classes))
+ (format o-port "//~%")
+
+ (format o-port "#include <mb_protocol_class.h>~%")
+ (format o-port "#include <unistd.h>~%")
+ (format o-port
+ "static const char~%protocol_class_init_data[~d] = {~% "
+ (length output))
+
+ (do ((lst output (cdr lst))
+ (i 0 (+ i 1)))
+ ((null? lst) #t)
+ (format o-port "~a, " (car lst))
+ (when (= 15 (modulo i 16))
+ (format o-port "~% ")))
+
+ (format o-port "~&};~%")
+ (format o-port "static mb_protocol_class_init _init_(protocol_class_init_data, sizeof(protocol_class_init_data));~%")
+ )))
+
+
+ (map (lambda (pc)
+ (let ((obj-to-dump
+ (list (protocol-class-name pc) ; class name
+ (map car (protocol-class-incoming pc)) ; incoming msg names
+ (map car (protocol-class-outgoing pc)) ; outgoing msg names
+ ;;(protocol-class-incoming pc) ; full incoming msg descriptions
+ ;;(protocol-class-outgoing pc) ; full outgoing msg descriptions
+ )))
+ ;;(pretty-print obj-to-dump)
+ (pmt-serialize obj-to-dump (so-stream 'put-byte))))
+ classes)
+
+ (format-output-for-c++ ((so-stream 'get-output)))
+
+ #t))))
+
+
+(define (make-serial-output-stream)
+ (letrec ((output '())
+ (put-byte
+ (lambda (byte)
+ (set! output (cons byte output))))
+ (get-output
+ (lambda ()
+ (reverse output))))
+ (lambda (key)
+ (case key
+ ((put-byte) put-byte)
+ ((get-output) get-output)
+ (else (error "Unknown key" key))))))
+
diff --git a/omnithread/omnithread.h b/omnithread/omnithread.h
index bd916561e..26e42b0e1 100644
--- a/omnithread/omnithread.h
+++ b/omnithread/omnithread.h
@@ -391,11 +391,15 @@ protected:
// execute the run() or run_undetached() member functions depending on
// whether start() or start_undetached() is called respectively.
+public:
+
void start_undetached(void);
// can be used with the above constructor in a derived class to cause
// the thread to be undetached. In this case the thread executes the
// run_undetached member function.
+protected:
+
virtual ~omni_thread(void);
// destructor cannot be called by user (except via a derived class).
// Use exit() or cancel() instead. This also means a thread object must
diff --git a/omnithread/posix.cc b/omnithread/posix.cc
index b82e86df3..7325166c6 100644
--- a/omnithread/posix.cc
+++ b/omnithread/posix.cc
@@ -51,6 +51,10 @@
#include <time.h>
#include <omnithread.h>
+#if (PthreadDraftVersion == 0)
+#error "PthreadDraftVersion not defined. If not sure, define it to 10"
+#endif
+
#ifdef HAVE_NANOSLEEP
#undef NoNanoSleep
#else
@@ -73,8 +77,14 @@
#endif
#endif
+#if 1
#define DB(x) // x
-//#include <iostream.h> or #include <iostream> if DB is on.
+#else
+#define DB(x) x
+#include <iostream>
+using std::cerr;
+using std::endl;
+#endif
#if (PthreadDraftVersion <= 6)
#define ERRNO(x) (((x) != 0) ? (errno) : 0)
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))))
diff --git a/usrp/doc/inband-signaling-usb-host b/usrp/doc/inband-signaling-usb-host
index ca306fe60..1a5d87073 100644
--- a/usrp/doc/inband-signaling-usb-host
+++ b/usrp/doc/inband-signaling-usb-host
@@ -18,241 +18,6 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
-This is preliminary design document on the organization of the host
-component of the USRP inband signaling implementation over USB.
-Assumptions: we'll have a single usrp_usb_daemon, implemented as an
-mblock, that will provide the high-level message based interface to
-the USRP. The daemon will handle all resource allocation, muxing and
-demuxing for the control and status messages from multiple clients.
-
-The underlying cross-process IPC mechanism is not yet specified.
-All communication will be via messages.
-
-The external interface to the usrp_usb_daemon will consist of two sets
-of replicated ports, one set for the transmit, and one set for
-receive.
-
-
-// ------------------------------------------------------------------------
-
-// Protocol class usrp_usb_common
-// Defined from client's point-of-view
-//
-// This protocol class is shared by the usrp_usb_tx and usrp_usb_rx
-// protocol classes
-
-// outgoing:
-
-cmd_allocate_channel(invocation_handle, channel, capacity_reservation)
-
-invocation_handle
-Type Handle
-Use The identifier provided by the client to tag the method invocation.
- The identifier will be returned with the response, to provide
- the client with a mechanism to match asynchronous responses with
- commands that generated them.
-
-channel
-Type integer
-Use Specifies the Tx channel to allocate
-
-capacity_reservation
-Type float, units are bytes/s
-Use Specifies the number of bytes/s of USB capacity to reserve for
- this channel.
-
-
-// incoming:
-
-response_allocate_channel(invocation_handle, status)
-
-Type Handle
-Use The identifier provided by the client in the prompting invocation.
- The identifier is returned with the response, so that the
- client has a mechanism to match asynchronous responses with
- commands that generated them. The value of the invocation_handle
- is opaque to the server, and is not required by the server to be unique.
-
-Type Status
-Use Contains the status code for the operation, per FIXME, and
- an optional message.
-
-Preconditions:
- a) None
-
-Postconditions:
- a) If successful, the requested channel and USB capacity are
- allocated for the client's exclusive use.
-
-
-// outgoing:
-
-cmd_deallocate_channel(invocation_handle, channel)
-
-invocation_handle
-Type Handle
-Use The identifier provided by the client to tag the method invocation.
- The identifier will be returned with the response, to provide
- the client with a mechanism to match asynchronous responses with
- commands that generated them.
-
-channel
-Type integer
-Use Specifies the Tx channel to deallocate
-
-
-// incoming:
-
-response_deallocate_channel(invocation_handle, status)
-
-Type Handle
-Use The identifier provided by the client in the prompting invocation.
- The identifier is returned with the response, so that the
- client has a mechanism to match asynchronous responses with
- commands that generated them. The value of the invocation_handle
- is opaque to the server, and is not required by the server to be unique.
-
-Type Status
-Use Contains the status code for the operation, per FIXME, and
- an optional message.
-
-Preconditions:
- a) None
-
-Postconditions:
- a) If successful, the requested channel and associated USB capacity
- are deallocated, and return to the pool of available resources.
-
-
-// ------------------------------------------------------------------------
-
-// Protocol class usrp_usb_tx inherits from usrp_usb_common
-// Defined from client's point-of-view
-
-// outgoing:
-
-cmd_xmit_raw_frame(invocation_handle, channel, samples, timestamp)
-
-invocation_handle
-Type Handle
-Use The identifier provided by the client to tag the method invocation.
- The identifier will be returned with the response, to provide
- the client with a mechanism to match asynchronous responses with
- commands that generated them.
-
-channel
-Type integer
-Use Specifies the channel that the frame of samples shall be transmitted on.
-
-samples
-Type homogenous vector of unsigned char
-Use These samples must already be in the appropriate format for parsing
- by the USRP FPGA. The required format depends on the
- configuration associated with this channel. No conversion of
- the samples takes place in this method. Samples will be split
- into multiple USB data packets as required for transport
- across the USB.
-
-timestamp
-Type 32-bit integer
-Use Specifies the time at which the first sample in samples
- shall be sent to the D/A converter. The format and
- interpretation of time is as specified in
- inband-signaling-usb.
-
-
-// incoming:
-
-response_xmit_raw_frame(invocation_handle, status)
-
-Type Handle
-Use The identifier provided by the client in the prompting invocation.
- The identifier is returned with the response, so that the
- client has a mechanism to match asynchronous responses with
- commands that generated them. The value of the invocation_handle
- is opaque to the server, and is not required by the server to be unique.
-
-Type Status
-Use Contains the status code for the operation, per FIXME, and
- an optional message.
-
-Preconditions:
- a) The specified channel is allocated to this client
-
-Postconditions:
- a) If successful, the samples of the frame have been queued for
- transmission to the USRP.
-
-
-// ------------------------------------------------------------------------
-
-// Protocol class usrp_usb_rx inherits from usrp_usb_common
-// Defined from client's point-of-view
-
-
-// outgoing:
-
-cmd_recv_raw_samples(invocation_handle, channel)
-
-invocation_handle
-Type Handle
-Use The identifier provided by the client to tag the method invocation.
- The identifier will be returned with the response, to provide
- the client with a mechanism to match asynchronous responses with
- commands that generated them.
-
-channel
-Type integer
-Use Specifies the channel that the samples shall be received from.
-
-The client may issue multiple cmd_recv_raw_samples commands to ensure
-an uninterrupted flow of samples. The appropriate number of
-outstanding cmds to issue is TBD, but is at least 2.
-
-[Discussion: I'm not sure if this is really the interface we want.
-We may want to provide an enable/disable method, and then just begin
-streaming samples. Or, we may wan to implement packet boundary
-detection in the FPGA, and then return a frame's worth of samples
-(potentially in multiple pieces).
-
-It may be that we need to different modes, one for packet based
-reception and one for continuous streaming.]
-
-
-// incoming:
-
-response_recv_raw_samples(invocation_handle, samples, timestamp, properties)
-
-Type Handle
-Use The identifier provided by the client in the prompting invocation.
- The identifier is returned with the response, so that the
- client has a mechanism to match asynchronous responses with
- commands that generated them. The value of the invocation_handle
- is opaque to the server, and is not required by the server to be unique.
-
-samples
-Type homogenous vector of unsigned char
-Use Samples as returned by the USRP FPGA. The format of the
- returned samples depends on the configuration associated with
- this channel. No conversion or unpacking of samples takes place in
- this method.
-
-timestamp
-Type 32-bit integer
-Use Specifies the time at which the first sample in samples
- was received from the A/D converter. The format and
- interpretation of time is as specified in
- inband-signaling-usb.
-
-properties
-Type Map
-Use Returns additional (key, value) pairs associated with the
- reception of these samples. In particular, the map may contain
- the Received Strength Signal Indication (RSSI) reported by the
- front end at the time the first sample was received from the A/D.
-
-// ------------------------------------------------------------------------
-
-To do: control and configuration messages...
+See usrp/host/lib/inband/usrp_server.mbh for interface
diff --git a/usrp/fpga/inband_lib/chan_fifo_reader.v b/usrp/fpga/inband_lib/chan_fifo_reader.v
new file mode 100755
index 000000000..2b3178da7
--- /dev/null
+++ b/usrp/fpga/inband_lib/chan_fifo_reader.v
@@ -0,0 +1,197 @@
+module chan_fifo_reader
+ ( input reset,
+ input tx_clock,
+ input tx_strobe,
+ input [31:0]adc_clock,
+ input [3:0] samples_format,
+ input [15:0] fifodata,
+ input pkt_waiting,
+ output reg rdreq,
+ output reg skip,
+ output reg [15:0]tx_q,
+ output reg [15:0]tx_i,
+ output reg overrun,
+ output reg underrun) ;
+
+ // Should not be needed if adc clock rate < tx clock rate
+ `define JITTER 5
+
+ //Samples format
+ // 16 bits interleaved complex samples
+ `define QI16 4'b0
+
+ // States
+ `define IDLE 4'd0
+ `define READ 4'd1
+ `define HEADER1 4'd2
+ `define HEADER2 4'd3
+ `define TIMESTAMP1 4'd4
+ `define TIMESTAMP2 4'd5
+ `define WAIT 4'd6
+ `define WAITSTROBE 4'd7
+ `define SENDWAIT 4'd8
+ `define SEND 4'd9
+ `define FEED 4'd10
+ `define DISCARD 4'd11
+
+ // State registers
+ reg[3:0] reader_state;
+ reg[3:0] reader_next_state;
+
+ //Variables
+ reg[8:0] payload_len;
+ reg[8:0] read_len;
+ reg[31:0] timestamp;
+ reg burst;
+ reg qsample;
+ always @(posedge tx_clock)
+ begin
+ if (reset)
+ begin
+ reader_state <= `IDLE;
+ reader_next_state <= `IDLE;
+ rdreq <= 0;
+ skip <= 0;
+ overrun <= 0;
+ underrun <= 0;
+ burst <= 0;
+ qsample <= 1;
+ end
+ else
+ begin
+ reader_state = reader_next_state;
+ case (reader_state)
+ `IDLE:
+ begin
+ if (pkt_waiting == 1)
+ begin
+ reader_next_state <= `READ;
+ rdreq <= 1;
+ underrun <= 0;
+ end
+ else if (burst == 1)
+ underrun <= 1;
+ end
+
+ // Just wait for the fifo data to arrive
+ `READ:
+ begin
+ reader_next_state <= `HEADER1;
+ end
+
+ // First part of the header
+ `HEADER1:
+ begin
+ reader_next_state <= `HEADER2;
+
+ //Check Start burst flag
+ if (fifodata[3] == 1)
+ burst <= 1;
+
+ if (fifodata[4] == 1)
+ burst <= 0;
+ end
+
+ // Read payload length
+ `HEADER2:
+ begin
+ payload_len <= (fifodata & 16'h1FF);
+ read_len <= 9'd0;
+ reader_next_state <= `TIMESTAMP1;
+ end
+
+ `TIMESTAMP1:
+ begin
+ timestamp <= {fifodata, 16'b0};
+ rdreq <= 0;
+ reader_next_state <= `TIMESTAMP2;
+ end
+
+ `TIMESTAMP2:
+ begin
+ timestamp <= timestamp + fifodata;
+ reader_next_state <= `WAIT;
+ end
+
+ // Decide if we wait, send or discard samples
+ `WAIT:
+ begin
+ // Wait a little bit more
+ if (timestamp > adc_clock + `JITTER)
+ reader_next_state <= `WAIT;
+ // Let's send it
+ else if ((timestamp < adc_clock + `JITTER
+ && timestamp > adc_clock)
+ || timestamp == 32'hFFFFFFFF)
+ begin
+ reader_next_state <= `WAITSTROBE;
+ end
+ // Outdated
+ else if (timestamp < adc_clock)
+ begin
+ reader_next_state <= `DISCARD;
+ skip <= 1;
+ end
+ end
+
+ // Wait for the transmit chain to be ready
+ `WAITSTROBE:
+ begin
+ // If end of payload...
+ if (read_len == payload_len)
+ begin
+ reader_next_state <= `DISCARD;
+ skip <= (payload_len < 508);
+ end
+
+ if (tx_strobe == 1)
+ reader_next_state <= `SENDWAIT;
+ end
+
+ `SENDWAIT:
+ begin
+ rdreq <= 1;
+ reader_next_state <= `SEND;
+ end
+
+ // Send the samples to the tx_chain
+ `SEND:
+ begin
+ reader_next_state <= `WAITSTROBE;
+ rdreq <= 0;
+ read_len <= read_len + 2;
+ case(samples_format)
+ `QI16:
+ begin
+ tx_q <= qsample ? fifodata : 16'bZ;
+ tx_i <= ~qsample ? fifodata : 16'bZ;
+ qsample <= ~ qsample;
+ end
+ default:
+ begin
+ // Assume 16 bits complex samples by default
+ $display ("Error unknown samples format");
+ tx_q <= qsample ? fifodata : 16'bZ;
+ tx_i <= ~qsample ? fifodata : 16'bZ;
+ qsample <= ~ qsample;
+ end
+ endcase
+ end
+
+ `DISCARD:
+ begin
+ skip <= 0;
+ reader_next_state <= `IDLE;
+ end
+
+ default:
+ begin
+ $display ("Error unknown state");
+ reader_state <= `IDLE;
+ reader_next_state <= `IDLE;
+ end
+ endcase
+ end
+ end
+
+endmodule \ No newline at end of file
diff --git a/usrp/fpga/inband_lib/data_packet_fifo.v b/usrp/fpga/inband_lib/data_packet_fifo.v
new file mode 100755
index 000000000..5b37b14ea
--- /dev/null
+++ b/usrp/fpga/inband_lib/data_packet_fifo.v
@@ -0,0 +1,128 @@
+module data_packet_fifo
+ ( input reset,
+ input clock,
+ input [15:0]ram_data_in,
+ input write_enable,
+ output reg have_space,
+ output reg [15:0]ram_data_out,
+ output reg pkt_waiting,
+ input read_enable,
+ input pkt_complete,
+ input skip_packet) ;
+
+ /* Some parameters for usage later on */
+ parameter DATA_WIDTH = 16 ;
+ parameter NUM_PACKETS = 4 ;
+
+ /* Create the RAM here */
+ reg [DATA_WIDTH-1:0] usb_ram [256*NUM_PACKETS-1:0] ;
+
+ /* Create the address signals */
+ reg [7:0] usb_ram_offset_out ;
+ reg [1:0] usb_ram_packet_out ;
+ reg [7:0] usb_ram_offset_in ;
+ reg [1:0] usb_ram_packet_in ;
+
+ wire [7-2+NUM_PACKETS:0] usb_ram_aout ;
+ wire [7-2+NUM_PACKETS:0] usb_ram_ain ;
+ reg isfull;
+
+ assign usb_ram_aout = {usb_ram_packet_out, usb_ram_offset_out} ;
+ assign usb_ram_ain = {usb_ram_packet_in, usb_ram_offset_in} ;
+
+ // Check if there is one full packet to process
+ always @(usb_ram_ain, usb_ram_aout)
+ begin
+ if (reset)
+ pkt_waiting <= 0;
+ else if (usb_ram_ain >= usb_ram_aout)
+ pkt_waiting <= usb_ram_ain - usb_ram_aout >= 256;
+ else
+ pkt_waiting <= (usb_ram_ain + 10'b1111111111 - usb_ram_aout) >= 256;
+ end
+
+ // Check if there is room
+ always @(usb_ram_ain, usb_ram_aout)
+ begin
+ if (reset)
+ have_space <= 1;
+ else if (usb_ram_ain == usb_ram_aout)
+ have_space <= ~isfull;
+ else if (usb_ram_ain > usb_ram_aout)
+ have_space <= (usb_ram_ain - usb_ram_aout) <= 256 * (NUM_PACKETS - 1);
+ else
+ have_space <= (usb_ram_aout - usb_ram_ain) >= 256;
+ end
+
+ /* RAM Write Address process */
+ always @(posedge clock)
+ begin
+ if( reset )
+ begin
+ usb_ram_offset_in <= 0 ;
+ usb_ram_packet_in <= 0 ;
+ end
+ else
+ if( pkt_complete )
+ begin
+ usb_ram_packet_in <= usb_ram_packet_in + 1;
+ usb_ram_offset_in <= 0;
+ end
+ else if( write_enable )
+ begin
+ if (usb_ram_offset_in == 8'b11111111)
+ begin
+ usb_ram_offset_in <= 0;
+ usb_ram_packet_in <= usb_ram_packet_in + 1;
+ end
+ else
+ usb_ram_offset_in <= usb_ram_offset_in + 1 ;
+ if (usb_ram_ain + 1 == usb_ram_aout)
+ isfull <= 1;
+ end
+ end
+
+ /* RAM Writing process */
+ always @(posedge clock)
+ begin
+ if( write_enable )
+ begin
+ usb_ram[usb_ram_ain] <= ram_data_in ;
+ end
+ end
+
+ /* RAM Read Address process */
+ always @(posedge clock)
+ begin
+ if( reset )
+ begin
+ usb_ram_packet_out <= 0 ;
+ usb_ram_offset_out <= 0 ;
+ isfull <= 0;
+ end
+ else
+ if( skip_packet )
+ begin
+ usb_ram_packet_out <= usb_ram_packet_out + 1 ;
+ usb_ram_offset_out <= 0 ;
+ end
+ else if(read_enable) begin
+ if( usb_ram_offset_out == 8'b11111111 )
+ begin
+ usb_ram_offset_out <= 0 ;
+ usb_ram_packet_out <= usb_ram_packet_out + 1 ;
+ end
+ else
+ usb_ram_offset_out <= usb_ram_offset_out + 1 ;
+ end
+ if (usb_ram_ain == usb_ram_aout)
+ isfull <= 0;
+ end
+
+ /* RAM Reading Process */
+ always @(posedge clock)
+ begin
+ ram_data_out <= usb_ram[usb_ram_aout] ;
+ end
+
+endmodule
diff --git a/usrp/fpga/inband_lib/tx_buffer_inband.v b/usrp/fpga/inband_lib/tx_buffer_inband.v
new file mode 100755
index 000000000..56c07807a
--- /dev/null
+++ b/usrp/fpga/inband_lib/tx_buffer_inband.v
@@ -0,0 +1,183 @@
+module tx_buffer_inband
+ ( input usbclk,
+ input bus_reset, // Used here for the 257-Hack to fix the FX2 bug
+ input reset, // standard DSP-side reset
+ input [15:0] usbdata,
+ input wire WR,
+ output wire have_space,
+ output reg tx_underrun,
+ input wire [3:0] channels,
+ output [15:0] tx_i_0,
+ output [15:0] tx_q_0,
+ output [15:0] tx_i_1,
+ output [15:0] tx_q_1,
+ //NOT USED
+ output reg [15:0] tx_i_2,
+ output reg [15:0] tx_q_2,
+ output reg [15:0] tx_i_3,
+ output reg [15:0] tx_q_3,
+ input txclk,
+ input txstrobe,
+ input clear_status,
+ output wire tx_empty,
+ output [11:0] debugbus
+ );
+
+ wire [15:0] tx_data_bus;
+
+ wire WR_chan_0;
+ wire chan_0_done;
+ wire OR0;
+ wire UR0;
+
+ wire WR_chan_1;
+ wire chan_1_done;
+ wire OR1;
+ wire UR1;
+
+ // NOT USED yet
+ wire WR_cmd;
+ wire cmd_done;
+
+ //EXTERNAL REGISTER
+ //TODO: increment it
+ reg [31:0] time_counter;
+ reg [7:0] txstrobe_rate_0;
+ reg [7:0] txstrobe_rate_1;
+
+
+ //Usb block
+ wire [15:0] tupf_fifodata;
+ wire tupf_pkt_waiting;
+ wire tupf_rdreq;
+ wire tupf_skip;
+ wire tupf_have_space;
+
+ usb_packet_fifo2 tx_usb_packet_fifo
+ ( .reset (reset),
+ .usb_clock (usbclk),
+ .fpga_clock (txclk),
+ .write_data (usbdata),
+ .write_enable (WR),
+ .read_data (tupf_fifodata),
+ .pkt_waiting (tupf_pkt_waiting),
+ .read_enable (tupf_rdreq),
+ .skip_packet (tupf_skip),
+ .have_space (tupf_have_space),
+ .tx_empty (tx_empty)
+ );
+
+ usb_fifo_reader tx_usb_packet_reader (
+ .reset(reset),
+ .tx_clock(txclk),
+ .tx_data_bus(tx_data_bus),
+ .WR_chan_0(WR_chan_0),
+ .WR_chan_1(WR_chan_1),
+ .WR_cmd(WR_cmd),
+ .chan_0_done(chan_0_done),
+ .chan_1_done(chan_1_done),
+ .cmd_done(cmd_done),
+ .rdreq(tupf_rdreq),
+ .skip(tupf_skip),
+ .pkt_waiting(tupf_pkt_waiting),
+ .fifodata(tupf_fifodata)
+ );
+
+
+ //Channel 0 block
+ wire [15:0] tdpf_fifodata_0;
+ wire tdpf_pkt_waiting_0;
+ wire tdpf_rdreq_0;
+ wire tdpf_skip_0;
+ wire tdpf_have_space_0;
+ wire txstrobe_chan_0;
+
+ data_packet_fifo tx_data_packet_fifo_0
+ ( .reset(reset),
+ .clock(txclk),
+ .ram_data_in(tx_data_bus),
+ .write_enable(WR_chan_0),
+ .ram_data_out(tdpf_fifodata_0),
+ .pkt_waiting(tdpf_pkt_waiting_0),
+ .read_enable(tdpf_rdreq_0),
+ .pkt_complete(chan_0_done),
+ .skip_packet(tdpf_skip_0),
+ .have_space(tdpf_have_space_0)
+ );
+
+ strobe_gen strobe_gen_0
+ ( .clock(txclk),
+ .reset(reset),
+ .enable(1'b1),
+ .rate(txstrobe_rate_0),
+ .strobe_in(txstrobe),
+ .strobe(txstrobe_chan_0)
+ );
+
+ chan_fifo_reader tx_chan_0_reader (
+ .reset(reset),
+ .tx_clock(txclk),
+ .tx_strobe(txstrobe),
+ //.tx_strobe(txstrobe_chan_0),
+ .adc_clock(time_counter),
+ .samples_format(4'b0),
+ .tx_q(tx_q_0),
+ .tx_i(tx_i_0),
+ .overrun(OR0),
+ .underrun(UR0),
+ .skip(tdpf_skip_0),
+ .rdreq(tdpf_rdreq_0),
+ .fifodata(tdpf_fifodata_0),
+ .pkt_waiting(tdpf_pkt_waiting_0)
+ );
+
+
+ //Channel 1 block
+ wire [15:0] tdpf_fifodata_1;
+ wire tdpf_pkt_waiting_1;
+ wire tdpf_rdreq_1;
+ wire tdpf_skip_1;
+ wire tdpf_have_space_1;
+ wire txstrobe_chan_1;
+
+ data_packet_fifo tx_data_packet_fifo_1
+ ( .reset(reset),
+ .clock(txclk),
+ .ram_data_in(tx_data_bus),
+ .write_enable(WR_chan_1),
+ .ram_data_out(tdpf_fifodata_1),
+ .pkt_waiting(tdpf_pkt_waiting_1),
+ .read_enable(tdpf_rdreq_1),
+ .pkt_complete(chan_1_done),
+ .skip_packet(tdpf_skip_1),
+ .have_space(tdpf_have_space_1)
+ );
+
+ strobe_gen strobe_gen_1
+ ( .clock(txclk),
+ .reset(reset),
+ .enable(1'b1),
+ .rate(txstrobe_rate_1),
+ .strobe_in(txstrobe),
+ .strobe(txstrobe_chan_1)
+ );
+
+ chan_fifo_reader tx_chan_1_reader (
+ .reset(reset),
+ .tx_clock(txclk),
+ .tx_strobe(txstrobe),
+ //.tx_strobe(txstrobe_chan_1),
+ .adc_clock(time_counter),
+ .samples_format(4'b0),
+ .tx_q(tx_q_1),
+ .tx_i(tx_i_1),
+ .overrun(OR1),
+ .underrun(UR1),
+ .skip(tdpf_skip_1),
+ .rdreq(tdpf_rdreq_1),
+ .fifodata(tdpf_fifodata_1),
+ .pkt_waiting(tdpf_pkt_waiting_1)
+ );
+
+endmodule // tx_buffer
+
diff --git a/usrp/fpga/inband_lib/usb_fifo_reader.v b/usrp/fpga/inband_lib/usb_fifo_reader.v
new file mode 100755
index 000000000..170c70fd4
--- /dev/null
+++ b/usrp/fpga/inband_lib/usb_fifo_reader.v
@@ -0,0 +1,135 @@
+module usb_fifo_reader (tx_clock, fifodata, pkt_waiting, reset,
+ rdreq, skip, done_chan, WR_chan, tx_data_bus);
+
+ /* Module parameters */
+ parameter NUM_CHAN = 2 ;
+ parameter WIDTH = 32 ;
+
+ input wire tx_clock ;
+ input wire reset ;
+ input wire [WIDTH-1:0] fifodata ;
+ input wire pkt_waiting ;
+ output reg rdreq ;
+ output reg skip ;
+ output reg [NUM_CHAN:0] done_chan ;
+ output reg [NUM_CHAN:0] WR_chan ;
+ output reg [WIDTH-1:0] tx_data_bus ;
+
+
+
+ /* States definition */
+ `define IDLE 3'd0
+ `define WAIT 3'd1
+ `define READ_HEADER 3'd2
+ `define FORWARD_DATA 3'd3
+ `define SKIP_REST 3'd4
+
+ /* Channel Ids */
+ `define TXCHAN0 5'h0
+ `define TXCHAN1 5'h1
+ `define TXCMD 5'h1F
+
+ /* Local registers */
+ reg [2:0] reader_state ;
+ reg [2:0] reader_next_state ;
+ reg [4:0] channel ;
+ reg [8:0] pkt_length ;
+ reg [8:0] read_length ;
+
+ /* State Machine */
+ always @(posedge tx_clock)
+ begin
+ if (reset)
+ begin
+ reader_state <= `IDLE ;
+ reader_next_state <= `IDLE ;
+ rdreq <= 0 ;
+ skip <= 0 ;
+ WR_chan <= {NUM_CHAN+1{1'b0}} ;
+ done_chan <= {NUM_CHAN+1{1'b0}} ;
+ end
+ else
+ begin
+ reader_state = reader_next_state ;
+
+ case(reader_state)
+ `IDLE:
+ begin
+ reader_next_state <= pkt_waiting ? `WAIT : `IDLE ;
+ rdreq <= pkt_waiting ;
+ end
+
+ /* Wait for the fifo's data to show up */
+ `WAIT:
+ begin
+ reader_next_state <= `READ_HEADER ;
+ end
+
+ `READ_HEADER:
+ begin
+ reader_next_state <= `FORWARD_DATA ;
+
+ /* Read header fields */
+ channel <= (fifodata & 32'h1F0000) ;
+ pkt_length <= (fifodata & 16'h1FF) + 4 ;
+ read_length <= 9'd0 ;
+
+ /* Forward data */
+ case (channel)
+ `TXCHAN0: WR_chan[0] <= 1 ;
+ `TXCHAN1: WR_chan[1] <= 1 ;
+ `TXCMD: WR_chan[2] <= 1 ;
+ default: WR_chan <= 1 ;
+ endcase
+ tx_data_bus <= fifodata ;
+ end
+
+ `FORWARD_DATA:
+ begin
+ read_length <= read_length + 4 ;
+
+ // If end of payload...
+ if (read_length == pkt_length)
+ begin
+ reader_next_state <= `SKIP_REST ;
+ /* If the packet is 512 bytes, don't skip */
+ skip <= pkt_length < 506 ;
+
+ /* Data pushing done */
+ WR_chan <= {NUM_CHAN+1{1'b0}} ;
+
+ /* Notify next block */
+ case (channel)
+ `TXCHAN0: done_chan[0] <= 1 ;
+ `TXCHAN1: done_chan[1] <= 1 ;
+ `TXCMD: done_chan[2] <= 1 ;
+ default: done_chan[0] <= 1 ;
+ endcase
+ end
+ else if (read_length == pkt_length - 4)
+ rdreq <= 0 ;
+
+ /* Forward data */
+ tx_data_bus <= fifodata ;
+ end
+
+ `SKIP_REST:
+ begin
+ reader_next_state <= pkt_waiting ? `READ_HEADER : `IDLE ;
+ done_chan <= {NUM_CHAN+1{1'b0}} ;
+ rdreq <= pkt_waiting ;
+ skip <= 0 ;
+ end
+
+ default:
+ begin
+ reader_state <= `IDLE;
+ reader_next_state <= `IDLE;
+ end
+ endcase
+ end
+ end
+endmodule
+
+
+ \ No newline at end of file
diff --git a/usrp/fpga/inband_lib/usb_packet_fifo.v b/usrp/fpga/inband_lib/usb_packet_fifo.v
new file mode 100755
index 000000000..c416e2bdb
--- /dev/null
+++ b/usrp/fpga/inband_lib/usb_packet_fifo.v
@@ -0,0 +1,112 @@
+module usb_packet_fifo
+ ( input reset,
+ input clock_in,
+ input clock_out,
+ input [15:0]ram_data_in,
+ input write_enable,
+ output reg [15:0]ram_data_out,
+ output reg pkt_waiting,
+ output reg have_space,
+ input read_enable,
+ input skip_packet ) ;
+
+ /* Some parameters for usage later on */
+ parameter DATA_WIDTH = 16 ;
+ parameter NUM_PACKETS = 4 ;
+
+ /* Create the RAM here */
+ reg [DATA_WIDTH-1:0] usb_ram [256*NUM_PACKETS-1:0] ;
+
+ /* Create the address signals */
+ reg [7-2+NUM_PACKETS:0] usb_ram_ain ;
+ reg [7:0] usb_ram_offset ;
+ reg [1:0] usb_ram_packet ;
+
+ wire [7-2+NUM_PACKETS:0] usb_ram_aout ;
+ reg isfull;
+
+ assign usb_ram_aout = {usb_ram_packet,usb_ram_offset} ;
+
+ // Check if there is one full packet to process
+ always @(usb_ram_ain, usb_ram_aout)
+ begin
+ if (reset)
+ pkt_waiting <= 0;
+ else if (usb_ram_ain == usb_ram_aout)
+ pkt_waiting <= isfull;
+ else if (usb_ram_ain > usb_ram_aout)
+ pkt_waiting <= (usb_ram_ain - usb_ram_aout) >= 256;
+ else
+ pkt_waiting <= (usb_ram_ain + 10'b1111111111 - usb_ram_aout) >= 256;
+ end
+
+ // Check if there is room
+ always @(usb_ram_ain, usb_ram_aout)
+ begin
+ if (reset)
+ have_space <= 1;
+ else if (usb_ram_ain == usb_ram_aout)
+ have_space <= ~isfull;
+ else if (usb_ram_ain > usb_ram_aout)
+ have_space <= (usb_ram_ain - usb_ram_aout) <= 256 * (NUM_PACKETS - 1);
+ else
+ have_space <= (usb_ram_aout - usb_ram_ain) >= 256;
+ end
+
+ /* RAM Write Address process */
+ always @(posedge clock_in)
+ begin
+ if( reset )
+ usb_ram_ain <= 0 ;
+ else
+ if( write_enable )
+ begin
+ usb_ram_ain <= usb_ram_ain + 1 ;
+ if (usb_ram_ain + 1 == usb_ram_aout)
+ isfull <= 1;
+ end
+ end
+
+ /* RAM Writing process */
+ always @(posedge clock_in)
+ begin
+ if( write_enable )
+ begin
+ usb_ram[usb_ram_ain] <= ram_data_in ;
+ end
+ end
+
+ /* RAM Read Address process */
+ always @(posedge clock_out)
+ begin
+ if( reset )
+ begin
+ usb_ram_packet <= 0 ;
+ usb_ram_offset <= 0 ;
+ isfull <= 0;
+ end
+ else
+ if( skip_packet )
+ begin
+ usb_ram_packet <= usb_ram_packet + 1 ;
+ usb_ram_offset <= 0 ;
+ end
+ else if(read_enable)
+ if( usb_ram_offset == 8'b11111111 )
+ begin
+ usb_ram_offset <= 0 ;
+ usb_ram_packet <= usb_ram_packet + 1 ;
+ end
+ else
+ usb_ram_offset <= usb_ram_offset + 1 ;
+ if (usb_ram_ain == usb_ram_aout)
+ isfull <= 0;
+ end
+
+ /* RAM Reading Process */
+ always @(posedge clock_out)
+ begin
+ ram_data_out <= usb_ram[usb_ram_aout] ;
+ end
+
+endmodule \ No newline at end of file
diff --git a/usrp/fpga/inband_lib/usb_packet_fifo2.v b/usrp/fpga/inband_lib/usb_packet_fifo2.v
new file mode 100755
index 000000000..d815e4e37
--- /dev/null
+++ b/usrp/fpga/inband_lib/usb_packet_fifo2.v
@@ -0,0 +1,119 @@
+`default_nettype none
+
+module usb_packet_fifo2(reset, usb_clock, fpga_clock, write_enable, write_data,
+ read_enable, skip_packet, read_data, have_space, pkt_waiting, tx_empty) ;
+
+ /* Module parameters */
+ parameter LOG2_N = 2 ;
+ parameter BUS_WIDTH = 16 ;
+ parameter FIFO_WIDTH = 32 ;
+
+ input wire reset;
+ input wire usb_clock ;
+ input wire fpga_clock ;
+ input wire write_enable ;
+ input wire [BUS_WIDTH-1:0] write_data ;
+ input wire read_enable ;
+ input wire skip_packet ;
+ output wire [FIFO_WIDTH-1:0] read_data ;
+ output wire have_space ;
+ output wire pkt_waiting ;
+ output wire tx_empty;
+
+
+ /* Variable for generate statement */
+ genvar i ;
+
+ /* Local wires for FIFO connections */
+ wire [2**LOG2_N-1:0] fifo_resets ;
+ reg [2**LOG2_N-1:0] fifo_we ;
+ wire [2**LOG2_N-1:0] fifo_re ;
+ reg [FIFO_WIDTH-1:0] fifo_wdata[2**LOG2_N-1:0] ;
+ wire [FIFO_WIDTH-1:0] fifo_rdata[2**LOG2_N-1:0] ;
+ wire [2**LOG2_N-1:0] fifo_rempty ;
+ wire [2**LOG2_N-1:0] fifo_rfull ;
+ wire [2**LOG2_N-1:0] fifo_wempty ;
+ wire [2**LOG2_N-1:0] fifo_wfull ;
+
+ /* FIFO Select for read and write ports */
+ reg [LOG2_N-1:0] fifo_rselect ;
+ reg [LOG2_N-1:0] fifo_wselect ;
+
+ /* Used to convert 16 bits usbdata to the 32 bits wide fifo */
+ reg word_complete ;
+ reg [BUS_WIDTH-1:0] write_data_delayed ;
+
+ /* Assign have_space to empty flag of currently selected write FIFO */
+ assign have_space = fifo_wempty[fifo_wselect] ;
+
+ /* Assign pkt_waiting to full flag of currently selected read FIFO */
+ assign pkt_waiting = fifo_rfull[fifo_rselect] ;
+
+ /* Assign the read_data to the output of the currently selected FIFO */
+ assign read_data = fifo_rdata[fifo_rselect] ;
+
+ /* Figure out if we're all empty */
+ assign tx_empty = !(~fifo_rempty) ;
+
+ /* Increment fifo_rselect here */
+ always @(posedge fpga_clock)
+ begin
+ if (reset)
+ fifo_rselect <= {2**LOG2_N{1'b0}} ;
+
+ if (fifo_rempty[fifo_rselect])
+ fifo_rselect <= fifo_rselect + 1 ;
+
+ if (skip_packet)
+ fifo_rselect <= fifo_rselect + 1 ;
+ end
+
+ /* Increment fifo_wselect and pack data into 32 bits block */
+ always @(posedge usb_clock, reset)
+ begin
+ if (reset)
+ begin
+ fifo_wselect <= {2**LOG2_N{1'b0}} ;
+ word_complete <= 0;
+ end
+
+ if (fifo_wfull[fifo_wselect])
+ fifo_wselect <= fifo_wselect + 1 ;
+
+ if (write_enable)
+ begin
+ word_complete <= ~word_complete ;
+
+ if (word_complete)
+ fifo_wdata[fifo_wselect] <= {write_data_delayed, write_data} ;
+ else
+ write_data_delayed <= write_data ;
+
+ /* Avoid to continue to write in the previous fifo when we have
+ just swichted to the next one */
+ fifo_we[fifo_wselect-1] <= 0 ;
+
+ fifo_we[fifo_wselect] <= write_enable & word_complete ;
+ end
+ end
+
+ /* Generate all the single packet FIFOs */
+ generate
+ for( i = 0 ; i < 2**LOG2_N ; i = i + 1 )
+ begin : generate_single_packet_fifos
+ assign fifo_re[i] = (fifo_rselect == i) ? read_enable : 1'b0 ;
+ assign fifo_resets[i] = (fifo_rselect == i) ? skip_packet : 1'b0 ;
+ fifo_512 single_packet_fifo(.wrclk ( usb_clock ),
+ .rdclk ( fpga_clock ),
+ .aclr ( fifo_resets[i] ),
+ .wrreq ( fifo_we[i] ),
+ .data ( fifo_wdata[i] ),
+ .rdreq ( fifo_re[i] ),
+ .q ( fifo_rdata[i] ),
+ .rdfull ( fifo_rfull[i] ),
+ .rdempty( fifo_rempty[i] ),
+ .wrfull ( fifo_wfull[i] ),
+ .wrempty( fifo_wempty[i] ) ) ;
+ end
+ endgenerate
+endmodule \ No newline at end of file
diff --git a/usrp/fpga/megacells/fifo_512.bsf b/usrp/fpga/megacells/fifo_512.bsf
new file mode 100755
index 000000000..a955b5655
--- /dev/null
+++ b/usrp/fpga/megacells/fifo_512.bsf
@@ -0,0 +1,116 @@
+/*
+WARNING: Do NOT edit the input and output ports in this file in a text
+editor if you plan to continue editing the block that represents it in
+the Block Editor! File corruption is VERY likely to occur.
+*/
+/*
+Copyright (C) 1991-2006 Altera Corporation
+Your use of Altera Corporation's design tools, logic functions
+and other software and tools, and its AMPP partner logic
+functions, and any output files any of the foregoing
+(including device programming or simulation files), and any
+associated documentation or information are expressly subject
+to the terms and conditions of the Altera Program License
+Subscription Agreement, Altera MegaCore Function License
+Agreement, or other applicable license agreement, including,
+without limitation, that your use is for the sole purpose of
+programming logic devices manufactured by Altera and sold by
+Altera or its authorized distributors. Please refer to the
+applicable agreement for further details.
+*/
+(header "symbol" (version "1.1"))
+(symbol
+ (rect 0 0 160 184)
+ (text "fifo_512" (rect 58 1 109 17)(font "Arial" (font_size 10)))
+ (text "inst" (rect 8 168 25 180)(font "Arial" ))
+ (port
+ (pt 0 32)
+ (input)
+ (text "data[31..0]" (rect 0 0 60 14)(font "Arial" (font_size 8)))
+ (text "data[31..0]" (rect 20 26 71 39)(font "Arial" (font_size 8)))
+ (line (pt 0 32)(pt 16 32)(line_width 3))
+ )
+ (port
+ (pt 0 56)
+ (input)
+ (text "wrreq" (rect 0 0 35 14)(font "Arial" (font_size 8)))
+ (text "wrreq" (rect 20 50 45 63)(font "Arial" (font_size 8)))
+ (line (pt 0 56)(pt 16 56)(line_width 1))
+ )
+ (port
+ (pt 0 72)
+ (input)
+ (text "wrclk" (rect 0 0 31 14)(font "Arial" (font_size 8)))
+ (text "wrclk" (rect 26 66 48 79)(font "Arial" (font_size 8)))
+ (line (pt 0 72)(pt 16 72)(line_width 1))
+ )
+ (port
+ (pt 0 104)
+ (input)
+ (text "rdreq" (rect 0 0 30 14)(font "Arial" (font_size 8)))
+ (text "rdreq" (rect 20 98 44 111)(font "Arial" (font_size 8)))
+ (line (pt 0 104)(pt 16 104)(line_width 1))
+ )
+ (port
+ (pt 0 120)
+ (input)
+ (text "rdclk" (rect 0 0 27 14)(font "Arial" (font_size 8)))
+ (text "rdclk" (rect 26 114 47 127)(font "Arial" (font_size 8)))
+ (line (pt 0 120)(pt 16 120)(line_width 1))
+ )
+ (port
+ (pt 0 160)
+ (input)
+ (text "aclr" (rect 0 0 21 14)(font "Arial" (font_size 8)))
+ (text "aclr" (rect 20 154 37 167)(font "Arial" (font_size 8)))
+ (line (pt 0 160)(pt 16 160)(line_width 1))
+ )
+ (port
+ (pt 160 40)
+ (output)
+ (text "wrfull" (rect 0 0 33 14)(font "Arial" (font_size 8)))
+ (text "wrfull" (rect 113 34 138 47)(font "Arial" (font_size 8)))
+ (line (pt 160 40)(pt 144 40)(line_width 1))
+ )
+ (port
+ (pt 160 56)
+ (output)
+ (text "wrempty" (rect 0 0 50 14)(font "Arial" (font_size 8)))
+ (text "wrempty" (rect 98 50 137 63)(font "Arial" (font_size 8)))
+ (line (pt 160 56)(pt 144 56)(line_width 1))
+ )
+ (port
+ (pt 160 96)
+ (output)
+ (text "q[31..0]" (rect 0 0 42 14)(font "Arial" (font_size 8)))
+ (text "q[31..0]" (rect 105 90 141 103)(font "Arial" (font_size 8)))
+ (line (pt 160 96)(pt 144 96)(line_width 3))
+ )
+ (port
+ (pt 160 120)
+ (output)
+ (text "rdfull" (rect 0 0 28 14)(font "Arial" (font_size 8)))
+ (text "rdfull" (rect 117 114 141 127)(font "Arial" (font_size 8)))
+ (line (pt 160 120)(pt 144 120)(line_width 1))
+ )
+ (port
+ (pt 160 136)
+ (output)
+ (text "rdempty" (rect 0 0 46 14)(font "Arial" (font_size 8)))
+ (text "rdempty" (rect 102 130 140 143)(font "Arial" (font_size 8)))
+ (line (pt 160 136)(pt 144 136)(line_width 1))
+ )
+ (drawing
+ (text "32 bits x 128 words" (rect 63 156 144 168)(font "Arial" ))
+ (line (pt 16 16)(pt 144 16)(line_width 1))
+ (line (pt 144 16)(pt 144 168)(line_width 1))
+ (line (pt 144 168)(pt 16 168)(line_width 1))
+ (line (pt 16 168)(pt 16 16)(line_width 1))
+ (line (pt 16 84)(pt 144 84)(line_width 1))
+ (line (pt 16 148)(pt 144 148)(line_width 1))
+ (line (pt 16 66)(pt 22 72)(line_width 1))
+ (line (pt 22 72)(pt 16 78)(line_width 1))
+ (line (pt 16 114)(pt 22 120)(line_width 1))
+ (line (pt 22 120)(pt 16 126)(line_width 1))
+ )
+)
diff --git a/usrp/fpga/megacells/fifo_512.cmp b/usrp/fpga/megacells/fifo_512.cmp
new file mode 100755
index 000000000..86fc07846
--- /dev/null
+++ b/usrp/fpga/megacells/fifo_512.cmp
@@ -0,0 +1,31 @@
+--Copyright (C) 1991-2006 Altera Corporation
+--Your use of Altera Corporation's design tools, logic functions
+--and other software and tools, and its AMPP partner logic
+--functions, and any output files any of the foregoing
+--(including device programming or simulation files), and any
+--associated documentation or information are expressly subject
+--to the terms and conditions of the Altera Program License
+--Subscription Agreement, Altera MegaCore Function License
+--Agreement, or other applicable license agreement, including,
+--without limitation, that your use is for the sole purpose of
+--programming logic devices manufactured by Altera and sold by
+--Altera or its authorized distributors. Please refer to the
+--applicable agreement for further details.
+
+
+component fifo_512
+ PORT
+ (
+ aclr : IN STD_LOGIC := '0';
+ data : IN STD_LOGIC_VECTOR (31 DOWNTO 0);
+ rdclk : IN STD_LOGIC ;
+ rdreq : IN STD_LOGIC ;
+ wrclk : IN STD_LOGIC ;
+ wrreq : IN STD_LOGIC ;
+ q : OUT STD_LOGIC_VECTOR (31 DOWNTO 0);
+ rdempty : OUT STD_LOGIC ;
+ rdfull : OUT STD_LOGIC ;
+ wrempty : OUT STD_LOGIC ;
+ wrfull : OUT STD_LOGIC
+ );
+end component;
diff --git a/usrp/fpga/megacells/fifo_512.inc b/usrp/fpga/megacells/fifo_512.inc
new file mode 100755
index 000000000..9ae1e3af4
--- /dev/null
+++ b/usrp/fpga/megacells/fifo_512.inc
@@ -0,0 +1,32 @@
+--Copyright (C) 1991-2006 Altera Corporation
+--Your use of Altera Corporation's design tools, logic functions
+--and other software and tools, and its AMPP partner logic
+--functions, and any output files any of the foregoing
+--(including device programming or simulation files), and any
+--associated documentation or information are expressly subject
+--to the terms and conditions of the Altera Program License
+--Subscription Agreement, Altera MegaCore Function License
+--Agreement, or other applicable license agreement, including,
+--without limitation, that your use is for the sole purpose of
+--programming logic devices manufactured by Altera and sold by
+--Altera or its authorized distributors. Please refer to the
+--applicable agreement for further details.
+
+
+FUNCTION fifo_512
+(
+ aclr,
+ data[31..0],
+ rdclk,
+ rdreq,
+ wrclk,
+ wrreq
+)
+
+RETURNS (
+ q[31..0],
+ rdempty,
+ rdfull,
+ wrempty,
+ wrfull
+);
diff --git a/usrp/fpga/megacells/fifo_512.v b/usrp/fpga/megacells/fifo_512.v
new file mode 100755
index 000000000..b034b4ddc
--- /dev/null
+++ b/usrp/fpga/megacells/fifo_512.v
@@ -0,0 +1,180 @@
+// megafunction wizard: %LPM_FIFO+%
+// GENERATION: STANDARD
+// VERSION: WM1.0
+// MODULE: dcfifo
+
+// ============================================================
+// File Name: fifo_512.v
+// Megafunction Name(s):
+// dcfifo
+// ============================================================
+// ************************************************************
+// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+//
+// 5.1 Build 213 01/19/2006 SP 1 SJ Web Edition
+// ************************************************************
+
+
+//Copyright (C) 1991-2006 Altera Corporation
+//Your use of Altera Corporation's design tools, logic functions
+//and other software and tools, and its AMPP partner logic
+//functions, and any output files any of the foregoing
+//(including device programming or simulation files), and any
+//associated documentation or information are expressly subject
+//to the terms and conditions of the Altera Program License
+//Subscription Agreement, Altera MegaCore Function License
+//Agreement, or other applicable license agreement, including,
+//without limitation, that your use is for the sole purpose of
+//programming logic devices manufactured by Altera and sold by
+//Altera or its authorized distributors. Please refer to the
+//applicable agreement for further details.
+
+
+// synopsys translate_off
+`timescale 1 ps / 1 ps
+// synopsys translate_on
+module fifo_512 (
+ aclr,
+ data,
+ rdclk,
+ rdreq,
+ wrclk,
+ wrreq,
+ q,
+ rdempty,
+ rdfull,
+ wrempty,
+ wrfull);
+
+ input aclr;
+ input [31:0] data;
+ input rdclk;
+ input rdreq;
+ input wrclk;
+ input wrreq;
+ output [31:0] q;
+ output rdempty;
+ output rdfull;
+ output wrempty;
+ output wrfull;
+
+ wire sub_wire0;
+ wire sub_wire1;
+ wire sub_wire2;
+ wire sub_wire3;
+ wire [31:0] sub_wire4;
+ wire rdfull = sub_wire0;
+ wire rdempty = sub_wire1;
+ wire wrfull = sub_wire2;
+ wire wrempty = sub_wire3;
+ wire [31:0] q = sub_wire4[31:0];
+
+ dcfifo dcfifo_component (
+ .wrclk (wrclk),
+ .rdreq (rdreq),
+ .aclr (aclr),
+ .rdclk (rdclk),
+ .wrreq (wrreq),
+ .data (data),
+ .rdfull (sub_wire0),
+ .rdempty (sub_wire1),
+ .wrfull (sub_wire2),
+ .wrempty (sub_wire3),
+ .q (sub_wire4)
+ // synopsys translate_off
+ ,
+ .rdusedw (),
+ .wrusedw ()
+ // synopsys translate_on
+ );
+ defparam
+ dcfifo_component.add_ram_output_register = "OFF",
+ dcfifo_component.clocks_are_synchronized = "FALSE",
+ dcfifo_component.intended_device_family = "Cyclone",
+ dcfifo_component.lpm_hint = "RAM_BLOCK_TYPE=M4K",
+ dcfifo_component.lpm_numwords = 128,
+ dcfifo_component.lpm_showahead = "OFF",
+ dcfifo_component.lpm_type = "dcfifo",
+ dcfifo_component.lpm_width = 32,
+ dcfifo_component.lpm_widthu = 7,
+ dcfifo_component.overflow_checking = "ON",
+ dcfifo_component.underflow_checking = "ON",
+ dcfifo_component.use_eab = "ON";
+
+
+endmodule
+
+// ============================================================
+// CNX file retrieval info
+// ============================================================
+// Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0"
+// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1"
+// Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
+// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
+// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0"
+// Retrieval info: PRIVATE: Clock NUMERIC "4"
+// Retrieval info: PRIVATE: Depth NUMERIC "128"
+// Retrieval info: PRIVATE: Empty NUMERIC "1"
+// Retrieval info: PRIVATE: Full NUMERIC "1"
+// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone"
+// Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0"
+// Retrieval info: PRIVATE: LegacyRREQ NUMERIC "1"
+// Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0"
+// Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0"
+// Retrieval info: PRIVATE: Optimize NUMERIC "2"
+// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "2"
+// Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0"
+// Retrieval info: PRIVATE: UsedW NUMERIC "1"
+// Retrieval info: PRIVATE: Width NUMERIC "32"
+// Retrieval info: PRIVATE: dc_aclr NUMERIC "1"
+// Retrieval info: PRIVATE: rsEmpty NUMERIC "1"
+// Retrieval info: PRIVATE: rsFull NUMERIC "1"
+// Retrieval info: PRIVATE: rsUsedW NUMERIC "0"
+// Retrieval info: PRIVATE: sc_aclr NUMERIC "0"
+// Retrieval info: PRIVATE: sc_sclr NUMERIC "0"
+// Retrieval info: PRIVATE: wsEmpty NUMERIC "1"
+// Retrieval info: PRIVATE: wsFull NUMERIC "1"
+// Retrieval info: PRIVATE: wsUsedW NUMERIC "0"
+// Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "OFF"
+// Retrieval info: CONSTANT: CLOCKS_ARE_SYNCHRONIZED STRING "FALSE"
+// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone"
+// Retrieval info: CONSTANT: LPM_HINT STRING "RAM_BLOCK_TYPE=M4K"
+// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "128"
+// Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "OFF"
+// Retrieval info: CONSTANT: LPM_TYPE STRING "dcfifo"
+// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "32"
+// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "7"
+// Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON"
+// Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON"
+// Retrieval info: CONSTANT: USE_EAB STRING "ON"
+// Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT GND aclr
+// Retrieval info: USED_PORT: data 0 0 32 0 INPUT NODEFVAL data[31..0]
+// Retrieval info: USED_PORT: q 0 0 32 0 OUTPUT NODEFVAL q[31..0]
+// Retrieval info: USED_PORT: rdclk 0 0 0 0 INPUT NODEFVAL rdclk
+// Retrieval info: USED_PORT: rdempty 0 0 0 0 OUTPUT NODEFVAL rdempty
+// Retrieval info: USED_PORT: rdfull 0 0 0 0 OUTPUT NODEFVAL rdfull
+// Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL rdreq
+// Retrieval info: USED_PORT: wrclk 0 0 0 0 INPUT NODEFVAL wrclk
+// Retrieval info: USED_PORT: wrempty 0 0 0 0 OUTPUT NODEFVAL wrempty
+// Retrieval info: USED_PORT: wrfull 0 0 0 0 OUTPUT NODEFVAL wrfull
+// Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL wrreq
+// Retrieval info: CONNECT: @data 0 0 32 0 data 0 0 32 0
+// Retrieval info: CONNECT: q 0 0 32 0 @q 0 0 32 0
+// Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0
+// Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0
+// Retrieval info: CONNECT: @rdclk 0 0 0 0 rdclk 0 0 0 0
+// Retrieval info: CONNECT: @wrclk 0 0 0 0 wrclk 0 0 0 0
+// Retrieval info: CONNECT: rdfull 0 0 0 0 @rdfull 0 0 0 0
+// Retrieval info: CONNECT: rdempty 0 0 0 0 @rdempty 0 0 0 0
+// Retrieval info: CONNECT: wrfull 0 0 0 0 @wrfull 0 0 0 0
+// Retrieval info: CONNECT: wrempty 0 0 0 0 @wrempty 0 0 0 0
+// Retrieval info: CONNECT: @aclr 0 0 0 0 aclr 0 0 0 0
+// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.inc TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.cmp TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.bsf TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_inst.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_bb.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_waveforms.html TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_wave*.jpg FALSE
diff --git a/usrp/fpga/megacells/fifo_512_bb.v b/usrp/fpga/megacells/fifo_512_bb.v
new file mode 100755
index 000000000..b11803159
--- /dev/null
+++ b/usrp/fpga/megacells/fifo_512_bb.v
@@ -0,0 +1,131 @@
+// megafunction wizard: %LPM_FIFO+%VBB%
+// GENERATION: STANDARD
+// VERSION: WM1.0
+// MODULE: dcfifo
+
+// ============================================================
+// File Name: fifo_512.v
+// Megafunction Name(s):
+// dcfifo
+// ============================================================
+// ************************************************************
+// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+//
+// 5.1 Build 213 01/19/2006 SP 1 SJ Web Edition
+// ************************************************************
+
+//Copyright (C) 1991-2006 Altera Corporation
+//Your use of Altera Corporation's design tools, logic functions
+//and other software and tools, and its AMPP partner logic
+//functions, and any output files any of the foregoing
+//(including device programming or simulation files), and any
+//associated documentation or information are expressly subject
+//to the terms and conditions of the Altera Program License
+//Subscription Agreement, Altera MegaCore Function License
+//Agreement, or other applicable license agreement, including,
+//without limitation, that your use is for the sole purpose of
+//programming logic devices manufactured by Altera and sold by
+//Altera or its authorized distributors. Please refer to the
+//applicable agreement for further details.
+
+module fifo_512 (
+ aclr,
+ data,
+ rdclk,
+ rdreq,
+ wrclk,
+ wrreq,
+ q,
+ rdempty,
+ rdfull,
+ wrempty,
+ wrfull);
+
+ input aclr;
+ input [31:0] data;
+ input rdclk;
+ input rdreq;
+ input wrclk;
+ input wrreq;
+ output [31:0] q;
+ output rdempty;
+ output rdfull;
+ output wrempty;
+ output wrfull;
+
+endmodule
+
+// ============================================================
+// CNX file retrieval info
+// ============================================================
+// Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0"
+// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1"
+// Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
+// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
+// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0"
+// Retrieval info: PRIVATE: Clock NUMERIC "4"
+// Retrieval info: PRIVATE: Depth NUMERIC "128"
+// Retrieval info: PRIVATE: Empty NUMERIC "1"
+// Retrieval info: PRIVATE: Full NUMERIC "1"
+// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone"
+// Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0"
+// Retrieval info: PRIVATE: LegacyRREQ NUMERIC "1"
+// Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0"
+// Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0"
+// Retrieval info: PRIVATE: Optimize NUMERIC "2"
+// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "2"
+// Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0"
+// Retrieval info: PRIVATE: UsedW NUMERIC "1"
+// Retrieval info: PRIVATE: Width NUMERIC "32"
+// Retrieval info: PRIVATE: dc_aclr NUMERIC "1"
+// Retrieval info: PRIVATE: rsEmpty NUMERIC "1"
+// Retrieval info: PRIVATE: rsFull NUMERIC "1"
+// Retrieval info: PRIVATE: rsUsedW NUMERIC "0"
+// Retrieval info: PRIVATE: sc_aclr NUMERIC "0"
+// Retrieval info: PRIVATE: sc_sclr NUMERIC "0"
+// Retrieval info: PRIVATE: wsEmpty NUMERIC "1"
+// Retrieval info: PRIVATE: wsFull NUMERIC "1"
+// Retrieval info: PRIVATE: wsUsedW NUMERIC "0"
+// Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "OFF"
+// Retrieval info: CONSTANT: CLOCKS_ARE_SYNCHRONIZED STRING "FALSE"
+// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone"
+// Retrieval info: CONSTANT: LPM_HINT STRING "RAM_BLOCK_TYPE=M4K"
+// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "128"
+// Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "OFF"
+// Retrieval info: CONSTANT: LPM_TYPE STRING "dcfifo"
+// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "32"
+// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "7"
+// Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON"
+// Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON"
+// Retrieval info: CONSTANT: USE_EAB STRING "ON"
+// Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT GND aclr
+// Retrieval info: USED_PORT: data 0 0 32 0 INPUT NODEFVAL data[31..0]
+// Retrieval info: USED_PORT: q 0 0 32 0 OUTPUT NODEFVAL q[31..0]
+// Retrieval info: USED_PORT: rdclk 0 0 0 0 INPUT NODEFVAL rdclk
+// Retrieval info: USED_PORT: rdempty 0 0 0 0 OUTPUT NODEFVAL rdempty
+// Retrieval info: USED_PORT: rdfull 0 0 0 0 OUTPUT NODEFVAL rdfull
+// Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL rdreq
+// Retrieval info: USED_PORT: wrclk 0 0 0 0 INPUT NODEFVAL wrclk
+// Retrieval info: USED_PORT: wrempty 0 0 0 0 OUTPUT NODEFVAL wrempty
+// Retrieval info: USED_PORT: wrfull 0 0 0 0 OUTPUT NODEFVAL wrfull
+// Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL wrreq
+// Retrieval info: CONNECT: @data 0 0 32 0 data 0 0 32 0
+// Retrieval info: CONNECT: q 0 0 32 0 @q 0 0 32 0
+// Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0
+// Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0
+// Retrieval info: CONNECT: @rdclk 0 0 0 0 rdclk 0 0 0 0
+// Retrieval info: CONNECT: @wrclk 0 0 0 0 wrclk 0 0 0 0
+// Retrieval info: CONNECT: rdfull 0 0 0 0 @rdfull 0 0 0 0
+// Retrieval info: CONNECT: rdempty 0 0 0 0 @rdempty 0 0 0 0
+// Retrieval info: CONNECT: wrfull 0 0 0 0 @wrfull 0 0 0 0
+// Retrieval info: CONNECT: wrempty 0 0 0 0 @wrempty 0 0 0 0
+// Retrieval info: CONNECT: @aclr 0 0 0 0 aclr 0 0 0 0
+// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.inc TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.cmp TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.bsf TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_inst.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_bb.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_waveforms.html TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_wave*.jpg FALSE
diff --git a/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf b/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf
index 2646d831f..8296a453e 100644
--- a/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf
+++ b/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf
@@ -27,7 +27,7 @@
# ========================
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 3.0
set_global_assignment -name PROJECT_CREATION_TIME_DATE "00:14:04 JULY 13, 2003"
-set_global_assignment -name LAST_QUARTUS_VERSION 6.1
+set_global_assignment -name LAST_QUARTUS_VERSION "5.1 SP1"
# Pin & Location Assignments
# ==========================
@@ -371,6 +371,13 @@ set_instance_assignment -name CLOCK_SETTINGS master_clk -to master_clk
set_instance_assignment -name PARTITION_HIERARCHY no_file_for_top_partition -to | -section_id Top
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
+set_global_assignment -name FITTER_AUTO_EFFORT_DESIRED_SLACK_MARGIN "100 ps"
+set_global_assignment -name VERILOG_FILE ../../inband_lib/tx_buffer_inband.v
+set_global_assignment -name VERILOG_FILE ../../inband_lib/usb_packet_fifo.v
+set_global_assignment -name VERILOG_FILE ../../inband_lib/chan_fifo_reader.v
+set_global_assignment -name VERILOG_FILE ../../inband_lib/data_packet_fifo.v
+set_global_assignment -name VERILOG_FILE ../../inband_lib/usb_fifo_reader.v
+set_global_assignment -name VERILOG_FILE ../../sdr_lib/cic_dec_shifter.v
set_global_assignment -name VERILOG_FILE ../../sdr_lib/rssi.v
set_global_assignment -name VERILOG_FILE ../../sdr_lib/ram16.v
set_global_assignment -name VERILOG_FILE ../../megacells/fifo_4k.v
@@ -405,5 +412,4 @@ set_global_assignment -name VERILOG_FILE usrp_inband_usb.v
set_global_assignment -name VERILOG_FILE ../../sdr_lib/clk_divider.v
set_global_assignment -name VERILOG_FILE ../../sdr_lib/serial_io.v
set_global_assignment -name VERILOG_FILE ../../sdr_lib/strobe_gen.v
-set_global_assignment -name VERILOG_FILE ../../sdr_lib/sign_extend.v
-set_global_assignment -name FITTER_AUTO_EFFORT_DESIRED_SLACK_MARGIN "100 ps" \ No newline at end of file
+set_global_assignment -name VERILOG_FILE ../../sdr_lib/sign_extend.v \ No newline at end of file
diff --git a/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v b/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v
index 55701b897..cc7490c5a 100644
--- a/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v
+++ b/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v
@@ -19,6 +19,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
//
+`define IN_BAND
`include "config.vh"
`include "../../../firmware/include/fpga_regs_common.v"
@@ -122,6 +123,20 @@ module usrp_inband_usb
assign bb_tx_i1 = ch2tx;
assign bb_tx_q1 = ch3tx;
+`ifdef IN_BAND
+ tx_buffer_inband tx_buffer
+ ( .usbclk(usbclk),.bus_reset(tx_bus_reset),.reset(tx_dsp_reset),
+ .usbdata(usbdata),.WR(WR),.have_space(have_space),.tx_underrun(tx_underrun),
+ .channels({tx_numchan,1'b0}),
+ .tx_i_0(ch0tx),.tx_q_0(ch1tx),
+ .tx_i_1(ch2tx),.tx_q_1(ch3tx),
+ .tx_i_2(),.tx_q_2(),
+ .tx_i_3(),.tx_q_3(),
+ .txclk(clk64),.txstrobe(strobe_interp),
+ .clear_status(clear_status),
+ .tx_empty(tx_empty),
+ .debugbus(tx_debugbus) );
+`else
tx_buffer tx_buffer
( .usbclk(usbclk),.bus_reset(tx_bus_reset),.reset(tx_dsp_reset),
.usbdata(usbdata),.WR(WR),.have_space(have_space),.tx_underrun(tx_underrun),
@@ -134,6 +149,7 @@ module usrp_inband_usb
.clear_status(clear_status),
.tx_empty(tx_empty),
.debugbus(tx_debugbus) );
+`endif
`ifdef TX_EN_0
tx_chain tx_chain_0
diff --git a/usrp/host/apps/Makefile.am b/usrp/host/apps/Makefile.am
index 8e0768e84..035a23ab7 100644
--- a/usrp/host/apps/Makefile.am
+++ b/usrp/host/apps/Makefile.am
@@ -23,8 +23,6 @@ include $(top_srcdir)/Makefile.common
INCLUDES = $(USRP_INCLUDES) $(BOOST_CFLAGS)
-USRP_LIB = $(top_builddir)/usrp/host/lib/libusrp.la
-
bin_PROGRAMS = \
usrper \
usrp_cal_dc_offset
@@ -45,13 +43,13 @@ noinst_PYTHON = \
check_order_quickly_SOURCES = check_order_quickly.cc
test_usrp_standard_rx_SOURCES = test_usrp_standard_rx.cc time_stuff.c
-test_usrp_standard_rx_LDADD = $(USRP_LIB)
+test_usrp_standard_rx_LDADD = $(USRP_LA)
test_usrp_standard_tx_SOURCES = test_usrp_standard_tx.cc time_stuff.c
-test_usrp_standard_tx_LDADD = $(USRP_LIB)
+test_usrp_standard_tx_LDADD = $(USRP_LA)
usrper_SOURCES = usrper.cc
-usrper_LDADD = $(USRP_LIB)
+usrper_LDADD = $(USRP_LA)
usrp_cal_dc_offset_SOURCES = usrp_cal_dc_offset.cc
-usrp_cal_dc_offset_LDADD = $(USRP_LIB)
+usrp_cal_dc_offset_LDADD = $(USRP_LA)
diff --git a/usrp/host/lib/Makefile.am b/usrp/host/lib/Makefile.am
index 7d17a380a..cd37a9b2b 100644
--- a/usrp/host/lib/Makefile.am
+++ b/usrp/host/lib/Makefile.am
@@ -20,133 +20,5 @@
include $(top_srcdir)/Makefile.common
-INCLUDES = $(USRP_INCLUDES)
+SUBDIRS = legacy inband
-lib_LTLIBRARIES = libusrp.la
-
-
-EXTRA_DIST = \
- std_paths.h.in \
- usrp_dbid.dat
-
-
-BUILT_SOURCES = \
- usrp_dbid.h \
- usrp_dbid.cc \
- usrp_dbid.py
-
-
-# ----------------------------------------------------------------
-# FUSB_TECH is set at configure time by way of
-# usrp/config/usrp_fusb_tech.m4.
-# It indicates which fast usb strategy we should be building.
-# We currently implement "generic", "darwin", "win32" and "linux"
-
-
-generic_CODE = \
- fusb_generic.cc \
- fusb_sysconfig_generic.cc
-
-darwin_CODE = \
- fusb_darwin.cc \
- fusb_sysconfig_darwin.cc \
- README_OSX \
- circular_buffer.h \
- circular_linked_list.h \
- darwin_libusb.h \
- mld_threads.h
-
-win32_CODE = \
- fusb_win32.cc \
- fusb_sysconfig_win32.cc
-
-linux_CODE = \
- fusb_linux.cc \
- fusb_sysconfig_linux.cc
-
-ra_wb_CODE = \
- fusb_ra_wb.cc \
- fusb_sysconfig_ra_wb.cc
-
-
-#
-# include each <foo>_CODE entry here...
-#
-EXTRA_libusrp_la_SOURCES = \
- $(generic_CODE) \
- $(darwin_CODE) \
- $(win32_CODE) \
- $(linux_CODE) \
- $(ra_wb_CODE)
-
-
-# work around automake deficiency
-libusrp_la_common_SOURCES = \
- fusb.cc \
- md5.c \
- usrp_basic.cc \
- usrp_config.cc \
- usrp_dbid.cc \
- usrp_local_sighandler.cc \
- usrp_prims.cc \
- usrp_standard.cc
-
-
-if FUSB_TECH_generic
-libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(generic_CODE)
-endif
-
-if FUSB_TECH_darwin
-libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(darwin_CODE)
-endif
-
-if FUSB_TECH_win32
-libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(win32_CODE)
-endif
-
-if FUSB_TECH_linux
-libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(linux_CODE)
-endif
-
-if FUSB_TECH_ra_wb
-libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(ra_wb_CODE)
-endif
-
-
-libusrp_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0
-libusrp_la_LIBADD = $(USB_LIBS) ../misc/libmisc.la
-
-include_HEADERS = \
- usrp_basic.h \
- usrp_bytesex.h \
- usrp_config.h \
- usrp_dbid.h \
- usrp_prims.h \
- usrp_slots.h \
- usrp_standard.h
-
-noinst_HEADERS = \
- ad9862.h \
- fusb.h \
- fusb_darwin.h \
- fusb_win32.h \
- fusb_generic.h \
- fusb_linux.h \
- fusb_ra_wb.h \
- md5.h \
- rate_to_regval.h \
- usrp_local_sighandler.h
-
-usrppython_PYTHON = \
- usrp_dbid.py
-
-noinst_PYTHON = \
- gen_usrp_dbid.py \
- check_data.py \
- dump_data.py
-
-usrp_dbid.py usrp_dbid.h usrp_dbid.cc: gen_usrp_dbid.py usrp_dbid.dat
- PYTHONPATH=$(top_srcdir)/usrp/src srcdir=$(srcdir) $(PYTHON) $(srcdir)/gen_usrp_dbid.py $(srcdir)/usrp_dbid.dat
-
-MOSTLYCLEANFILES = \
- $(BUILT_SOURCES) *~ *.pyc
diff --git a/usrp/host/lib/dxc-io-assignments.gnumeric b/usrp/host/lib/dxc-io-assignments.gnumeric
deleted file mode 100644
index 85e1a8817..000000000
--- a/usrp/host/lib/dxc-io-assignments.gnumeric
+++ /dev/null
Binary files differ
diff --git a/usrp/host/lib/inband/Makefile.am b/usrp/host/lib/inband/Makefile.am
new file mode 100644
index 000000000..9f6a7ab62
--- /dev/null
+++ b/usrp/host/lib/inband/Makefile.am
@@ -0,0 +1,92 @@
+#
+# 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.
+#
+
+include $(top_srcdir)/Makefile.common
+
+INCLUDES = \
+ $(DEFINES) $(OMNITHREAD_INCLUDES) $(PMT_INCLUDES) $(MBLOCK_INCLUDES) \
+ $(USRP_INCLUDES) $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES)
+
+TESTS = test_inband
+
+EXTRA_DIST =
+
+lib_LTLIBRARIES = \
+ libusrp_inband.la \
+ libusrp_inband-qa.la
+
+
+# ------------------------------------------------------------------------
+# Build the inband library
+
+BUILT_SOURCES = \
+ usrp_server_mbh.cc
+
+usrp_server_mbh.cc : usrp_server.mbh
+ $(COMPILE_MBH) usrp_server.mbh usrp_server_mbh.cc
+
+libusrp_inband_la_SOURCES = \
+ $(BUILT_SOURCES) \
+ usrp_server.cc
+
+libusrp_inband_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0
+
+libusrp_inband_la_LIBADD = \
+ $(MBLOCK_LA) \
+ -lstdc++
+
+
+include_HEADERS = \
+ usrp_server.h
+
+noinst_HEADERS = \
+ qa_inband.h \
+ qa_inband_packet_prims.h \
+ qa_inband_usrp_server.h
+
+# ------------------------------------------------------------------------
+# Build the qa code in its own library
+
+libusrp_inband_qa_la_SOURCES = \
+ qa_inband.cc \
+ qa_inband_packet_prims.cc \
+ qa_inband_usrp_server.cc
+
+# magic flags
+libusrp_inband_qa_la_LDFLAGS = $(NO_UNDEFINED) -avoid-version
+
+# link against c++ standard library
+libusrp_inband_qa_la_LIBADD = \
+ libusrp_inband.la \
+ $(CPPUNIT_LIBS) \
+ -lstdc++
+
+# ------------------------------------------------------------------------
+
+noinst_PROGRAMS = \
+ test_inband
+
+test_inband_SOURCES = test_inband.cc
+test_inband_LDADD = libusrp_inband-qa.la
+
+
+MOSTLYCLEANFILES = \
+ $(BUILT_SOURCES) *~ *.pyc
+
diff --git a/usrp/host/lib/inband/dump_packets.py b/usrp/host/lib/inband/dump_packets.py
new file mode 100755
index 000000000..ea27ca515
--- /dev/null
+++ b/usrp/host/lib/inband/dump_packets.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+import sys
+import struct
+from optparse import OptionParser
+
+from usb_packet import *
+
+def dump_packet(raw_pkt, outfile, dump_payload):
+ pkt = usb_packet(raw_pkt)
+ outfile.write(pkt.decoded_flags())
+ outfile.write(' chan= %2d len= %3d timestamp= 0x%08x rssi= % 2d tag= %2d\n' % (
+ pkt.chan(), pkt.payload_len(), pkt.timestamp(), pkt.rssi(), pkt.tag()))
+ if dump_payload:
+ assert pkt.payload_len() % 4 == 0
+ shorts = struct.unpack('<%dh' % (pkt.payload_len() // 2), pkt.payload())
+ for i in range(0, len(shorts), 2):
+ outfile.write(' %6d, %6d\n' % (shorts[i], shorts[i+1]))
+
+
+def dump_packets(infile, outfile, dump_payload):
+ raw_pkt = infile.read(512)
+ while raw_pkt:
+ if len(raw_pkt) != 512:
+ sys.stderr.write("File length is not a multiple of 512 bytes")
+ raise SystemExit, 1
+
+ dump_packet(raw_pkt, outfile, dump_payload)
+ raw_pkt = infile.read(512)
+
+
+def main():
+ parser = OptionParser()
+ parser.add_option('-p', '--dump-payload', action='store_true', default=False,
+ help='dump payload in decimal and hex')
+
+ (options, files) = parser.parse_args()
+ if len(files) == 0:
+ dump_packets(sys.stdin, sys.stdout, options.dump_payload)
+ else:
+ for f in files:
+ dump_packets(open(f, "r"), sys.stdout, options.dump_payload)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/usrp/host/lib/inband/gen_test_packets.py b/usrp/host/lib/inband/gen_test_packets.py
new file mode 100755
index 000000000..1e22722d2
--- /dev/null
+++ b/usrp/host/lib/inband/gen_test_packets.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+
+import random
+import struct
+from pprint import pprint
+from usb_packet import *
+
+MAX_PAYLOAD = 504
+TIME_NOW = 0xffffffff
+
+
+class sequence_generator(object):
+ def __init__(self):
+ self.i = 0
+
+ def __call__(self):
+ t = self.i
+ self.i += 1
+ return t
+
+def gen_shuffled_lengths():
+ valid_lengths = range(0, MAX_PAYLOAD+1, 4) # [0, 4, 8, ... 504]
+ random.shuffle(valid_lengths)
+ return valid_lengths
+
+
+class packet_sequence_generator(object):
+ def __init__(self, channel, lengths):
+ self.next = sequence_generator()
+ self.channel = channel
+ self.lengths = lengths
+
+ def __call__(self, output_file):
+ gen_packet(output_file, self.channel, self.next, self.lengths[0])
+ del self.lengths[0]
+
+
+def gen_packet(output_file, channel, content_generator, payload_len):
+ assert (payload_len % 4) == 0
+ payload = []
+ n_iq = payload_len // 4
+ for n in range(n_iq):
+ payload.append(content_generator()) # I
+ payload.append(content_generator()) # Q
+ for n in range(MAX_PAYLOAD // 4 - n_iq):
+ payload.append(0x0000)
+ payload.append(0xffff)
+
+ assert (len(payload) == MAX_PAYLOAD // 2)
+
+ #print "\npayload_len =", payload_len
+ #pprint(payload)
+
+ output_file.write(make_header(FL_START_OF_BURST|FL_END_OF_BURST,
+ channel, payload_len, TIME_NOW))
+ output_file.write(struct.pack('<252h', *payload))
+
+
+def gen_all_valid_packet_lengths_1_channel(output_file):
+ lengths = gen_shuffled_lengths()
+ npkts = len(lengths) # number of packets we'll generator on each stream
+ pkt_gen_0 = packet_sequence_generator(0, lengths)
+ for i in range(npkts):
+ pkt_gen_0(output_file)
+
+ assert pkt_gen_0.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127
+
+
+def gen_all_valid_packet_lengths_2_channels(output_file):
+ lengths = gen_shuffled_lengths()
+ npkts = len(lengths) # number of packets we'll generator on each stream
+ pkt_gen_0 = packet_sequence_generator(0, lengths)
+ pkt_gen_1 = packet_sequence_generator(1, gen_shuffled_lengths())
+ pkt_gen = (pkt_gen_0, pkt_gen_1)
+
+ which_gen = (npkts * [0]) + (npkts * [1])
+ random.shuffle(which_gen)
+
+ for i in which_gen:
+ pkt_gen[i](output_file)
+
+ assert pkt_gen_0.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127
+ assert pkt_gen_1.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127
+
+if __name__ == '__main__':
+ gen_all_valid_packet_lengths_1_channel(open("all_valid_packet_lengths_1_channel.dat", "w"))
+ gen_all_valid_packet_lengths_2_channels(open("all_valid_packet_lengths_2_channels.dat", "w"))
diff --git a/usrp/host/lib/inband/qa_inband.cc b/usrp/host/lib/inband/qa_inband.cc
new file mode 100644
index 000000000..00a821f39
--- /dev/null
+++ b/usrp/host/lib/inband/qa_inband.cc
@@ -0,0 +1,35 @@
+/* -*- 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.
+ */
+
+#include <qa_inband.h>
+#include <qa_inband_packet_prims.h>
+#include <qa_inband_usrp_server.h>
+
+CppUnit::TestSuite *
+qa_inband::suite()
+{
+ CppUnit::TestSuite *s = new CppUnit::TestSuite("inband");
+
+ s->addTest (qa_inband_packet_prims::suite());
+ s->addTest (qa_inband_usrp_server::suite());
+
+ return s;
+}
diff --git a/usrp/host/lib/inband/qa_inband.h b/usrp/host/lib/inband/qa_inband.h
new file mode 100644
index 000000000..92386f955
--- /dev/null
+++ b/usrp/host/lib/inband/qa_inband.h
@@ -0,0 +1,35 @@
+/* -*- 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_QA_INBAND_H
+#define INCLUDED_QA_INBAND_H
+
+#include <cppunit/TestSuite.h>
+
+//! collect all the tests for the user server
+
+class qa_inband {
+ public:
+ //! return suite of tests for all of usrp server
+ static CppUnit::TestSuite *suite();
+};
+
+#endif /* INCLUDED_QA_INBAND_H */
diff --git a/usrp/host/lib/inband/qa_inband_packet_prims.cc b/usrp/host/lib/inband/qa_inband_packet_prims.cc
new file mode 100644
index 000000000..9d9a0c70e
--- /dev/null
+++ b/usrp/host/lib/inband/qa_inband_packet_prims.cc
@@ -0,0 +1,161 @@
+/* -*- 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 <qa_inband_packet_prims.h>
+#include <cppunit/TestAssert.h>
+#include <stdio.h>
+#include <usrp_inband_usb_packet.h> // will change on gigabit crossover
+
+typedef usrp_inband_usb_packet transport_pkt;
+
+void
+qa_inband_packet_prims::test_flags()
+{
+ transport_pkt pkt;
+
+ // Test each one of the flags while ensuring no other fields become set in the process
+ pkt.set_header(pkt.FL_START_OF_BURST,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(1, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(pkt.FL_END_OF_BURST,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(pkt.FL_OVERRUN,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(pkt.FL_UNDERRUN,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(pkt.FL_DROPPED,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ // test of all fields set
+ pkt.set_header(
+ pkt.FL_START_OF_BURST |
+ pkt.FL_END_OF_BURST |
+ pkt.FL_UNDERRUN |
+ pkt.FL_OVERRUN |
+ pkt.FL_DROPPED
+ ,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(1, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+
+}
+//////////////////////////////////////////////////////////////////////
+
+void
+qa_inband_packet_prims::test_fields()
+{
+ transport_pkt pkt;
+ void * payload;
+
+ // test word0 field exclusiveness
+ //
+ // I want to test max values of each field to ensure field boundaries
+ // but these max values could change based on technology? The
+ // max payload is returned by a private method so the code is not
+ // technology dependent
+ pkt.set_header(0,16,0,0);
+ CPPUNIT_ASSERT_EQUAL(16, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(0,0,8,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(8, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0,pkt.payload_len());
+
+ pkt.set_header(0,0,0,pkt.max_payload());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(pkt.max_payload(), pkt.payload_len());
+
+ // test timestamp, shouldn't have to test other fields since
+ // setting the timestamp only has the ability to affect one word
+ pkt.set_timestamp(54);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(54), pkt.timestamp());
+
+ // test the payload, ensure no other fields overwritten
+ //
+ // is there a better test for this?
+ pkt.set_header(0,0,0,0);
+ payload = malloc(pkt.payload_len());
+ memset(payload, 'f', pkt.payload_len());
+ memcpy(pkt.payload(), payload, pkt.payload_len());
+ CPPUNIT_ASSERT_EQUAL(0, memcmp(pkt.payload(), payload, pkt.payload_len()));
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+ free(payload);
+
+}
+//////////////////////////////////////////////////////////////////////
diff --git a/usrp/host/lib/inband/qa_inband_packet_prims.h b/usrp/host/lib/inband/qa_inband_packet_prims.h
new file mode 100644
index 000000000..5e60c60e7
--- /dev/null
+++ b/usrp/host/lib/inband/qa_inband_packet_prims.h
@@ -0,0 +1,41 @@
+/* -*- 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 QA_INBAND_PACKET_PRIMS_H
+#define QA_INBAND_PACKET_PRIMS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+class qa_inband_packet_prims : public CppUnit::TestCase {
+
+ CPPUNIT_TEST_SUITE(qa_inband_packet_prims);
+ CPPUNIT_TEST(test_flags);
+ CPPUNIT_TEST(test_fields);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ void test_flags();
+ void test_fields();
+
+};
+
+#endif /* INCLUDED_QA_INBAND_PACKET_PRIMS_H */
diff --git a/usrp/host/lib/inband/qa_inband_usrp_server.cc b/usrp/host/lib/inband/qa_inband_usrp_server.cc
new file mode 100644
index 000000000..2885a4d88
--- /dev/null
+++ b/usrp/host/lib/inband/qa_inband_usrp_server.cc
@@ -0,0 +1,455 @@
+/* -*- 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 <qa_inband_usrp_server.h>
+#include <cppunit/TestAssert.h>
+#include <stdio.h>
+#include <usrp_server.h>
+#include <mb_mblock.h>
+#include <mb_runtime.h>
+#include <mb_protocol_class.h>
+#include <mb_class_registry.h>
+#include <vector>
+#include <iostream>
+
+static pmt_t s_cmd_allocate_channel = pmt_intern("cmd-allocate-channel");
+static pmt_t s_response_allocate_channel = pmt_intern("response-allocate-channel");
+static pmt_t s_send_allocate_channel = pmt_intern("send-allocate-channel");
+static pmt_t s_cmd_deallocate_channel = pmt_intern("cmd-deallocate-channel");
+static pmt_t s_response_deallocate_channel = pmt_intern("response-deallocate-channel");
+static pmt_t s_send_deallocate_channel = pmt_intern("send-deallocate-channel");
+static pmt_t s_cmd_max_capacity = pmt_intern("cmd-max-capacity");
+static pmt_t s_response_max_capacity = pmt_intern("response-max-capacity");
+static pmt_t s_cmd_ntx_chan = pmt_intern("cmd-ntx-chan");
+static pmt_t s_cmd_nrx_chan = pmt_intern("cmd-nrx-chan");
+static pmt_t s_response_ntx_chan = pmt_intern("response-ntx-chan");
+static pmt_t s_response_nrx_chan = pmt_intern("response-nrx-chan");
+static pmt_t s_cmd_current_capacity_allocation = pmt_intern("cmd-current-capacity-allocation");
+static pmt_t s_response_current_capacity_allocation = pmt_intern("response-current-capacity-allocation");
+
+
+// ----------------------------------------------------------------------------------------------
+
+class qa_alloc_top : public mb_mblock
+{
+ mb_port_sptr d_tx;
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+
+ long d_nmsgs_to_recv;
+ long d_nrecvd;
+
+ long d_max_capacity;
+ long d_ntx_chan, d_nrx_chan;
+
+ long d_nstatus;
+ long d_nstatus_to_recv;
+
+ public:
+ qa_alloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~qa_alloc_top();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void check_message(mb_message_sptr msg);
+ void run_tests();
+};
+
+qa_alloc_top::qa_alloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_nrecvd=0;
+ d_nmsgs_to_recv = 7;
+ d_nstatus=0;
+ d_nstatus_to_recv = 3;
+
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Test the TX side
+ define_component("server", "usrp_server", PMT_F);
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+
+}
+
+qa_alloc_top::~qa_alloc_top(){}
+
+void
+qa_alloc_top::initial_transition()
+{
+ // Retrieve information about the USRP, then run tests
+ d_cs->send(s_cmd_max_capacity, pmt_list1(PMT_F));
+ d_cs->send(s_cmd_ntx_chan, pmt_list1(PMT_F));
+ d_cs->send(s_cmd_nrx_chan, pmt_list1(PMT_F));
+}
+
+void
+qa_alloc_top::run_tests()
+{
+ std::cout << "[qa_alloc_top] Starting tests...\n";
+ // should be able to allocate 1 byte
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+
+ // should not be able to allocate max capacity after 100 bytes were allocated
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::RQSTD_CAPACITY_UNAVAIL), pmt_from_long(d_max_capacity)));
+
+ // keep allocating a little more until all of the channels are used and test the error response
+ // we start at 1 since we've already allocated 1 channel
+ for(int i=1; i < d_ntx_chan; i++) {
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+ d_nmsgs_to_recv++;
+ }
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_UNAVAIL), pmt_from_long(1)));
+
+ // test out the same on the RX side
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::RQSTD_CAPACITY_UNAVAIL), pmt_from_long(d_max_capacity)));
+
+ for(int i=1; i < d_nrx_chan; i++) {
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+ d_nmsgs_to_recv++;
+ }
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_UNAVAIL), pmt_from_long(1)));
+
+ // when all is said and done, there should be d_ntx_chan+d_ntx_chan bytes allocated
+ d_cs->send(s_cmd_current_capacity_allocation, pmt_list1(pmt_from_long(d_ntx_chan+d_nrx_chan)));
+}
+
+void
+qa_alloc_top::handle_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+
+ if ((pmt_eq(msg->port_id(), d_tx->port_symbol())
+ || pmt_eq(msg->port_id(), d_rx->port_symbol()))
+ && pmt_eq(msg->signal(), s_response_allocate_channel))
+ check_message(msg);
+
+ if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
+
+ if(pmt_eq(msg->signal(), s_response_max_capacity)) {
+ d_max_capacity = pmt_to_long(pmt_nth(1, data));
+ std::cout << "[qa_alloc_top] USRP has max capacity of " << d_max_capacity << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_ntx_chan)) {
+ d_ntx_chan = pmt_to_long(pmt_nth(1, data));
+ std::cout << "[qa_alloc_top] USRP tx channels: " << d_ntx_chan << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_nrx_chan)) {
+ d_nrx_chan = pmt_to_long(pmt_nth(1, data));
+ std::cout << "[qa_alloc_top] USRP rx channels: " << d_nrx_chan << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) {
+ check_message(msg);
+ }
+
+ d_nstatus++;
+
+ if(d_nstatus==d_nstatus_to_recv)
+ run_tests();
+ }
+}
+
+void
+qa_alloc_top::check_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+
+ pmt_t expected_result = pmt_nth(0, data);
+ pmt_t result = pmt_nth(1, data);
+
+ d_nrecvd++;
+
+
+ if(!pmt_eqv(expected_result, result)) {
+ std::cout << "Got: " << result << " Expected: " << expected_result << "\n";
+ shutdown_all(PMT_F);
+ } else {
+ std::cout << "[qa_alloc_top] Received expected response for message " << d_nrecvd << "\n";
+ }
+
+ if(d_nrecvd == d_nmsgs_to_recv)
+ shutdown_all(PMT_T);
+}
+
+REGISTER_MBLOCK_CLASS(qa_alloc_top);
+
+// ----------------------------------------------------------------------------------------------
+
+class qa_dealloc_top : public mb_mblock
+{
+ mb_port_sptr d_tx;
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+
+ long d_max_capacity;
+ long d_ntx_chan, d_nrx_chan;
+
+ long d_nstatus;
+ long d_nstatus_to_recv;
+
+ long d_nalloc_to_recv;
+ long d_nalloc_recvd;
+
+ long d_ndealloc_to_recv;
+ long d_ndealloc_recvd;
+
+ std::vector<long> d_tx_chans;
+ std::vector<long> d_rx_chans;
+
+ public:
+ qa_dealloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~qa_dealloc_top();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void check_allocation(mb_message_sptr msg);
+ void check_deallocation(mb_message_sptr msg);
+ void allocate_max();
+ void deallocate_all();
+};
+
+qa_dealloc_top::qa_dealloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_ndealloc_recvd=0;
+ d_ndealloc_to_recv = 0;
+ d_nalloc_recvd=0;
+ d_nalloc_to_recv = 0;
+ d_nstatus=0;
+ d_nstatus_to_recv = 3;
+
+ d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
+ d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
+ d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
+
+ // Test the TX side
+ define_component("server", "usrp_server", PMT_F);
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+}
+
+qa_dealloc_top::~qa_dealloc_top(){}
+
+void
+qa_dealloc_top::initial_transition()
+{
+ // Retrieve information about the USRP, then run tests
+ d_cs->send(s_cmd_max_capacity, pmt_list1(PMT_F));
+ d_cs->send(s_cmd_ntx_chan, pmt_list1(PMT_F));
+ d_cs->send(s_cmd_nrx_chan, pmt_list1(PMT_F));
+}
+
+void
+qa_dealloc_top::allocate_max()
+{
+ std::cout << "[qa_dealloc_top] Max allocating...\n";
+
+ // Keep allocating until we hit the maximum number of channels
+ for(int i=0; i < d_ntx_chan; i++) {
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+ d_nalloc_to_recv++;
+ }
+ for(int i=0; i < d_nrx_chan; i++) {
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+ d_nalloc_to_recv++;
+ }
+}
+
+void
+qa_dealloc_top::deallocate_all() {
+
+ // Deallocate all of the channels that were allocated from allocate_max()
+ for(int i=0; i < (int)d_tx_chans.size(); i++) {
+ d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_T, pmt_from_long(d_tx_chans[i])));
+ d_ndealloc_to_recv++;
+ }
+ for(int i=0; i < (int)d_rx_chans.size(); i++) {
+ d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_T, pmt_from_long(d_rx_chans[i])));
+ d_ndealloc_to_recv++;
+ }
+
+ // Should get permission denied errors trying to re-dealloc the channels, as we no
+ // longer have permission to them after deallocating
+ for(int i=0; i < (int)d_tx_chans.size(); i++) {
+ d_tx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::PERMISSION_DENIED), pmt_from_long(d_tx_chans[i])));
+ d_ndealloc_to_recv++;
+ }
+ for(int i=0; i < (int)d_rx_chans.size(); i++) {
+ d_rx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::PERMISSION_DENIED), pmt_from_long(d_rx_chans[i])));
+ d_ndealloc_to_recv++;
+ }
+
+ // Try to deallocate a channel that doesn't exist on both sides, the last element in the vectors
+ // is the highest channel number, so we take that plus 1
+ d_ndealloc_to_recv+=2;
+ d_tx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_INVALID), pmt_from_long(d_rx_chans.back()+1)));
+ d_rx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_INVALID), pmt_from_long(d_rx_chans.back()+1)));
+
+
+ // The used capacity should be back to 0 now that we've deallocated everything
+ d_cs->send(s_cmd_current_capacity_allocation, pmt_list1(pmt_from_long(0)));
+}
+
+void
+qa_dealloc_top::handle_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+ if (pmt_eq(msg->port_id(), d_tx->port_symbol())
+ || pmt_eq(msg->port_id(), d_rx->port_symbol())) {
+
+ if(pmt_eq(msg->signal(), s_response_allocate_channel)) {
+ check_allocation(msg);
+ }
+
+ if(pmt_eq(msg->signal(), s_response_deallocate_channel)){
+ check_deallocation(msg);
+ }
+ }
+
+ if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
+
+ if(pmt_eq(msg->signal(), s_response_max_capacity)) {
+ d_max_capacity = pmt_to_long(pmt_nth(1, data));
+ std::cout << "[qa_dealloc_top] USRP has max capacity of " << d_max_capacity << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_ntx_chan)) {
+ d_ntx_chan = pmt_to_long(pmt_nth(1, data));
+ std::cout << "[qa_dealloc_top] USRP tx channels: " << d_ntx_chan << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_nrx_chan)) {
+ d_nrx_chan = pmt_to_long(pmt_nth(1, data));
+ std::cout << "[qa_dealloc_top] USRP rx channels: " << d_nrx_chan << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) {
+ // the final command is a capacity check which should be 0, then we shutdown
+ pmt_t expected_result = pmt_nth(0, data);
+ pmt_t result = pmt_nth(1, data);
+
+ if(pmt_eqv(expected_result, result))
+ shutdown_all(PMT_T);
+ else
+ shutdown_all(PMT_F);
+ }
+
+ d_nstatus++;
+
+ if(d_nstatus==d_nstatus_to_recv)
+ allocate_max();
+ }
+}
+
+void
+qa_dealloc_top::check_deallocation(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+
+ pmt_t expected_result = pmt_nth(0, data);
+ pmt_t result = pmt_nth(1, data);
+
+ d_ndealloc_recvd++;
+
+ if(!pmt_eqv(expected_result, result)) {
+ std::cout << "Got: " << result << " Expected: " << expected_result << "\n";
+ shutdown_all(PMT_F);
+ } else {
+ std::cout << "[qa_dealloc_top] Received expected deallocation response for message " << d_ndealloc_recvd << "\n";
+ }
+}
+
+void
+qa_dealloc_top::check_allocation(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+ pmt_t channel = pmt_nth(2, data);
+
+ d_nalloc_recvd++;
+
+ if(pmt_eqv(status, PMT_F)) {
+ std::cout << "[qa_dealloc_top] Unexpected error response when allocating channels\n";
+ shutdown_all(PMT_F);
+ } else {
+ // store all of the allocate channel numbers
+ if(pmt_eq(msg->port_id(), d_tx->port_symbol()))
+ d_tx_chans.push_back(pmt_to_long(channel));
+ if(pmt_eq(msg->port_id(), d_rx->port_symbol()))
+ d_rx_chans.push_back(pmt_to_long(channel));
+ }
+
+ if(d_nalloc_recvd == d_nalloc_to_recv) {
+
+ std::cout << "[qa_dealloc_top] Allocated TX channels: ";
+ for(int i=0; i < (int)d_tx_chans.size(); i++)
+ std::cout << d_tx_chans[i] << " ";
+
+ std::cout << "\n[qa_dealloc_top] Allocated RX channels: ";
+ for(int i=0; i < (int)d_rx_chans.size(); i++)
+ std::cout << d_rx_chans[i] << " ";
+ std::cout << "\n";
+
+ deallocate_all(); // once we've allocated all of our channels, try to dealloc them
+ }
+}
+
+REGISTER_MBLOCK_CLASS(qa_dealloc_top);
+
+// ----------------------------------------------------------------------------------------------
+
+void
+qa_inband_usrp_server::test_chan_allocation()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_T;
+
+ rt->run("top", "qa_alloc_top", PMT_F, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
+
+void
+qa_inband_usrp_server::test_chan_deallocation()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_T;
+
+ rt->run("top", "qa_dealloc_top", PMT_F, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
+
+void
+qa_inband_usrp_server::test_fragmentation()
+{
+
+}
diff --git a/usrp/host/lib/inband/qa_inband_usrp_server.h b/usrp/host/lib/inband/qa_inband_usrp_server.h
new file mode 100644
index 000000000..eb0f7a3e0
--- /dev/null
+++ b/usrp/host/lib/inband/qa_inband_usrp_server.h
@@ -0,0 +1,42 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef QA_INBAND_USRP_SERVER_H
+#define QA_INBAND_USRP_SERVER_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+class qa_inband_usrp_server : public CppUnit::TestCase {
+
+ CPPUNIT_TEST_SUITE(qa_inband_usrp_server);
+ CPPUNIT_TEST(test_chan_allocation);
+ CPPUNIT_TEST(test_chan_deallocation);
+ CPPUNIT_TEST(test_fragmentation);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ void test_chan_allocation();
+ void test_chan_deallocation();
+ void test_fragmentation();
+};
+
+#endif /* INCLUDED_QA_INBAND_USRP_SERVER_H */
diff --git a/usrp/host/lib/inband/test_inband.cc b/usrp/host/lib/inband/test_inband.cc
new file mode 100644
index 000000000..49619bef2
--- /dev/null
+++ b/usrp/host/lib/inband/test_inband.cc
@@ -0,0 +1,36 @@
+/* -*- 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.
+ */
+
+#include <cppunit/TextTestRunner.h>
+#include <qa_inband.h>
+
+int
+main(int argc, char **argv)
+{
+
+ CppUnit::TextTestRunner runner;
+
+ runner.addTest(qa_inband::suite ());
+
+ bool was_successful = runner.run("", false);
+
+ return was_successful ? 0 : 1;
+}
diff --git a/usrp/host/lib/inband/usb_packet.py b/usrp/host/lib/inband/usb_packet.py
new file mode 100644
index 000000000..5ca19b790
--- /dev/null
+++ b/usrp/host/lib/inband/usb_packet.py
@@ -0,0 +1,115 @@
+#
+# 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.
+#
+
+import struct
+
+
+FL_OVERRUN = 0x80000000
+FL_UNDERRUN = 0x40000000
+FL_DROPPED = 0x20000000
+FL_END_OF_BURST = 0x10000000
+FL_START_OF_BURST = 0x08000000
+
+FL_ALL_FLAGS = 0xf8000000
+
+FL_OVERRUN_SHIFT = 31
+FL_UNDERRUN_SHIFT = 30
+FL_DROPPED_SHIFT = 29
+FL_END_OF_BURST_SHIFT = 28
+FL_START_OF_BURST_SHIFT = 27
+
+RSSI_MASK = 0x3f
+RSSI_SHIFT = 21
+
+CHAN_MASK = 0x1f
+CHAN_SHIFT = 16
+
+TAG_MASK = 0xf
+TAG_SHIFT = 9
+
+PAYLOAD_LEN_MASK = 0x1ff
+PAYLOAD_LEN_SHIFT = 0
+
+def make_header(flags, chan, payload_len, timestamp, rssi=0, tag=0):
+ word0 = ((flags & FL_ALL_FLAGS)
+ | ((rssi & RSSI_MASK) << RSSI_SHIFT)
+ | ((chan & CHAN_MASK) << CHAN_SHIFT)
+ | ((tag & TAG_MASK) << TAG_SHIFT)
+ | ((payload_len & PAYLOAD_LEN_MASK) << PAYLOAD_LEN_SHIFT))
+ word1 = timestamp
+ return struct.pack('<2I', word0, word1)
+
+
+def _decode(pred, indicator):
+ if pred:
+ return indicator
+ else:
+ return '-'
+
+
+class usb_packet(object):
+ def __init__(self, raw_pkt):
+ assert isinstance(raw_pkt, str) and len(raw_pkt) == 512
+ self._raw_pkt = raw_pkt;
+ (self._word0, self._word1) = struct.unpack('<2I', self._raw_pkt[0:8])
+
+ def timestamp(self):
+ return self._word1
+
+ def rssi(self):
+ return (self._word0 >> RSSI_SHIFT) & RSSI_MASK
+
+ def chan(self):
+ return (self._word0 >> CHAN_SHIFT) & CHAN_MASK
+
+ def tag(self):
+ return (self._word0 >> TAG_SHIFT) & TAG_MASK
+
+ def payload_len(self):
+ return (self._word0 >> PAYLOAD_LEN_SHIFT) & PAYLOAD_LEN_MASK
+
+ def flags(self):
+ return self._word0 & FL_ALL_FLAGS
+
+ def overrun(self):
+ return (self._word0 >> FL_OVERRUN_SHIFT) & 0x1
+
+ def underrun(self):
+ return (self._word0 >> FL_UNDERRUN_SHIFT) & 0x1
+
+ def start_of_burst(self):
+ return (self._word0 >> FL_START_OF_BURST_SHIFT) & 0x1
+
+ def end_of_burst(self):
+ return (self._word0 >> FL_END_OF_BURST_SHIFT) & 0x1
+
+ def dropped(self):
+ return (self._word0 >> FL_DROPPED_SHIFT) & 0x1
+
+ def payload(self):
+ return self._raw_pkt[8:8+self.payload_len()]
+
+ def decoded_flags(self):
+ s = (_decode(self.overrun(), 'O')
+ + _decode(self.underrun(), 'U')
+ + _decode(self.dropped(), 'D')
+ + _decode(self.end_of_burst(), 'E')
+ + _decode(self.start_of_burst(), 'S'))
+ return s
diff --git a/usrp/host/lib/inband/usrp_inband_usb_packet.h b/usrp/host/lib/inband/usrp_inband_usb_packet.h
new file mode 100644
index 000000000..471bfc666
--- /dev/null
+++ b/usrp/host/lib/inband/usrp_inband_usb_packet.h
@@ -0,0 +1,149 @@
+/* -*- 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_USRP_INBAND_USB_PACKET_H_
+#define INCLUDED_USRP_INBAND_USB_PACKET_H_
+
+#include <usrp_bytesex.h>
+#include <mb_mblock.h>
+
+static const int USB_PKT_SIZE = 512; // bytes
+static const int MAX_PAYLOAD = USB_PKT_SIZE-2*sizeof(uint32_t);
+
+class usrp_inband_usb_packet {
+ //
+ // keep raw packet in USRP-endian order
+ //
+ uint32_t d_word0;
+ uint32_t d_timestamp;
+ unsigned char d_payload[MAX_PAYLOAD];
+
+public:
+
+ enum flags {
+ FL_OVERRUN = 0x80000000,
+ FL_UNDERRUN = 0x40000000,
+ FL_DROPPED = 0x20000000,
+ FL_END_OF_BURST = 0x10000000,
+ FL_START_OF_BURST = 0x08000000,
+
+ FL_ALL_FLAGS = 0xf8000000
+ };
+
+ static const int FL_OVERRUN_SHIFT = 31;
+ static const int FL_UNDERRUN_SHIFT = 30;
+ static const int FL_DROPPED_SHIFT = 29;
+ static const int FL_END_OF_BURST_SHIFT = 28;
+ static const int FL_START_OF_BURST_SHIFT = 27;
+
+ static const int RSSI_MASK = 0x3f;
+ static const int RSSI_SHIFT = 21;
+
+ static const int CHAN_MASK = 0x1f;
+ static const int CHAN_SHIFT = 16;
+
+ static const int TAG_MASK = 0xf;
+ static const int TAG_SHIFT = 9;
+
+ static const int PAYLOAD_LEN_MASK = 0x1ff;
+ static const int PAYLOAD_LEN_SHIFT = 0;
+
+public:
+
+ void set_timestamp(uint32_t timestamp){
+ d_timestamp = host_to_usrp_u32(timestamp);
+ }
+
+ void set_end_of_burst() {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ word0 |= 1<<FL_END_OF_BURST_SHIFT;
+ d_word0 = host_to_usrp_u32(word0);
+ }
+
+ void set_header(int flags, int chan, int tag, int payload_len){
+ uint32_t word0 = ((flags & FL_ALL_FLAGS)
+ | ((chan & CHAN_MASK) << CHAN_SHIFT)
+ | ((tag & TAG_MASK) << TAG_SHIFT)
+ | ((payload_len & PAYLOAD_LEN_MASK) << PAYLOAD_LEN_SHIFT));
+ d_word0 = host_to_usrp_u32(word0);
+ }
+
+ uint32_t timestamp() const {
+ return usrp_to_host_u32(d_timestamp);
+ }
+
+ int rssi() const {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ return (word0 >> RSSI_SHIFT) & RSSI_MASK;
+ }
+
+ int chan() const {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ return (word0 >> CHAN_SHIFT) & CHAN_MASK;
+ }
+
+ int tag() const {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ return (word0 >> TAG_SHIFT) & TAG_MASK;
+ }
+
+ int payload_len() const {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ return (word0 >> PAYLOAD_LEN_SHIFT) & PAYLOAD_LEN_MASK;
+ }
+
+ int flags() const {
+ return usrp_to_host_u32(d_word0) & FL_ALL_FLAGS;
+ }
+
+ int overrun() const {
+ return (usrp_to_host_u32(d_word0) & FL_OVERRUN) >> FL_OVERRUN_SHIFT;
+ }
+
+
+ int underrun() const {
+ return (usrp_to_host_u32(d_word0) & FL_UNDERRUN) >> FL_UNDERRUN_SHIFT;
+ }
+
+
+ int start_of_burst() const {
+ return (usrp_to_host_u32(d_word0) & FL_START_OF_BURST) >> FL_START_OF_BURST_SHIFT;
+ }
+
+ int end_of_burst() const {
+ return (usrp_to_host_u32(d_word0) & FL_END_OF_BURST) >> FL_END_OF_BURST_SHIFT;
+ }
+
+ int dropped() const {
+ return (usrp_to_host_u32(d_word0) & FL_DROPPED) >> FL_DROPPED_SHIFT;
+ }
+
+ unsigned char *payload() {
+ return d_payload;
+ }
+
+ static int max_payload() {
+ return MAX_PAYLOAD;
+ }
+
+};
+
+#endif
diff --git a/usrp/host/lib/inband/usrp_server.cc b/usrp/host/lib/inband/usrp_server.cc
new file mode 100644
index 000000000..5041a9213
--- /dev/null
+++ b/usrp/host/lib/inband/usrp_server.cc
@@ -0,0 +1,394 @@
+/* -*- 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 <usrp_server.h>
+#include <iostream>
+#include <usrp_inband_usb_packet.h>
+#include <mb_class_registry.h>
+#include <vector>
+
+typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy
+
+// FIXME We should machine generate these by a simple preprocessor run over this file
+//
+// These are all the messages that we expect to receive.
+//
+// We "intern" these here (make them into symbols) so that our
+// comparisions below are effectively pointer comparisons.
+
+static pmt_t s_cmd_allocate_channel = pmt_intern("cmd-allocate-channel");
+static pmt_t s_cmd_close = pmt_intern("cmd-close");
+static pmt_t s_cmd_deallocate_channel = pmt_intern("cmd-deallocate-channel");
+static pmt_t s_cmd_open = pmt_intern("cmd-open");
+static pmt_t s_cmd_start_recv_raw_samples = pmt_intern("cmd-start-recv-raw-samples");
+static pmt_t s_cmd_stop_recv_raw_samples = pmt_intern("cmd-stop-recv-raw-samples");
+static pmt_t s_cmd_to_control_channel = pmt_intern("cmd-to-control-channel");
+static pmt_t s_cmd_xmit_raw_frame = pmt_intern("cmd-xmit-raw-frame");
+static pmt_t s_cmd_max_capacity = pmt_intern("cmd-max-capacity");
+static pmt_t s_cmd_ntx_chan = pmt_intern("cmd-ntx-chan");
+static pmt_t s_cmd_nrx_chan = pmt_intern("cmd-nrx-chan");
+static pmt_t s_cmd_current_capacity_allocation = pmt_intern("cmd-current-capacity-allocation");
+static pmt_t s_response_allocate_channel = pmt_intern("response-allocate-channel");
+static pmt_t s_response_close = pmt_intern("response-close");
+static pmt_t s_response_deallocate_channel = pmt_intern("response-deallocate-channel");
+static pmt_t s_response_from_control_channel = pmt_intern("response-from-control-channel");
+static pmt_t s_response_open = pmt_intern("response-open");
+static pmt_t s_response_recv_raw_samples = pmt_intern("response-recv-raw-samples");
+static pmt_t s_response_xmit_raw_frame = pmt_intern("response-xmit-raw-frame");
+static pmt_t s_response_max_capacity = pmt_intern("response-max-capacity");
+static pmt_t s_response_ntx_chan = pmt_intern("response-ntx-chan");
+static pmt_t s_response_nrx_chan = pmt_intern("response-nrx-chan");
+static pmt_t s_response_current_capacity_allocation = pmt_intern("response-current-capacity-allocation");
+
+static std::string
+str(long x)
+{
+ std::ostringstream s;
+ s << x;
+ return s.str();
+}
+
+usrp_server::usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(rt, instance_name, user_arg)
+{
+ // define our ports
+
+ // control & status port
+ d_cs = define_port("cs", "usrp-server-cs", true, mb_port::EXTERNAL);
+
+ // ports
+ //
+ // (if/when we do replicated ports, these will be replaced by a
+ // single replicated port)
+ for(int port=0; port < N_PORTS; port++) {
+ d_tx.push_back(define_port("tx"+str(port), "usrp-tx", true, mb_port::EXTERNAL));
+ d_rx.push_back(define_port("rx"+str(port), "usrp-rx", true, mb_port::EXTERNAL));
+ }
+
+ // FIXME ... initializing to 2 channels on each for now, eventually we should
+ // query the FPGA to get these values
+ d_ntx_chan = 2;
+ d_nrx_chan = 2;
+
+ // Initialize capacity on each channel to 0 and to no owner
+ for(int chan=0; chan < d_ntx_chan; chan++) {
+ d_chaninfo_tx[chan].assigned_capacity = 0;
+ d_chaninfo_tx[chan].owner = PMT_NIL;
+ }
+ for(int chan=0; chan < d_nrx_chan; chan++) {
+ d_chaninfo_rx[chan].assigned_capacity = 0;
+ d_chaninfo_rx[chan].owner = PMT_NIL;
+ }
+}
+
+usrp_server::~usrp_server()
+{
+}
+
+
+void
+usrp_server::initial_transition()
+{
+ // the initial transition
+}
+
+void
+usrp_server::handle_message(mb_message_sptr msg)
+{
+ pmt_t event = msg->signal(); // the "name" of the message
+ pmt_t port_id = msg->port_id(); // which port it came in on
+ pmt_t data = msg->data();
+ pmt_t metadata = msg->metadata();
+ pmt_t invocation_handle;
+ pmt_t reply_data;
+ pmt_t status;
+
+ if (1){
+ std::cout << "[USRP_SERVER] event: " << event << std::endl;
+ std::cout << "[USRP_SERVER] port_id: " << port_id << std::endl;
+ }
+
+ // It would be nice if this were all table driven, and we could
+ // compute our state transition as f(current_state, port_id, signal)
+
+ if (pmt_eq(port_id, d_cs->port_symbol())){ // message came in on our control/status port
+
+ if (pmt_eq(event, s_cmd_open)){
+ // extract args from data
+ invocation_handle = pmt_nth(0, data);
+ long which_usrp = pmt_to_long(pmt_nth(1, data)); // integer usrp id, usually 0
+
+ // Do the right thing....
+ // build a reply
+
+ // if everything OK
+ status = PMT_T;
+ reply_data = pmt_list2(invocation_handle, status);
+
+ // ...and send it
+ d_cs->send(s_response_open, reply_data);
+ return;
+ }
+ else if (pmt_eq(event, s_cmd_close)){
+ // ...
+ }
+ else if (pmt_eq(event, s_cmd_max_capacity)) {
+ invocation_handle = pmt_nth(0, data);
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(max_capacity()));
+ d_cs->send(s_response_max_capacity, reply_data);
+ return;
+ }
+ else if (pmt_eq(event, s_cmd_ntx_chan)) {
+ invocation_handle = pmt_nth(0, data);
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(d_ntx_chan));
+ d_cs->send(s_response_ntx_chan, reply_data);
+ }
+ else if (pmt_eq(event, s_cmd_nrx_chan)) {
+ invocation_handle = pmt_nth(0, data);
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(d_nrx_chan));
+ d_cs->send(s_response_nrx_chan, reply_data);
+ }
+ else if (pmt_eq(event, s_cmd_current_capacity_allocation)) {
+ invocation_handle = pmt_nth(0, data);
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(current_capacity_allocation()));
+ d_cs->send(s_response_current_capacity_allocation, reply_data);
+ }
+ goto unhandled;
+ }
+
+ if (pmt_eq(event, s_cmd_allocate_channel)){
+ handle_cmd_allocate_channel(port_id, data);
+ return;
+ }
+
+ if (pmt_eq(event, s_cmd_deallocate_channel)) {
+ handle_cmd_deallocate_channel(port_id, data);
+ return;
+ }
+
+ if (pmt_eq(event, s_cmd_xmit_raw_frame)){
+ handle_cmd_xmit_raw_frame(data);
+ return;
+ }
+
+ unhandled:
+ std::cout << "[USRP_SERVER] unhandled msg: " << msg << std::endl;
+}
+
+// Return -1 if it is not an RX port, or an index
+int usrp_server::tx_port_index(pmt_t port_id) {
+
+ for(int i=0; i < (int) d_tx.size(); i++)
+ if(pmt_eq(d_tx[i]->port_symbol(), port_id))
+ return i;
+
+ return -1;
+}
+
+// Return -1 if it is not an RX port, or an index
+int usrp_server::rx_port_index(pmt_t port_id) {
+
+ for(int i=0; i < (int) d_rx.size(); i++)
+ if(pmt_eq(d_rx[i]->port_symbol(), port_id))
+ return i;
+
+ return -1;
+}
+
+// Go through all TX and RX channels, sum up the assigned capacity
+// and return it
+long usrp_server::current_capacity_allocation() {
+ long capacity = 0;
+
+ for(int chan=0; chan < d_ntx_chan; chan++)
+ capacity += d_chaninfo_tx[chan].assigned_capacity;
+
+ for(int chan=0; chan < d_nrx_chan; chan++)
+ capacity += d_chaninfo_rx[chan].assigned_capacity;
+
+ return capacity;
+}
+
+void usrp_server::handle_cmd_allocate_channel(pmt_t port_id, pmt_t data) {
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ long rqstd_capacity = pmt_to_long(pmt_nth(1, data));
+ long chan, port;
+ pmt_t reply_data;
+
+ // If it's a TX port, allocate on a free channel, else check if it's a RX port
+ // and allocate.
+ if((port = tx_port_index(port_id)) != -1) {
+
+ // Check capacity exists
+ if((D_USB_CAPACITY - current_capacity_allocation()) < rqstd_capacity) {
+ reply_data = pmt_list3(invocation_handle, pmt_from_long(RQSTD_CAPACITY_UNAVAIL), PMT_NIL); // no capacity available
+ d_tx[port]->send(s_response_allocate_channel, reply_data);
+ return;
+ }
+
+ // Find a free channel, assign the capacity and respond
+ for(chan=0; chan < d_ntx_chan; chan++) {
+ if(d_chaninfo_tx[chan].owner == PMT_NIL) {
+ d_chaninfo_tx[chan].owner = port_id;
+ d_chaninfo_tx[chan].assigned_capacity = rqstd_capacity;
+ reply_data = pmt_list3(invocation_handle, PMT_T, pmt_from_long(chan));
+ d_tx[port]->send(s_response_allocate_channel, reply_data);
+ return;
+ }
+ }
+
+ std::cout << "[USRP_SERVER] Couldnt find a TX chan\n";
+
+ reply_data = pmt_list3(invocation_handle, pmt_from_long(CHANNEL_UNAVAIL), PMT_NIL); // no free TX chan found
+ d_tx[port]->send(s_response_allocate_channel, reply_data);
+ return;
+ }
+
+ // Repeat the same process on the RX side if the port was not determined to be TX
+ if((port = rx_port_index(port_id)) != -1) {
+
+ if((D_USB_CAPACITY - current_capacity_allocation()) < rqstd_capacity) {
+ reply_data = pmt_list3(invocation_handle, pmt_from_long(RQSTD_CAPACITY_UNAVAIL), PMT_NIL); // no capacity available
+ d_rx[port]->send(s_response_allocate_channel, reply_data);
+ return;
+ }
+
+ for(chan=0; chan < d_nrx_chan; chan++) {
+ if(d_chaninfo_rx[chan].owner == PMT_NIL) {
+ d_chaninfo_rx[chan].owner = port_id;
+ d_chaninfo_rx[chan].assigned_capacity = rqstd_capacity;
+ reply_data = pmt_list3(invocation_handle, PMT_T, pmt_from_long(chan));
+ d_rx[port]->send(s_response_allocate_channel, reply_data);
+ return;
+ }
+ }
+
+ std::cout << "[USRP_SERVER] Couldnt find a RX chan\n";
+ reply_data = pmt_list3(invocation_handle, pmt_from_long(CHANNEL_UNAVAIL), PMT_NIL); // no free RX chan found
+ d_rx[port]->send(s_response_allocate_channel, reply_data);
+ return;
+ }
+}
+
+// Check the port type and deallocate assigned capacity based on this, ensuring
+// that the owner of the method invocation is the owner of the port and that
+// the channel number is valid.
+void usrp_server::handle_cmd_deallocate_channel(pmt_t port_id, pmt_t data) {
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ long channel = pmt_to_long(pmt_nth(1, data));
+ long port;
+ pmt_t reply_data;
+
+ // Check that the channel number is valid, and that the calling port is the owner
+ // of the channel, and if so remove the assigned capacity.
+ if((port = tx_port_index(port_id)) != -1) {
+
+ if(channel >= d_ntx_chan) {
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(CHANNEL_INVALID)); // not a legit channel number
+ d_tx[port]->send(s_response_deallocate_channel, reply_data);
+ return;
+ }
+
+ if(d_chaninfo_tx[channel].owner != port_id) {
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(PERMISSION_DENIED)); // not the owner of the port
+ d_tx[port]->send(s_response_deallocate_channel, reply_data);
+ return;
+ }
+
+ d_chaninfo_tx[channel].assigned_capacity = 0;
+ d_chaninfo_tx[channel].owner = PMT_NIL;
+
+ reply_data = pmt_list2(invocation_handle, PMT_T);
+ d_tx[port]->send(s_response_deallocate_channel, reply_data);
+ return;
+ }
+
+ // Repeated process on the RX side
+ if((port = rx_port_index(port_id)) != -1) {
+
+ if(channel >= d_nrx_chan) {
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(CHANNEL_INVALID)); // not a legit channel number
+ d_rx[port]->send(s_response_deallocate_channel, reply_data);
+ return;
+ }
+
+ if(d_chaninfo_rx[channel].owner != port_id) {
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(PERMISSION_DENIED)); // not the owner of the port
+ d_rx[port]->send(s_response_deallocate_channel, reply_data);
+ return;
+ }
+
+ d_chaninfo_rx[channel].assigned_capacity = 0;
+ d_chaninfo_rx[channel].owner = PMT_NIL;
+
+ reply_data = pmt_list2(invocation_handle, PMT_T);
+ d_rx[port]->send(s_response_deallocate_channel, reply_data);
+ return;
+ }
+
+}
+
+void usrp_server::handle_cmd_xmit_raw_frame(pmt_t data) {
+
+ size_t n_bytes, psize;
+ long max_payload_len = transport_pkt::max_payload();
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ long channel = pmt_to_long(pmt_nth(1, data));
+ const void *samples = pmt_uniform_vector_elements(pmt_nth(2, data), n_bytes);
+ long timestamp = pmt_to_long(pmt_nth(3, data));
+
+ // Determine the number of packets to allocate contiguous memory for bursting over the
+ // USB and get a pointer to the memory to be used in building the packets
+ long n_packets = static_cast<long>(std::ceil(n_bytes / (double)max_payload_len));
+ pmt_t v_packets = pmt_make_u8vector(sizeof(transport_pkt) * n_packets, 0);
+
+ transport_pkt *pkts =
+ (transport_pkt *) pmt_u8vector_writeable_elements(v_packets, psize);
+
+ for(int n=0; n < n_packets; n++) {
+
+ long payload_len = std::min((long)(n_bytes-(n*max_payload_len)), (long)max_payload_len);
+
+ if(n == 0) { // first packet gets start of burst flag and timestamp
+ pkts[n].set_header(pkts[n].FL_START_OF_BURST, channel, 0, payload_len);
+ pkts[n].set_timestamp(timestamp);
+ } else {
+ pkts[n].set_header(0, channel, 0, payload_len);
+ pkts[n].set_timestamp(0xffffffff);
+ }
+
+ memcpy(pkts[n].payload(), (uint8_t *)samples+(max_payload_len * n), payload_len);
+ }
+
+ pkts[n_packets-1].set_end_of_burst(); // set the last packet's end of burst
+
+ // interface with the USRP to send the USB packet, since the memory is
+ // contiguous, this should be a serious of memory copies to the bus, each being
+ // USB_PKT_SIZE * MAX_PACKET_BURST bytes worth of data (given a full burst)
+}
+
+REGISTER_MBLOCK_CLASS(usrp_server);
diff --git a/usrp/host/lib/inband/usrp_server.h b/usrp/host/lib/inband/usrp_server.h
new file mode 100644
index 000000000..87c2768e5
--- /dev/null
+++ b/usrp/host/lib/inband/usrp_server.h
@@ -0,0 +1,82 @@
+/* -*- 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_USRP_SERVER_H
+#define INCLUDED_USRP_SERVER_H
+
+#include <mb_mblock.h>
+#include <vector>
+
+/*!
+ * \brief Implements the lowest-level mblock interface to the USRP
+ */
+class usrp_server : public mb_mblock
+{
+public:
+
+ enum error_codes {
+ RQSTD_CAPACITY_UNAVAIL = 0,
+ CHANNEL_UNAVAIL = 1,
+ CHANNEL_INVALID = 2,
+ PERMISSION_DENIED = 3
+ };
+
+ // our ports
+ enum port_types {
+ RX_PORT = 0,
+ TX_PORT = 1
+ };
+ static const int N_PORTS = 4;
+ std::vector<mb_port_sptr> d_tx, d_rx;
+ mb_port_sptr d_cs;
+
+ static const int D_USB_CAPACITY = 32 * 1024 * 1024;
+ static const int D_MAX_CHANNELS = 16;
+ long d_ntx_chan;
+ long d_nrx_chan;
+
+ struct channel_info {
+ long assigned_capacity; // the capacity currently assignedby the channel
+ pmt_t owner; // port ID of the owner of the channel
+ };
+
+ struct channel_info d_chaninfo_tx[D_MAX_CHANNELS];
+ struct channel_info d_chaninfo_rx[D_MAX_CHANNELS];
+
+public:
+ usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
+ ~usrp_server();
+
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+protected:
+ static int max_capacity() { return D_USB_CAPACITY; }
+
+private:
+ void handle_cmd_allocate_channel(pmt_t port_id, pmt_t data);
+ void handle_cmd_deallocate_channel(pmt_t port_id, pmt_t data);
+ void handle_cmd_xmit_raw_frame(pmt_t data);
+ int rx_port_index(pmt_t port_id);
+ int tx_port_index(pmt_t port_id);
+ long current_capacity_allocation();
+};
+
+#endif /* INCLUDED_USRP_SERVER_H */
diff --git a/usrp/host/lib/inband/usrp_server.mbh b/usrp/host/lib/inband/usrp_server.mbh
new file mode 100644
index 000000000..97bb0e664
--- /dev/null
+++ b/usrp/host/lib/inband/usrp_server.mbh
@@ -0,0 +1,256 @@
+;; -*- scheme -*- ; not really, but tells emacs how to format this
+;;
+;; 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 is an mblock header file
+;;
+;; The format is very much a work-in-progress.
+;; It'll be compiled to C++.
+;; ----------------------------------------------------------------
+
+;; In the outgoing messages described below, invocation-handle is an
+;; identifier provided by the client to tag the method invocation.
+;; The identifier will be returned with the response, to provide the
+;; client with a mechanism to match asynchronous responses with the
+;; commands that generate them. The value of the invocation-handle is
+;; opaque the the server, and is not required by the server to be
+;; unique.
+;;
+;; In the incoming messages described below, invocation-handle is the
+;; identifier provided by the client in the prompting invocation. The
+;; identifier is returned with the response, so that the client has a
+;; mechanism to match asynchronous responses with the commands that
+;; generated them.
+;;
+;; status is either #t, indicating success, or a pair containing
+;; (status-code . message), where status-code is a symbol and message
+;; is a string.
+
+
+;; ----------------------------------------------------------------
+;; usrp-channel
+;;
+;; The protocol class is defined from the client's point-of-view.
+;; (The client port is unconjugated, the server port is conjugated.)
+
+(define-protocol-class usrp-channel
+
+ (:outgoing
+
+ (cmd-allocate-channel invocation-handle capacity-reservation)
+
+ ;; The cmd-allocate-channel message requests that the server
+ ;; allocates a logical channel in the FPGA for use.
+ ;; capacity-reservation specifies the number of bytes/s of
+ ;; interconnect capacity (USB or ethernet) to reserve for this
+ ;; channel. (The reservation is just a sanity check, no OS
+ ;; specific mechanism is used.)
+
+ (cmd-deallocate-channel invocation-handle channel)
+
+ ;; The integer channel specifies the channel to deallocate.
+
+ )
+
+ (:incoming
+
+
+ (response-allocate-channel invocation-handle status channel)
+
+ ;; If successful, a channel the specified capacity was allocated.
+ ;; channel, an integer, indicates which channel was allocated.
+
+ (response-deallocate-channel invocation-handle status)
+
+ ;; If successful, the specified channel and associated interconnect
+ ;; capacity were deallocated.
+
+ )
+ )
+
+;; ----------------------------------------------------------------
+;; usrp-low-level-cs
+;;
+;; The protocol class is defined from the client's point-of-view.
+;; (The client port is unconjugated, the server port is conjugated.)
+;;
+;; This defines a low level control and status interface to the usrp.
+;; This will probably be replaced (or at least augmented) with a
+;; higher level interface. For now, this will allow us to get on
+;; the air.
+;;
+;; The subpackets are lists containing the relevant parameters. The
+;; server will marshall them appropriately. Below is a list of
+;; subpackets. See inband-signaling-usb for details. The opcodes are
+;; symbols; unless otherwise indicated the remaining parameters are
+;; integers. rid values are limited to 3-bits.
+;;
+;; (op-ping-fixed rid ping-value)
+;; (op-ping-fixed-reply rid ping-value)
+;; (op-write-reg reg-number reg-value)
+;; (op-write-reg-masked reg-number reg-value mask-value)
+;; (op-read-reg rid reg-number reg-value)
+;; (op-read-reg-reply rid reg-number reg-value)
+;; (op-i2c-write i2c-addr u8-vec)
+;; (op-i2c-read rid i2c-addr nbytes)
+;; (op-i2c-read-reply rid i2c-addr u8-vec)
+;; (op-spi-write enables format opt-header-bytes u8-vec)
+;; (op-spi-read rid enables format opt-header-bytes nbytes)
+;; (op-spi-read-reply rid u8-vec)
+;; (op-delay ticks)
+
+
+(define-protocol-class usrp-low-level-cs
+
+ (:outgoing
+
+ (cmd-to-control-channel invocation-handle list-of-subpackets)
+
+ )
+
+ (:incoming
+
+ (response-from-control-channel invocation-handle status list-of-subpackets)
+
+ )
+ )
+
+;; ----------------------------------------------------------------
+;; usrp-tx
+;;
+;; The protocol class is defined from the client's point-of-view.
+;; (The client port is unconjugated, the server port is conjugated.)
+
+(define-protocol-class usrp-tx
+ (:include usrp-channel)
+ (:include usrp-low-level-cs)
+
+ (:outgoing
+
+ (cmd-xmit-raw-frame invocation-handle channel samples timestamp)
+
+ ;; The argument channel must be an integer. It specifies the
+ ;; channel on which the frame of samples will be be sent.
+ ;;
+ ;; samples must be a uniform numeric vector. The contents of the
+ ;; sample vector is treated as opaque and is passed on to the FPGA
+ ;; unmodified. It is the responsibility of the sender to ensure
+ ;; that the binary format is sensible for the current FPGA
+ ;; configuration.
+ ;;
+ ;; timestamp is a 32-bit integer that specifies the time at which
+ ;; the first sample in samples shall be sent to the D/A converter.
+ ;; The format and interpration of time is specified in the file
+ ;; inband-signaling-usb
+ )
+
+ (:incoming
+
+ (response-xmit-raw-frame invocation-handle status)
+
+ ;; If successful, the samples of the associated frame have been
+ ;; transmitted to the USRP. This message may be used to implement
+ ;; Tx flow control. The client could for example implement a
+ ;; policy of never having more than 4 unacknowledged
+ ;; cmd-xmit-raw-frame's outstanding.
+
+ )
+ )
+
+;; ----------------------------------------------------------------
+;; usrp-rx
+;;
+;; The protocol class is defined from the client's point-of-view.
+;; (The client port is unconjugated, the server port is conjugated.)
+
+(define-protocol-class usrp-rx
+ (:include usrp-channel)
+ (:include usrp-low-level-cs)
+
+ (:outgoing
+
+ (cmd-start-recv-raw-samples invocation-handle channel)
+
+ ;; The argument channel must be an integer. It specifies the
+ ;; channel from which frames of samples will be be received. The
+ ;; server will return response-recv-raw-samples messages until a
+ ;; cmd-stop-recv-raw-samples message is received.
+
+ (cmd-stop-recv-raw-samples invocation-handle channel)
+
+ ;; The argument channel must be an integer. There is no reply to
+ ;; this message.
+
+ )
+
+ (:incoming
+
+ (response-recv-raw-samples invocation-handle status samples timestamp properties)
+
+ ;; samples is a uniform numeric vector. The contents of the sample
+ ;; vector is treated as opaque and is passed from the FPGA
+ ;; unmodified. It is the responsibility of the receiver to decode
+ ;; the binary format as appropriate for the current FPGA
+ ;; configuration.
+ ;;
+ ;; timestamp is a 32-bit integer that specifies the time at which
+ ;; the first sample in samples was received from the A/D converter.
+ ;; The format and interpretation of time is as specified in the
+ ;; file inband-signaling-usb.
+ ;;
+ ;; properties is a dictionary containing additional (key, value)
+ ;; pairs associated with the reception of these samples. In
+ ;; particular, the map may contain the Received Signal Strength
+ ;; Indication (RSSI) reported by the front end at the time the
+ ;; first sample was received from the A/D.
+
+ )
+ )
+
+
+;; ----------------------------------------------------------------
+;; usrp-server-cs
+;;
+;; Control and status port for usrp-server
+;;
+;; The protocol class is defined from the client's point-of-view.
+;; (The client port is unconjugated, the server port is conjugated.)
+
+(define-protocol-class usrp-server-cs
+
+ (:outgoing
+ (cmd-open invocation-handle which-usrp)
+ (cmd-close invocation-handle)
+ (cmd-max-capacity invocation-handle)
+ (cmd-ntx-chan invocation-handle)
+ (cmd-nrx-chan invocation-handle)
+ (cmd-current-capacity-allocation invocation-handle)
+ )
+
+ (:incoming
+ (response-open invocation-handle status)
+ (response-close invocation-handle status)
+ (response-max-capacity invocation-handle capacity)
+ (response-ntx-chan invocation-handle ntx-chan)
+ (response-nrx-chan invocation-handle nrx-chan)
+ (response-current-capacity-allocation invocation-handle capacity)
+ )
+ )
diff --git a/usrp/host/lib/legacy/Makefile.am b/usrp/host/lib/legacy/Makefile.am
new file mode 100644
index 000000000..7303fb4c1
--- /dev/null
+++ b/usrp/host/lib/legacy/Makefile.am
@@ -0,0 +1,153 @@
+#
+# USRP - Universal Software Radio Peripheral
+#
+# Copyright (C) 2003,2004,2006,2007 Free Software Foundation, Inc.
+#
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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, Boston, MA 02110-1301 USA
+#
+
+include $(top_srcdir)/Makefile.common
+
+INCLUDES = $(USRP_INCLUDES)
+
+lib_LTLIBRARIES = libusrp.la
+
+libusrp_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0
+
+libusrp_la_LIBADD = \
+ $(USB_LIBS) \
+ ../../misc/libmisc.la
+
+EXTRA_DIST = \
+ std_paths.h.in \
+ usrp_dbid.dat
+
+
+BUILT_SOURCES = \
+ usrp_dbid.h \
+ usrp_dbid.cc \
+ usrp_dbid.py
+
+
+# ----------------------------------------------------------------
+# FUSB_TECH is set at configure time by way of
+# usrp/config/usrp_fusb_tech.m4.
+# It indicates which fast usb strategy we should be building.
+# We currently implement "generic", "darwin", "win32" and "linux"
+
+
+generic_CODE = \
+ fusb_generic.cc \
+ fusb_sysconfig_generic.cc
+
+darwin_CODE = \
+ fusb_darwin.cc \
+ fusb_sysconfig_darwin.cc \
+ README_OSX \
+ circular_buffer.h \
+ circular_linked_list.h \
+ darwin_libusb.h \
+ mld_threads.h
+
+win32_CODE = \
+ fusb_win32.cc \
+ fusb_sysconfig_win32.cc
+
+linux_CODE = \
+ fusb_linux.cc \
+ fusb_sysconfig_linux.cc
+
+ra_wb_CODE = \
+ fusb_ra_wb.cc \
+ fusb_sysconfig_ra_wb.cc
+
+
+#
+# include each <foo>_CODE entry here...
+#
+EXTRA_libusrp_la_SOURCES = \
+ $(generic_CODE) \
+ $(darwin_CODE) \
+ $(win32_CODE) \
+ $(linux_CODE) \
+ $(ra_wb_CODE)
+
+
+# work around automake deficiency
+libusrp_la_common_SOURCES = \
+ fusb.cc \
+ md5.c \
+ usrp_basic.cc \
+ usrp_config.cc \
+ usrp_dbid.cc \
+ usrp_local_sighandler.cc \
+ usrp_prims.cc \
+ usrp_standard.cc
+
+
+if FUSB_TECH_generic
+libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(generic_CODE)
+endif
+
+if FUSB_TECH_darwin
+libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(darwin_CODE)
+endif
+
+if FUSB_TECH_win32
+libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(win32_CODE)
+endif
+
+if FUSB_TECH_linux
+libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(linux_CODE)
+endif
+
+if FUSB_TECH_ra_wb
+libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(ra_wb_CODE)
+endif
+
+include_HEADERS = \
+ usrp_basic.h \
+ usrp_bytesex.h \
+ usrp_config.h \
+ usrp_dbid.h \
+ usrp_prims.h \
+ usrp_slots.h \
+ usrp_standard.h
+
+noinst_HEADERS = \
+ ad9862.h \
+ fusb.h \
+ fusb_darwin.h \
+ fusb_win32.h \
+ fusb_generic.h \
+ fusb_linux.h \
+ fusb_ra_wb.h \
+ md5.h \
+ rate_to_regval.h \
+ usrp_local_sighandler.h
+
+usrppython_PYTHON = \
+ usrp_dbid.py
+
+noinst_PYTHON = \
+ gen_usrp_dbid.py \
+ check_data.py \
+ dump_data.py
+
+usrp_dbid.py usrp_dbid.h usrp_dbid.cc: gen_usrp_dbid.py usrp_dbid.dat
+ PYTHONPATH=$(top_srcdir)/usrp/src srcdir=$(srcdir) $(PYTHON) $(srcdir)/gen_usrp_dbid.py $(srcdir)/usrp_dbid.dat
+
+MOSTLYCLEANFILES = \
+ $(BUILT_SOURCES) *~ *.pyc
diff --git a/usrp/host/lib/README_OSX b/usrp/host/lib/legacy/README_OSX
index 20230f121..20230f121 100644
--- a/usrp/host/lib/README_OSX
+++ b/usrp/host/lib/legacy/README_OSX
diff --git a/usrp/host/lib/ad9862.h b/usrp/host/lib/legacy/ad9862.h
index d1895bbe5..d1895bbe5 100644
--- a/usrp/host/lib/ad9862.h
+++ b/usrp/host/lib/legacy/ad9862.h
diff --git a/usrp/host/lib/check_data.py b/usrp/host/lib/legacy/check_data.py
index 655ca1503..655ca1503 100755
--- a/usrp/host/lib/check_data.py
+++ b/usrp/host/lib/legacy/check_data.py
diff --git a/usrp/host/lib/circular_buffer.h b/usrp/host/lib/legacy/circular_buffer.h
index 913360dfb..913360dfb 100644
--- a/usrp/host/lib/circular_buffer.h
+++ b/usrp/host/lib/legacy/circular_buffer.h
diff --git a/usrp/host/lib/circular_linked_list.h b/usrp/host/lib/legacy/circular_linked_list.h
index 0e460a26b..0e460a26b 100644
--- a/usrp/host/lib/circular_linked_list.h
+++ b/usrp/host/lib/legacy/circular_linked_list.h
diff --git a/usrp/host/lib/darwin_libusb.h b/usrp/host/lib/legacy/darwin_libusb.h
index bdbdd3446..bdbdd3446 100644
--- a/usrp/host/lib/darwin_libusb.h
+++ b/usrp/host/lib/legacy/darwin_libusb.h
diff --git a/usrp/host/lib/dump_data.py b/usrp/host/lib/legacy/dump_data.py
index 34dde3dcc..34dde3dcc 100755
--- a/usrp/host/lib/dump_data.py
+++ b/usrp/host/lib/legacy/dump_data.py
diff --git a/usrp/host/lib/fusb.cc b/usrp/host/lib/legacy/fusb.cc
index 01ced9e2a..01ced9e2a 100644
--- a/usrp/host/lib/fusb.cc
+++ b/usrp/host/lib/legacy/fusb.cc
diff --git a/usrp/host/lib/fusb.h b/usrp/host/lib/legacy/fusb.h
index da1b7c0ad..da1b7c0ad 100644
--- a/usrp/host/lib/fusb.h
+++ b/usrp/host/lib/legacy/fusb.h
diff --git a/usrp/host/lib/fusb_darwin.cc b/usrp/host/lib/legacy/fusb_darwin.cc
index 8be545372..8be545372 100644
--- a/usrp/host/lib/fusb_darwin.cc
+++ b/usrp/host/lib/legacy/fusb_darwin.cc
diff --git a/usrp/host/lib/fusb_darwin.h b/usrp/host/lib/legacy/fusb_darwin.h
index 9254c7f77..9254c7f77 100644
--- a/usrp/host/lib/fusb_darwin.h
+++ b/usrp/host/lib/legacy/fusb_darwin.h
diff --git a/usrp/host/lib/fusb_generic.cc b/usrp/host/lib/legacy/fusb_generic.cc
index f9f3c29d7..f9f3c29d7 100644
--- a/usrp/host/lib/fusb_generic.cc
+++ b/usrp/host/lib/legacy/fusb_generic.cc
diff --git a/usrp/host/lib/fusb_generic.h b/usrp/host/lib/legacy/fusb_generic.h
index 8c3a45647..8c3a45647 100644
--- a/usrp/host/lib/fusb_generic.h
+++ b/usrp/host/lib/legacy/fusb_generic.h
diff --git a/usrp/host/lib/fusb_linux.cc b/usrp/host/lib/legacy/fusb_linux.cc
index 1eaba4e50..1eaba4e50 100644
--- a/usrp/host/lib/fusb_linux.cc
+++ b/usrp/host/lib/legacy/fusb_linux.cc
diff --git a/usrp/host/lib/fusb_linux.h b/usrp/host/lib/legacy/fusb_linux.h
index b2d46a514..b2d46a514 100644
--- a/usrp/host/lib/fusb_linux.h
+++ b/usrp/host/lib/legacy/fusb_linux.h
diff --git a/usrp/host/lib/fusb_ra_wb.cc b/usrp/host/lib/legacy/fusb_ra_wb.cc
index c95f4afbe..c95f4afbe 100644
--- a/usrp/host/lib/fusb_ra_wb.cc
+++ b/usrp/host/lib/legacy/fusb_ra_wb.cc
diff --git a/usrp/host/lib/fusb_ra_wb.h b/usrp/host/lib/legacy/fusb_ra_wb.h
index 09bf8ee65..09bf8ee65 100644
--- a/usrp/host/lib/fusb_ra_wb.h
+++ b/usrp/host/lib/legacy/fusb_ra_wb.h
diff --git a/usrp/host/lib/fusb_sysconfig_darwin.cc b/usrp/host/lib/legacy/fusb_sysconfig_darwin.cc
index f66c298db..f66c298db 100644
--- a/usrp/host/lib/fusb_sysconfig_darwin.cc
+++ b/usrp/host/lib/legacy/fusb_sysconfig_darwin.cc
diff --git a/usrp/host/lib/fusb_sysconfig_generic.cc b/usrp/host/lib/legacy/fusb_sysconfig_generic.cc
index d336cb946..d336cb946 100644
--- a/usrp/host/lib/fusb_sysconfig_generic.cc
+++ b/usrp/host/lib/legacy/fusb_sysconfig_generic.cc
diff --git a/usrp/host/lib/fusb_sysconfig_linux.cc b/usrp/host/lib/legacy/fusb_sysconfig_linux.cc
index 468fa9f82..468fa9f82 100644
--- a/usrp/host/lib/fusb_sysconfig_linux.cc
+++ b/usrp/host/lib/legacy/fusb_sysconfig_linux.cc
diff --git a/usrp/host/lib/fusb_sysconfig_ra_wb.cc b/usrp/host/lib/legacy/fusb_sysconfig_ra_wb.cc
index 68eecedc5..68eecedc5 100644
--- a/usrp/host/lib/fusb_sysconfig_ra_wb.cc
+++ b/usrp/host/lib/legacy/fusb_sysconfig_ra_wb.cc
diff --git a/usrp/host/lib/fusb_sysconfig_win32.cc b/usrp/host/lib/legacy/fusb_sysconfig_win32.cc
index 282e77ac4..282e77ac4 100644
--- a/usrp/host/lib/fusb_sysconfig_win32.cc
+++ b/usrp/host/lib/legacy/fusb_sysconfig_win32.cc
diff --git a/usrp/host/lib/fusb_win32.cc b/usrp/host/lib/legacy/fusb_win32.cc
index c6e3c972e..c6e3c972e 100644
--- a/usrp/host/lib/fusb_win32.cc
+++ b/usrp/host/lib/legacy/fusb_win32.cc
diff --git a/usrp/host/lib/fusb_win32.h b/usrp/host/lib/legacy/fusb_win32.h
index c796af49f..c796af49f 100644
--- a/usrp/host/lib/fusb_win32.h
+++ b/usrp/host/lib/legacy/fusb_win32.h
diff --git a/usrp/host/lib/gen_usrp_dbid.py b/usrp/host/lib/legacy/gen_usrp_dbid.py
index 14d3ee550..14d3ee550 100755
--- a/usrp/host/lib/gen_usrp_dbid.py
+++ b/usrp/host/lib/legacy/gen_usrp_dbid.py
diff --git a/usrp/host/lib/md5.c b/usrp/host/lib/legacy/md5.c
index abee067f3..abee067f3 100644
--- a/usrp/host/lib/md5.c
+++ b/usrp/host/lib/legacy/md5.c
diff --git a/usrp/host/lib/md5.h b/usrp/host/lib/legacy/md5.h
index 709cefb9b..709cefb9b 100644
--- a/usrp/host/lib/md5.h
+++ b/usrp/host/lib/legacy/md5.h
diff --git a/usrp/host/lib/mld_threads.h b/usrp/host/lib/legacy/mld_threads.h
index 08b3555ae..08b3555ae 100644
--- a/usrp/host/lib/mld_threads.h
+++ b/usrp/host/lib/legacy/mld_threads.h
diff --git a/usrp/host/lib/rate_to_regval.h b/usrp/host/lib/legacy/rate_to_regval.h
index 1ffdc0f69..1ffdc0f69 100644
--- a/usrp/host/lib/rate_to_regval.h
+++ b/usrp/host/lib/legacy/rate_to_regval.h
diff --git a/usrp/host/lib/std_paths.h.in b/usrp/host/lib/legacy/std_paths.h.in
index 22a8ecbd5..22a8ecbd5 100644
--- a/usrp/host/lib/std_paths.h.in
+++ b/usrp/host/lib/legacy/std_paths.h.in
diff --git a/usrp/host/lib/usrp_basic.cc b/usrp/host/lib/legacy/usrp_basic.cc
index cc9df04e7..2eef14727 100644
--- a/usrp/host/lib/usrp_basic.cc
+++ b/usrp/host/lib/legacy/usrp_basic.cc
@@ -923,8 +923,6 @@ usrp_basic_tx::usrp_basic_tx (int which_board, int fusb_block_size, int fusb_nbl
_write_fpga_reg(FR_ATR_MASK_2, 0);
_write_fpga_reg(FR_ATR_TXVAL_2, 0);
_write_fpga_reg(FR_ATR_RXVAL_2, 0);
- _write_fpga_reg(FR_ATR_TX_DELAY, 0);
- _write_fpga_reg(FR_ATR_RX_DELAY, 0);
}
diff --git a/usrp/host/lib/usrp_basic.h b/usrp/host/lib/legacy/usrp_basic.h
index 796a0f494..796a0f494 100644
--- a/usrp/host/lib/usrp_basic.h
+++ b/usrp/host/lib/legacy/usrp_basic.h
diff --git a/usrp/host/lib/usrp_bytesex.h b/usrp/host/lib/legacy/usrp_bytesex.h
index 391d29ccf..6c4e129c9 100644
--- a/usrp/host/lib/usrp_bytesex.h
+++ b/usrp/host/lib/legacy/usrp_bytesex.h
@@ -38,11 +38,30 @@ bswap_16 (unsigned short int x)
{
return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8));
}
+
+static inline unsigned int
+bswap32 (unsigned int x)
+{
+ return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) \
+ | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24));
+}
#endif
#ifdef WORDS_BIGENDIAN
+static inline unsigned int
+host_to_usrp_u32 (unsigned int x)
+{
+ return bswap_32(x);
+}
+
+static inline unsigned int
+usrp_to_host_u32 (unsigned int x)
+{
+ return bswap_32(x);
+}
+
static inline short int
host_to_usrp_short (short int x)
{
@@ -57,6 +76,18 @@ usrp_to_host_short (short int x)
#else
+static inline unsigned int
+host_to_usrp_u32 (unsigned int x)
+{
+ return x;
+}
+
+static inline unsigned int
+usrp_to_host_u32 (unsigned int x)
+{
+ return x;
+}
+
static inline short int
host_to_usrp_short (short int x)
{
diff --git a/usrp/host/lib/usrp_config.cc b/usrp/host/lib/legacy/usrp_config.cc
index 17bfd48d4..17bfd48d4 100644
--- a/usrp/host/lib/usrp_config.cc
+++ b/usrp/host/lib/legacy/usrp_config.cc
diff --git a/usrp/host/lib/usrp_config.h b/usrp/host/lib/legacy/usrp_config.h
index 91b398b9b..91b398b9b 100644
--- a/usrp/host/lib/usrp_config.h
+++ b/usrp/host/lib/legacy/usrp_config.h
diff --git a/usrp/host/lib/usrp_dbid.dat b/usrp/host/lib/legacy/usrp_dbid.dat
index a85d0532c..a85d0532c 100644
--- a/usrp/host/lib/usrp_dbid.dat
+++ b/usrp/host/lib/legacy/usrp_dbid.dat
diff --git a/usrp/host/lib/usrp_local_sighandler.cc b/usrp/host/lib/legacy/usrp_local_sighandler.cc
index ab6c485fd..ab6c485fd 100644
--- a/usrp/host/lib/usrp_local_sighandler.cc
+++ b/usrp/host/lib/legacy/usrp_local_sighandler.cc
diff --git a/usrp/host/lib/usrp_local_sighandler.h b/usrp/host/lib/legacy/usrp_local_sighandler.h
index f1c00cd51..f1c00cd51 100644
--- a/usrp/host/lib/usrp_local_sighandler.h
+++ b/usrp/host/lib/legacy/usrp_local_sighandler.h
diff --git a/usrp/host/lib/usrp_prims.cc b/usrp/host/lib/legacy/usrp_prims.cc
index f666a29fc..f666a29fc 100644
--- a/usrp/host/lib/usrp_prims.cc
+++ b/usrp/host/lib/legacy/usrp_prims.cc
diff --git a/usrp/host/lib/usrp_prims.h b/usrp/host/lib/legacy/usrp_prims.h
index 97cfb4a47..97cfb4a47 100644
--- a/usrp/host/lib/usrp_prims.h
+++ b/usrp/host/lib/legacy/usrp_prims.h
diff --git a/usrp/host/lib/usrp_slots.h b/usrp/host/lib/legacy/usrp_slots.h
index c4971d167..c4971d167 100644
--- a/usrp/host/lib/usrp_slots.h
+++ b/usrp/host/lib/legacy/usrp_slots.h
diff --git a/usrp/host/lib/usrp_standard.cc b/usrp/host/lib/legacy/usrp_standard.cc
index 6b4ec9393..6b4ec9393 100644
--- a/usrp/host/lib/usrp_standard.cc
+++ b/usrp/host/lib/legacy/usrp_standard.cc
diff --git a/usrp/host/lib/usrp_standard.h b/usrp/host/lib/legacy/usrp_standard.h
index 6fee4b9c1..6fee4b9c1 100644
--- a/usrp/host/lib/usrp_standard.h
+++ b/usrp/host/lib/legacy/usrp_standard.h
diff --git a/usrp/host/swig/Makefile.am b/usrp/host/swig/Makefile.am
index 8868d1ecb..35a81ea29 100644
--- a/usrp/host/swig/Makefile.am
+++ b/usrp/host/swig/Makefile.am
@@ -64,7 +64,7 @@ _usrp_prims_la_SOURCES = \
noinst_HEADERS =
-_usrp_prims_la_LIBADD = $(top_builddir)/usrp/host/lib/libusrp.la -lstdc++ $(PYTHON_LDFLAGS)
+_usrp_prims_la_LIBADD = $(USRP_LA) -lstdc++ $(PYTHON_LDFLAGS)
_usrp_prims_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version