From b629a998bdf0ff88af6f113bd605059ebd61efc8 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Mon, 4 Jun 2012 18:24:52 -0400
Subject: docs: added a description of a basic flowgraph to the manual's main
 page.

Also a brief discussion of throughput/latency and how to use the max_noutput_items methods to control them.
---
 docs/doxygen/other/main_page.dox | 101 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 101 insertions(+)

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox
index 68b0989436..4912a5411e 100644
--- a/docs/doxygen/other/main_page.dox
+++ b/docs/doxygen/other/main_page.dox
@@ -39,6 +39,106 @@ More details on packages in GNU Radio:
 \li \ref page_vocoder
 \li \ref page_pfb
 
+
+\section flowgraph Operating a Flowgraph
+
+The basic data structure in GNU Radio is the flowgraph, which
+represents the connections of the blocks through which a continuous
+stream of samples flows. The concept of a flowgraph is an acyclic
+directional graph with one or more source blocks (to insert samples
+into the flowgraph), one or more sink blocks (to terminate or export
+samples from the flowgraph), and any signal processing blocks in
+between.
+
+A program must at least create a GNU Radio 'top_block', which
+represents the top-most structure of the flowgraph. The top blocks
+provide the overall control and hold methods such as 'start,' 'stop,'
+and 'wait.'
+
+The general construction of a GNU Radio application is to create a top
+block, instantiate the blocks, connect the blocks together, and then
+start the top block. The following program shows how this is done. A
+single source and sink are used with a FIR filter between them.
+
+\code
+    from gnuradio import gr, filter
+    
+    class my_topblock(gr.top_block):
+        def __init__(self):
+            gr.top_block.__init__(self)
+    
+            amp = 1
+            taps = filter.firdes.low_pass(1, 1, 0.1, 0.01)
+            
+            self.src = gr.noise_source_c(gr.GR_GAUSSIAN, amp)
+            self.flt = filter.fir_filter_ccf(1, taps)
+            self.snk = gr.null_sink(gr.sizeof_gr_complex)
+    
+            self.connect(self.src, self.flt, self.snk)
+    
+    if __name__ == "__main__":
+        tb = my_topblock()
+        tb.start()
+        tb.wait()
+\endcode
+
+The 'tb.start()' starts the data flowing through the flowgraph while
+the 'tb.wait()' is the equivalent of a thread's 'join' operation and
+blocks until the top block is done.
+
+An alternative to using the 'start' and 'wait' methods, a 'run' method is
+also provided for convenience that is a blocking start call;
+equivalent to the above 'start' followed by a 'wait.'
+
+
+\subsection latency Latency and Throughput
+
+By default, GNU Radio runs a scheduler that attempts to optimize
+throughput. Using a dynamic scheduler, blocks in a flowgraph pass
+chunks of items from sources to sinks. The sizes of these chunks will
+vary depending on the speed of processing. For each block, the number
+of items is can process is dependent on how much space it has in its
+output buffer(s) and how many items are available on the input
+buffer(s).
+
+The consequence of this is that often a block may be called with a very
+large number of items to process (several thousand). In terms of
+speed, this is efficient since now the majority of the processing time
+is taken up with processing samples. Smaller chunks mean more calls
+into the scheduler to retrieve more data. The downside to this is that
+it can lead to large latency while a block is processing a large chunk
+of data.
+
+To combat this problem, the top block can be passed a limit on the
+number of output items a block will ever receive. A block may get less
+than this number, but never more, and so it serves as an upper limit
+to the latency any block will exhibit. By limiting the number of items
+per call to a block, though, we increase the overhead of the
+scheduler, and so reduce the overall efficiency of the application.
+
+To set the maximum number of output items, we pass a value into the
+'start' or 'run' method of the top block:
+
+\code
+     tb.start(1000)
+     tb.wait()
+or
+     tb.run(1000)
+\endcode
+
+Using this method, we place a global restriction on the size of items
+to all blocks. Each block, though, has the ability to overwrite this
+with its own limit. Using the 'set_max_noutput_items(m)' method for an
+individual block will overwrite the global setting. For example, in
+the following code, the global setting is 1000 items max, except for
+the FIR filter, which can receive up to 2000 items.
+
+\code
+     tb.flt.set_max_noutput_items(2000)
+     tb.run(1000)
+\endcode
+
+
 \section volk_main Using Volk in GNU Radio
 
 The \ref volk_guide page provides an overview of how to incorporate
@@ -48,4 +148,5 @@ Many blocks have already been converted to use Volk in their calls, so
 they can also serve as examples. See the gr_complex_to_xxx.h file for
 examples of various blocks that make use of Volk.
 
+
 */
-- 
cgit v1.2.3


From 9c5cd068c1414f1112ab41708833c0fbc267c4d0 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Mon, 4 Jun 2012 20:23:01 -0400
Subject: docs: added section explaining the basics of reconfiguring a
 flowgraph.

---
 docs/doxygen/other/main_page.dox | 138 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 131 insertions(+), 7 deletions(-)

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox
index 4912a5411e..1c4a60b3a8 100644
--- a/docs/doxygen/other/main_page.dox
+++ b/docs/doxygen/other/main_page.dox
@@ -55,10 +55,11 @@ represents the top-most structure of the flowgraph. The top blocks
 provide the overall control and hold methods such as 'start,' 'stop,'
 and 'wait.'
 
-The general construction of a GNU Radio application is to create a top
-block, instantiate the blocks, connect the blocks together, and then
-start the top block. The following program shows how this is done. A
-single source and sink are used with a FIR filter between them.
+The general construction of a GNU Radio application is to create a
+gr_top_block, instantiate the blocks, connect the blocks together, and
+then start the gr_top_block. The following program shows how this is
+done. A single source and sink are used with a FIR filter between
+them.
 
 \code
     from gnuradio import gr, filter
@@ -84,7 +85,7 @@ single source and sink are used with a FIR filter between them.
 
 The 'tb.start()' starts the data flowing through the flowgraph while
 the 'tb.wait()' is the equivalent of a thread's 'join' operation and
-blocks until the top block is done.
+blocks until the gr_top_block is done.
 
 An alternative to using the 'start' and 'wait' methods, a 'run' method is
 also provided for convenience that is a blocking start call;
@@ -109,7 +110,7 @@ into the scheduler to retrieve more data. The downside to this is that
 it can lead to large latency while a block is processing a large chunk
 of data.
 
-To combat this problem, the top block can be passed a limit on the
+To combat this problem, the gr_top_block can be passed a limit on the
 number of output items a block will ever receive. A block may get less
 than this number, but never more, and so it serves as an upper limit
 to the latency any block will exhibit. By limiting the number of items
@@ -117,7 +118,7 @@ per call to a block, though, we increase the overhead of the
 scheduler, and so reduce the overall efficiency of the application.
 
 To set the maximum number of output items, we pass a value into the
-'start' or 'run' method of the top block:
+'start' or 'run' method of the gr_top_block:
 
 \code
      tb.start(1000)
@@ -139,6 +140,129 @@ the FIR filter, which can receive up to 2000 items.
 \endcode
 
 
+\section reconfigure Reconfiguring Flowgraphs
+
+It is possible to reconfigure the flowgraph at runtime. The
+reconfiguration is meant for changes in the flowgraph structure, not
+individual parameter settings of the blocks. For example, changing the
+constant in a gr_add_const_cc block can be done while the flowgraph is
+running using the 'set_k(k)' method.
+
+Reconfiguration is done by locking the flowgraph, which stops it from
+running and processing data, performing the reconfiguration, and then
+restarting the graph by unlocking it.
+
+The following example code shows a graph that first adds two
+gr_noise_source_c blocks and then replaces the gr_add_cc block with a
+gr_sub_cc block to then subtract the sources.
+
+\code
+from gnuradio import gr
+import time
+
+class mytb(gr.top_block):
+    def __init__(self):
+        gr.top_block.__init__(self)
+
+        self.src0 = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
+        self.src1 = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
+        self.add  = gr.add_cc()
+        self.sub  = gr.sub_cc()
+        self.head = gr.head(gr.sizeof_gr_complex, 1000000)
+        self.snk  = gr.file_sink(gr.sizeof_gr_complex, "output.32fc")
+
+        self.connect(self.src0, (self.add,0))
+        self.connect(self.src1, (self.add,1))
+        self.connect(self.add, self.head)
+        self.connect(self.head, self.snk)
+
+def main():
+    tb = mytb()
+    tb.start()
+    time.sleep(0.01)
+
+    # Stop flowgraph and disconnect the add block
+    tb.lock()
+    tb.disconnect(tb.add, tb.head)
+    tb.disconnect(tb.src0, (tb.add,0))
+    tb.disconnect(tb.src1, (tb.add,1))
+
+    # Connect the sub block and restart
+    tb.connect(tb.sub, tb.head)
+    tb.connect(tb.src0, (tb.sub,0))
+    tb.connect(tb.src1, (tb.sub,1))
+    tb.unlock()
+
+    tb.wait()
+
+if __name__ == "__main__":
+    main()
+\endcode
+
+During reconfiguration, the maximum noutput_items value can be changed
+either globally using the 'set_max_noutput_items(m)' on the gr_top_block
+object or locally using the 'set_max_noutput_items(m)' on any given
+block object.
+
+A block also has a 'unset_max_noutput_items()' method that unsets the
+local max noutput_items value so that block reverts back to using the
+global value.
+
+The following example expands the previous example but sets and resets
+the max noutput_items both locally and globally.
+
+\code
+from gnuradio import gr
+import time
+
+class mytb(gr.top_block):
+    def __init__(self):
+        gr.top_block.__init__(self)
+
+        self.src0 = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
+        self.src1 = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
+        self.add  = gr.add_cc()
+        self.sub  = gr.sub_cc()
+        self.head = gr.head(gr.sizeof_gr_complex, 1000000)
+        self.snk  = gr.file_sink(gr.sizeof_gr_complex, "output.32fc")
+
+        self.connect(self.src0, (self.add,0))
+        self.connect(self.src1, (self.add,1))
+        self.connect(self.add, self.head)
+        self.connect(self.head, self.snk)
+
+def main():
+    # Start the gr_top_block after setting some max noutput_items.
+    tb = mytb()
+    tb.src1.set_max_noutput_items(2000)
+    tb.start(100)
+    time.sleep(0.01)
+    
+    # Stop flowgraph and disconnect the add block
+    tb.lock()
+
+    tb.disconnect(tb.add, tb.head)
+    tb.disconnect(tb.src0, (tb.add,0))
+    tb.disconnect(tb.src1, (tb.add,1))
+
+    # Connect the sub block
+    tb.connect(tb.sub, tb.head)
+    tb.connect(tb.src0, (tb.sub,0))
+    tb.connect(tb.src1, (tb.sub,1))
+
+    # Set new max_noutput_items for the gr_top_block
+    # and unset the local value for src1
+    tb.set_max_noutput_items(1000)
+    tb.src1.unset_max_noutput_items()
+    tb.unlock()
+
+    tb.wait()
+
+if __name__ == "__main__":
+    main()
+\endcode
+
+
 \section volk_main Using Volk in GNU Radio
 
 The \ref volk_guide page provides an overview of how to incorporate
-- 
cgit v1.2.3


From 5fcb7ebd473709fd9e4e99d542f21d3cee5aaf05 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Tue, 2 Oct 2012 13:08:11 -0400
Subject: docs: Adding notes discussing how to use new max_output_buffer
 feature.

Also sneaking in a new analog group for gr-analog.
---
 docs/doxygen/other/group_defs.dox |  1 +
 docs/doxygen/other/main_page.dox  | 50 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+)

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/group_defs.dox b/docs/doxygen/other/group_defs.dox
index 213486b7a1..4aee49ec85 100644
--- a/docs/doxygen/other/group_defs.dox
+++ b/docs/doxygen/other/group_defs.dox
@@ -28,6 +28,7 @@
 /*! \defgroup slicedice_blk Slicing and Dicing Streams  */
 /*! \defgroup vocoder_blk Voice Encoders and Decoders	*/
 /*! \defgroup digital Digital Modulation Blocks		*/
+/*! \defgroup analog Analog Communications Blocks	*/
 /*! \defgroup qtgui_blk QT Graphical Interfaces		*/
 /*! \defgroup uhd_blk UHD Interface  			*/
 /*! \defgroup audio_blk Audio Interface  		*/
diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox
index c90ad883f6..f2ab2a4367 100644
--- a/docs/doxygen/other/main_page.dox
+++ b/docs/doxygen/other/main_page.dox
@@ -139,6 +139,56 @@ the FIR filter, which can receive up to 2000 items.
      tb.run(1000)
 \endcode
 
+In some situations, you might actually want to restrict the size of
+the buffer itself. This can help to prevent a buffer who is blocked
+for data from just increasing the amount of items in its buffer, which
+will then cause an increased latency for new samples. You can set the
+size of an output buffer for each output port for every block. 
+
+WARNING: This is an advanced feature in GNU Radio and should not be
+used without a full understanding of this concept as explained below.
+
+To set the output buffer size of a block, you simply call:
+
+\code
+     tb.blk0.set_max_output_buffer(2000)
+     tb.blk1.set_max_output_buffer(2000,1)
+     tb.start()
+     print tb.blk1.max_output_buffer(0)
+     print tb.blk1.max_output_buffer(1)
+\endcode
+
+In the above example, all ports of blk0 are set to a buffer size of
+2000 in _items_ (not bytes), and blk1 only sets the size for output
+port 1, any and all other ports use the default. The third and fourth
+lines just print out the buffer sizes for ports 0 and 1 of blk1. This
+is done after start() is called because the values are updated based
+on what is actually allocated to the block's buffers.
+
+NOTES:
+
+1. Buffer length assignment is done once at runtime (i.e., when run()
+or start() is called). So to set the max buffer lengths, the
+set_max_output_buffer calls must be done before this.
+
+2. Once the flowgraph is started, the buffer lengths for a block are
+set and cannot be dynamically changed, even during a
+lock()/unlock(). If you need to change the buffer size, you will have
+to delete the block and rebuild it, and therefore must disconnect and
+reconnect the blocks.
+
+3. This can affect throughput. Large buffers are designed to improve
+the efficiency and speed of the program at the expense of
+latency. Limiting the size of the buffer may decrease performance.
+
+4. The real buffer size is actually based on a minimum granularity of
+the system. Typically, this is a page size, which is typically 4096
+bytes. This means that any buffer size that is specified with this
+command will get rounded up to the nearest granularity (e.g., page)
+size. When calling max_output_buffer(port) after the flowgraph is
+started, you will get how many items were actually allocated in the
+buffer, which may be different than what was initially specified.
+
 
 \section reconfigure Reconfiguring Flowgraphs
 
-- 
cgit v1.2.3


From 1e528816fd70f3a61d7f00a370cb056f03ceb6a7 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Tue, 2 Oct 2012 14:52:07 -0400
Subject: core: fixed swig file for exporting max/min buffer sizes with port
 first.

---
 docs/doxygen/other/main_page.dox               | 2 +-
 gnuradio-core/src/lib/runtime/gr_basic_block.i | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox
index f2ab2a4367..2826824647 100644
--- a/docs/doxygen/other/main_page.dox
+++ b/docs/doxygen/other/main_page.dox
@@ -152,7 +152,7 @@ To set the output buffer size of a block, you simply call:
 
 \code
      tb.blk0.set_max_output_buffer(2000)
-     tb.blk1.set_max_output_buffer(2000,1)
+     tb.blk1.set_max_output_buffer(1, 2000)
      tb.start()
      print tb.blk1.max_output_buffer(0)
      print tb.blk1.max_output_buffer(1)
diff --git a/gnuradio-core/src/lib/runtime/gr_basic_block.i b/gnuradio-core/src/lib/runtime/gr_basic_block.i
index 848017dd86..7713f2fe15 100644
--- a/gnuradio-core/src/lib/runtime/gr_basic_block.i
+++ b/gnuradio-core/src/lib/runtime/gr_basic_block.i
@@ -44,10 +44,10 @@ public:
     bool check_topology (int ninputs, int noutputs);
     long max_output_buffer(int i);
     void set_max_output_buffer(long max_output_buffer);
-    void set_max_output_buffer(long max_output_buffer, int port);
+    void set_max_output_buffer(int port, long max_output_buffer);
     long min_output_buffer(int i);
     void set_min_output_buffer(long min_output_buffer);
-    void set_min_output_buffer(long min_output_buffer, int port);
+    void set_min_output_buffer(int port, long min_output_buffer);
 };
 
 %rename(block_ncurrently_allocated) gr_basic_block_ncurrently_allocated;
-- 
cgit v1.2.3


From a47c5485e477a2b29a839c785fea45f29da07919 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Tue, 4 Dec 2012 15:49:19 -0500
Subject: docs: Removing some obsoleted Doxygen commands per issue #498.

These were set to the defaults and so should not affect previous versions of Doxygen.
---
 docs/doxygen/Doxyfile.in                                | 12 ------------
 docs/doxygen/Doxyfile.swig_doc.in                       | 17 -----------------
 docs/doxygen/doxyxml/example/Doxyfile                   | 17 -----------------
 gr-howto-write-a-block/docs/doxygen/Doxyfile.in         | 12 ------------
 .../docs/doxygen/Doxyfile.swig_doc.in                   | 17 -----------------
 .../docs/doxygen/doxyxml/example/Doxyfile               | 17 -----------------
 6 files changed, 92 deletions(-)

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/Doxyfile.in b/docs/doxygen/Doxyfile.in
index ad3c2d01f4..78a7a5d166 100644
--- a/docs/doxygen/Doxyfile.in
+++ b/docs/doxygen/Doxyfile.in
@@ -455,12 +455,6 @@ MAX_INITIALIZER_LINES  = 30
 
 SHOW_USED_FILES        = YES
 
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
 # Set the SHOW_FILES tag to NO to disable the generation of the Files page.
 # This will remove the Files entry from the Quick Index and from the
 # Folder Tree View (if specified). The default is YES.
@@ -862,12 +856,6 @@ HTML_FOOTER            =
 
 HTML_STYLESHEET        =
 
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
 # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
 # documentation will contain sections that can be hidden and shown after the
 # page has loaded. For this to work a browser that supports
diff --git a/docs/doxygen/Doxyfile.swig_doc.in b/docs/doxygen/Doxyfile.swig_doc.in
index 94e14bda1b..8f6182ca83 100644
--- a/docs/doxygen/Doxyfile.swig_doc.in
+++ b/docs/doxygen/Doxyfile.swig_doc.in
@@ -470,12 +470,6 @@ MAX_INITIALIZER_LINES  = 30
 
 SHOW_USED_FILES        = YES
 
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
 # Set the SHOW_FILES tag to NO to disable the generation of the Files page.
 # This will remove the Files entry from the Quick Index and from the
 # Folder Tree View (if specified). The default is YES.
@@ -796,12 +790,6 @@ HTML_FOOTER            =
 
 HTML_STYLESHEET        =
 
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
 # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
 # documentation will contain sections that can be hidden and shown after the
 # page has loaded. For this to work a browser that supports
@@ -950,11 +938,6 @@ ENUM_VALUES_PER_LINE   = 4
 
 GENERATE_TREEVIEW      = NO
 
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
-
-USE_INLINE_TREES       = NO
-
 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
 # used to set the initial width (in pixels) of the frame in which the tree
 # is shown.
diff --git a/docs/doxygen/doxyxml/example/Doxyfile b/docs/doxygen/doxyxml/example/Doxyfile
index 9780043be0..dd2e5c77eb 100644
--- a/docs/doxygen/doxyxml/example/Doxyfile
+++ b/docs/doxygen/doxyxml/example/Doxyfile
@@ -476,12 +476,6 @@ MAX_INITIALIZER_LINES  = 30
 
 SHOW_USED_FILES        = YES
 
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
 # Set the SHOW_FILES tag to NO to disable the generation of the Files page.
 # This will remove the Files entry from the Quick Index and from the
 # Folder Tree View (if specified). The default is YES.
@@ -808,12 +802,6 @@ HTML_STYLESHEET        =
 
 HTML_TIMESTAMP         = YES
 
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
 # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
 # documentation will contain sections that can be hidden and shown after the
 # page has loaded. For this to work a browser that supports
@@ -978,11 +966,6 @@ ENUM_VALUES_PER_LINE   = 4
 
 GENERATE_TREEVIEW      = NO
 
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
-
-USE_INLINE_TREES       = NO
-
 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
 # used to set the initial width (in pixels) of the frame in which the tree
 # is shown.
diff --git a/gr-howto-write-a-block/docs/doxygen/Doxyfile.in b/gr-howto-write-a-block/docs/doxygen/Doxyfile.in
index cb6a913bbe..6ee69ee35b 100644
--- a/gr-howto-write-a-block/docs/doxygen/Doxyfile.in
+++ b/gr-howto-write-a-block/docs/doxygen/Doxyfile.in
@@ -455,12 +455,6 @@ MAX_INITIALIZER_LINES  = 30
 
 SHOW_USED_FILES        = YES
 
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
 # Set the SHOW_FILES tag to NO to disable the generation of the Files page.
 # This will remove the Files entry from the Quick Index and from the
 # Folder Tree View (if specified). The default is YES.
@@ -807,12 +801,6 @@ HTML_FOOTER            =
 
 HTML_STYLESHEET        =
 
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
 # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
 # documentation will contain sections that can be hidden and shown after the
 # page has loaded. For this to work a browser that supports
diff --git a/gr-howto-write-a-block/docs/doxygen/Doxyfile.swig_doc.in b/gr-howto-write-a-block/docs/doxygen/Doxyfile.swig_doc.in
index 50b8aa81d6..121c3e8585 100644
--- a/gr-howto-write-a-block/docs/doxygen/Doxyfile.swig_doc.in
+++ b/gr-howto-write-a-block/docs/doxygen/Doxyfile.swig_doc.in
@@ -470,12 +470,6 @@ MAX_INITIALIZER_LINES  = 30
 
 SHOW_USED_FILES        = YES
 
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
 # Set the SHOW_FILES tag to NO to disable the generation of the Files page.
 # This will remove the Files entry from the Quick Index and from the
 # Folder Tree View (if specified). The default is YES.
@@ -796,12 +790,6 @@ HTML_FOOTER            =
 
 HTML_STYLESHEET        =
 
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
 # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
 # documentation will contain sections that can be hidden and shown after the
 # page has loaded. For this to work a browser that supports
@@ -950,11 +938,6 @@ ENUM_VALUES_PER_LINE   = 4
 
 GENERATE_TREEVIEW      = NO
 
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
-
-USE_INLINE_TREES       = NO
-
 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
 # used to set the initial width (in pixels) of the frame in which the tree
 # is shown.
diff --git a/gr-howto-write-a-block/docs/doxygen/doxyxml/example/Doxyfile b/gr-howto-write-a-block/docs/doxygen/doxyxml/example/Doxyfile
index 9780043be0..dd2e5c77eb 100644
--- a/gr-howto-write-a-block/docs/doxygen/doxyxml/example/Doxyfile
+++ b/gr-howto-write-a-block/docs/doxygen/doxyxml/example/Doxyfile
@@ -476,12 +476,6 @@ MAX_INITIALIZER_LINES  = 30
 
 SHOW_USED_FILES        = YES
 
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
 # Set the SHOW_FILES tag to NO to disable the generation of the Files page.
 # This will remove the Files entry from the Quick Index and from the
 # Folder Tree View (if specified). The default is YES.
@@ -808,12 +802,6 @@ HTML_STYLESHEET        =
 
 HTML_TIMESTAMP         = YES
 
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
 # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
 # documentation will contain sections that can be hidden and shown after the
 # page has loaded. For this to work a browser that supports
@@ -978,11 +966,6 @@ ENUM_VALUES_PER_LINE   = 4
 
 GENERATE_TREEVIEW      = NO
 
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
-
-USE_INLINE_TREES       = NO
-
 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
 # used to set the initial width (in pixels) of the frame in which the tree
 # is shown.
-- 
cgit v1.2.3


From 996e5996d64f90c85da8681e7df3086e20bcb530 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Thu, 13 Dec 2012 18:09:49 -0500
Subject: docs: added a page detailing metadata format.

---
 docs/doxygen/other/metadata.dox | 322 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 322 insertions(+)
 create mode 100644 docs/doxygen/other/metadata.dox

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/metadata.dox b/docs/doxygen/other/metadata.dox
new file mode 100644
index 0000000000..5b20b9e730
--- /dev/null
+++ b/docs/doxygen/other/metadata.dox
@@ -0,0 +1,322 @@
+/*! \page page_metadata Metadata Information
+
+\section Introduction
+
+Metadata files have extra information in the form of headers that
+carry metadata about the samples in the file. Raw, binary files carry
+no extra information and must be handled delicately. Any changes in
+the system state such as sample rate or if a receiver's frequency are
+not conveyed with the data in the file itself. Header of metadata
+solve this problem.
+
+We write metadata files using gr_file_meta_sink and read metadata
+files using gr_file_meta_source.
+
+Metadata files have headers that carry information about a segment of
+data within the file. The header structure is described in detail in
+the next section. A metadata file always starts with a header that
+describes the basic structure of the data. It contains information
+about the data type, if it's complex, the sample rate of the segment,
+the time stamp of the first sample of the segment, and information
+regarding the header size and segment size.
+
+Headers have two main tags associated with them:
+
+- rx_rate: the sample rate of the stream.
+- rx_time: the time stamp of the first item in the segment.
+
+These tags were inspired by the UHD tag format.
+
+The header gives enough information to process and handle the
+data. One cautionary note, though, is that the data type should never
+change within a file. There should be very little need for this, but
+more importantly. GNU Radio blocks can only set the data type of their
+IO signatures in the constructor, so changes in the data type
+afterward will not be recognized.
+
+We also have an extra header segment that is option. This can be
+loaded up at the beginning by the user specifying some extra metadata
+that should be transmitted along with the data. It also grows whenever
+it sees a stream tag, so the dictionary will contain and key:value
+pairs out of tags from the flowgraph.
+
+
+\subsection types Types of Metadata Files
+
+GNU Radio currently supports two types of metadata files:
+
+- inline: headers are inline with the data in the same file.
+- detached: headers are in a separate header file from the data.
+
+The inline method is the standard version. When a detached header is
+used, the headers are simply inserted back-to-back in the detached
+header file. The dat file, then, is the standard raw binary format
+with no interruptions in the data.
+
+
+\subsection updating Updating Headers
+
+While there is always a header that starts a metadata file, they are
+updated throughout as well. There are two events that trigger a new
+header. We define a segment as the unit of data associated with the
+last header.
+
+The first event that will trigger a new header is when enough samples
+have been written for the given segment. This number is defined as the
+maximum segment size and is a parameter we pass to the
+file_meta_sink. It defaults to 1 million items (items, not
+bytes). When that number of items is reached, a new header is
+generated and a new segment is started. This makes it easier for us to
+manipulate the data later and helps protect against catastrophic data
+loss.
+
+The second event to trigger a new segment is if a new tag is
+observed. If the tag is a standard tag in the header, the header value
+is updated, the header and current extras are written to file, and the
+segment begins again. If a tag from the extras is seen, the value
+associated with that tag is updated; and if a new tag is seen, a new
+key:value pair are added to the extras dictionary.
+
+When new tags are seen, we generate a new segment so that we make sure
+that all samples in that segment are defined by the header. If the
+sample rate changes, we create a new segment where all of the new
+samples are at that new rate. Also, in the case of UHD devices, if a
+segment loss is observed, it will generate a new timestamp as a tag of
+'rx_time'. We create a new file segment that reflects this change to
+keep the sample times exact.
+
+
+\subsection implementation Implementation
+
+Metadata files are created using gr_file_meta_sink. The default
+behavior is to create a single file with inline headers as
+metadata. An option can be set to switch to detached header mode.
+
+Metadata file are read into a flowgraph using
+gr_file_meta_source. This source reads a metadata file, inline by
+default with a settable option to use detached headers. The data from
+the segments is converted into a standard streaming output. The
+'rx_rate' and 'rx_time' and all key:value pairs in the extra header
+are converted into tags and added to the stream tags interface.
+
+
+\section structure Structure
+
+The file metadata consists of a static mandatory header and a dynamic
+optional extras header. Each header is a separate PMT
+dictionary. Headers are created by building a PMT dictionary of
+key:value pairs, then the dictionary is serialized into a string to be
+written to file. The header is always the same length that is
+predetermined by the version of the header (this must be known
+already). The header will then indicate if there is an extra data to
+be extracted as a separate serialized dictionary.
+
+To work with the PMTs for creating and extracting header information,
+we use PMT operators. For example, we create a simplified version of
+the header in C++ like this:
+
+\code
+  using namespace pmt;
+  const char METADATA_VERSION = 0x0;
+  pmt_t header;
+  header = pmt_make_dict();
+  header = pmt_dict_add(header, mp("version"), mp(METADATA_VERSION));
+  header = pmt_dict_add(header, mp("rx_rate"), mp(samp_rate));
+  std::string hdr_str = pmt_serialize_str(header);
+\endcode
+
+The call to pmt_dict_add adds a new key:value pair to the
+dictionary. Notice that it both takes and returns the 'header'
+variable. This is because we are actually creating a new dictionary
+with this function, so we just assign it to the same variable.
+
+The 'mp' functions are convenience functions provided by the PMT
+library. They interpret the data type of the value being inserted and
+call the correct 'pmt_from_xxx' function. For more direct control over
+the data type, see PMT functions in pmt.h, such as pmt_from_uint64 or
+pmt_from_double.
+
+We finish this off by using 'pmt_serialize_str' to convert the PMT
+dictionary into a specialized string format that makes it easy to
+write to a file.
+
+The header is always METADATA_HEADER_SIZE bytes long and a metadata
+file always starts with a header. So to extract the header from a
+file, we need to read in this many bytes from the beginning of the
+file and deserialize it. An important note about this is that the
+deserialize function must operate on a std::string. The serialized
+format of a dictionary contains null characters, so normal C character
+arrays (e.g., 'char *s') get confused.
+
+Assuming that 'std::string str' contains the full string as read from
+a file, we can access the dictionary in C++ like this:
+
+\code
+  pmt_t hdr = pmt_deserialize_str(str);
+  if(pmt_dict_has_key(hdr, pmt_string_to_symbol("strt"))) {
+    pmt_t r = pmt_dict_ref(hdr, pmt_string_to_symbol("strt"), PMT_NIL);
+    uint64_t seg_start = pmt_to_uint64(r);
+    uint64_t extra_len = seg_start - METADATA_HEADER_SIZE;
+  }
+\endcode
+
+This example first deserializes the string into a PMT dictionary
+again. This will throw an error if the string is malformed and cannot
+be deserialized correctly. We then want to get access to the item with
+key 'strt'. As the next subsection will show, this value indicates at
+which byte the data segment starts. We first check to make sure that
+this key exists in the dictionary. If not, our header does not contain
+the correct information and we might want to handle this as an error.
+
+Assuming the header is properly formatted, we then get the particular
+item referenced by the key 'strt'. This is a uint64_t, so we use the
+PMT function to extract and convert this value properly. We now know
+if we have an extra header in the file by looking at the difference
+between 'seg_start' and the static header size,
+METADATA_HEADER_SIZE. If the 'extra_len' is greater than 0, we know we
+have an extra header that we can process. Moreover, this also tells us
+the size of the serialized PMT dictionary in bytes, so we can easily
+read this many bytes from the file. We can then deserialize and parse
+this header just like the first.
+
+
+\subsection header Header Information
+
+The header is a PMT dictionary with a known structure. This structure
+may change, but we version the headers, so all headers of version X
+must be the same length and structure. As of now, we only have version
+0 headers, which look like the following:
+
+- version: (char) version number (usually set to METADATA_VERSION)
+- rx_rate: (double) Stream's sample rate
+- rx_time: (pmt_t pair - (uint64_t, double)) Time stamp (format from UHD)
+- type: (int) data type (enum below)
+- cplx: (bool) true if data is complex
+- strt: (uint64_t) start of data relative to current header
+- size: (uint64_t) size of following data segment
+
+The data types are indicated by an integer value from the following
+enumeration type:
+
+\code
+enum gr_file_types {
+  GR_FILE_BYTE=0,
+  GR_FILE_CHAR=0,
+  GR_FILE_SHORT=1,
+  GR_FILE_INT,
+  GR_FILE_LONG,
+  GR_FILE_LONG_LONG,
+  GR_FILE_FLOAT,
+  GR_FILE_DOUBLE,
+};
+\endcode
+
+\subsection extras Extras Information
+
+The extras section is an optional segment of the header. If 'strt' ==
+METADATA_HEADER_SIZE, then there is no extras. Otherwise, it is simply
+a PMT dictionary of key:value pairs. The extras header can contain
+anything and can grow while a program is running.
+
+We can insert extra data into the header at the beginning if we
+wish. All we need to do is use the 'pmt_dict_add' function to insert
+our hand-made metadata. This can be useful to add our own markers and
+information.
+
+The main role of the extras header, though, is as a container to hold
+any stream tags. When a stream tag is observed coming in, the tag's
+key and value are added to the dictionary. Like a standard dictionary,
+any time a key already exists, the value will be updated. If the key
+does not exist, a new entry is created and the new key:value pair are
+added together. So any new tags that the file metadata sink sees will
+add to the dictionary. It is therefore important to always check the
+'strt' value of the header to see if the length of the extras
+dictionary has changed at all.
+
+When reading out data from the extras, we do not necessarily know the
+data type of the PMT value. The key is always a PMT symbol, but the
+value can be any other PMT type. There are PMT functions that allow us
+to query the PMT to test if it is a particular type. We also have the
+ability to do 'pmt_print' on any PMT object to print it to
+screen. Before converting from a PMT to it's natural data type, it is
+necessary to know the data type.
+
+
+\section Utilities
+
+GNU Radio comes with a couple of utilities to help in debugging and
+manipulating metadata files. There is a general parser in Python that
+will convert the PMT header and extra header into Python
+dictionaries. This utility is:
+
+- gnuradio-core/src/python/gnuradio/parse_file_metadata.py
+
+This program is installed into the Python directory under the
+'gnuradio' module, so it can be accessed with:
+
+\code
+from gnuradio import parse_file_metadata
+\endcode
+
+It defines HEADER_LENGTH as the static length of the metadata header
+size. It also has dictionaries that can be used to convert from the
+file type to a string (ftype_to_string) and one to convert from the
+file type to the size of the data type in bytes (ftype_to_size).
+
+The 'parse_header' takes in a PMT dictionary, parses it, and returns a
+Python dictionary. An optional 'VERBOSE' bool can be set to print the
+information to standard out.
+
+The 'parse_extra_dict' is similar in that it converts from a PMT
+dictionary to a Python dictionary. The values are kept in their PMT
+format since we do not necessarily know the native data type.
+
+A program called 'gr_read_file_metadata' is installed into the path
+and can be used to read out all header information from a metadata
+file. This program is just called with the file name as the first
+command-line argument. An option '-D' will handle detached header
+files where the file of headers is expected to be the file name of the
+data with '.hdr' appended to it.
+
+
+\section Examples
+
+Examples are located in:
+
+- gnuradio-core/src/examples/metadata
+
+Currently, there are two GRC example programs.
+
+- file_metadata_sink: create a metadata file from UHD samples.
+- file_metadata_source: read the metadata file as input to a simple graph.
+
+The file sink example can be switched to use a signal source instead
+of a UHD source, but no extra tagged data is used in this mode.
+
+The file source example pushes the data stream to a new raw file while
+a tag debugger block prints out any tags observed in the metedata
+file. A QT GUI time sink is used to look at the signal as well.
+
+The following shows a simple way of creating extra metadata for a
+metadata file. This example is just showing how we can insert a date
+into the metadata to keep track of later. The date in this case is
+encoded as day|month|year.
+
+\code
+  from gruel import pmt
+
+  key = pmt.pmt_intern("date")
+  val = pmt.pmt_from_uint64(13122012)
+
+  extras = pmt.pmt_make_dict()
+  extras = pmt.pmt_dict_add(extras, key, val)
+  extras_str = pmt.pmt_serialize_str(extrasa)
+  self.sink = gr.file_meta_sink(gr.sizeof_gr_complex,
+                                "/tmp/metadat_file.out",
+				 samp_rate, 1,
+				 gr.GR_FILE_FLOAT, True,
+				 1000000, extra_str, False)
+
+\endcode
+
+*/
-- 
cgit v1.2.3


From 3910c6da3c62232e6593e5fcfe53f5ece933a294 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Fri, 14 Dec 2012 13:57:29 -0500
Subject: core: adding itemsize key to metadata header to allow for vectorized
 items.

This also simplifies some code in the source since we're told exactly what the items size is and don't have to infer.

Also adds an example using vector items.
---
 docs/doxygen/other/metadata.dox                    |   9 +-
 .../metadata/file_metadata_vector_sink.grc         | 219 +++++++++++++
 .../metadata/file_metadata_vector_source.grc       | 338 +++++++++++++++++++++
 gnuradio-core/src/lib/io/gr_file_meta_sink.cc      |   9 +-
 gnuradio-core/src/lib/io/gr_file_meta_sink.h       |   2 +-
 gnuradio-core/src/lib/io/gr_file_meta_sink.i       |   2 +-
 gnuradio-core/src/lib/io/gr_file_meta_source.cc    |  33 +-
 .../src/python/gnuradio/parse_file_metadata.py     |  21 +-
 grc/blocks/gr_file_meta_source.xml                 |   8 +-
 9 files changed, 596 insertions(+), 45 deletions(-)
 create mode 100644 gnuradio-core/src/examples/metadata/file_metadata_vector_sink.grc
 create mode 100644 gnuradio-core/src/examples/metadata/file_metadata_vector_source.grc

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/metadata.dox b/docs/doxygen/other/metadata.dox
index 5b20b9e730..4bc310531d 100644
--- a/docs/doxygen/other/metadata.dox
+++ b/docs/doxygen/other/metadata.dox
@@ -16,9 +16,9 @@ Metadata files have headers that carry information about a segment of
 data within the file. The header structure is described in detail in
 the next section. A metadata file always starts with a header that
 describes the basic structure of the data. It contains information
-about the data type, if it's complex, the sample rate of the segment,
-the time stamp of the first sample of the segment, and information
-regarding the header size and segment size.
+about the item size, data type, if it's complex, the sample rate of
+the segment, the time stamp of the first sample of the segment, and
+information regarding the header size and segment size.
 
 Headers have two main tags associated with them:
 
@@ -190,10 +190,11 @@ must be the same length and structure. As of now, we only have version
 - version: (char) version number (usually set to METADATA_VERSION)
 - rx_rate: (double) Stream's sample rate
 - rx_time: (pmt_t pair - (uint64_t, double)) Time stamp (format from UHD)
+- size: (int) item size in bytes - reflects vector length if any.
 - type: (int) data type (enum below)
 - cplx: (bool) true if data is complex
 - strt: (uint64_t) start of data relative to current header
-- size: (uint64_t) size of following data segment
+- bytes: (uint64_t) size of following data segment in bytes
 
 The data types are indicated by an integer value from the following
 enumeration type:
diff --git a/gnuradio-core/src/examples/metadata/file_metadata_vector_sink.grc b/gnuradio-core/src/examples/metadata/file_metadata_vector_sink.grc
new file mode 100644
index 0000000000..d67af3a660
--- /dev/null
+++ b/gnuradio-core/src/examples/metadata/file_metadata_vector_sink.grc
@@ -0,0 +1,219 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+  <timestamp>Fri Dec 14 13:52:31 2012</timestamp>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>200000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(208, 11)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_vector_source_x</key>
+    <param>
+      <key>id</key>
+      <value>gr_vector_source_x_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>vector</key>
+      <value>10*[0,1,2,3,4,5,6,7,8,9]</value>
+    </param>
+    <param>
+      <key>repeat</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(67, 100)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_file_meta_sink</key>
+    <param>
+      <key>id</key>
+      <value>gr_file_meta_sink_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>file</key>
+      <value>/tmp/metadat_file.out</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>samp_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>rel_rate</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>max_seg_size</key>
+      <value>1000000</value>
+    </param>
+    <param>
+      <key>extra_dict</key>
+      <value></value>
+    </param>
+    <param>
+      <key>detached</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>unbuffered</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(559, 60)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>options</key>
+    <param>
+      <key>id</key>
+      <value>file_metadata_vector_sink</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>title</key>
+      <value></value>
+    </param>
+    <param>
+      <key>author</key>
+      <value></value>
+    </param>
+    <param>
+      <key>description</key>
+      <value></value>
+    </param>
+    <param>
+      <key>window_size</key>
+      <value>1280, 1024</value>
+    </param>
+    <param>
+      <key>generate_options</key>
+      <value>no_gui</value>
+    </param>
+    <param>
+      <key>category</key>
+      <value>Custom</value>
+    </param>
+    <param>
+      <key>run_options</key>
+      <value>run</value>
+    </param>
+    <param>
+      <key>run</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>max_nouts</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>realtime_scheduling</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(10, 10)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_head</key>
+    <param>
+      <key>id</key>
+      <value>gr_head_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>num_items</key>
+      <value>10010000</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(325, 108)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <connection>
+    <source_block_id>gr_vector_source_x_0</source_block_id>
+    <sink_block_id>gr_head_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>gr_head_0</source_block_id>
+    <sink_block_id>gr_file_meta_sink_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+</flow_graph>
diff --git a/gnuradio-core/src/examples/metadata/file_metadata_vector_source.grc b/gnuradio-core/src/examples/metadata/file_metadata_vector_source.grc
new file mode 100644
index 0000000000..0662865f1d
--- /dev/null
+++ b/gnuradio-core/src/examples/metadata/file_metadata_vector_source.grc
@@ -0,0 +1,338 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+  <timestamp>Fri Dec 14 13:55:43 2012</timestamp>
+  <block>
+    <key>options</key>
+    <param>
+      <key>id</key>
+      <value>file_metadata_source</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>title</key>
+      <value></value>
+    </param>
+    <param>
+      <key>author</key>
+      <value></value>
+    </param>
+    <param>
+      <key>description</key>
+      <value></value>
+    </param>
+    <param>
+      <key>window_size</key>
+      <value>1280, 1024</value>
+    </param>
+    <param>
+      <key>generate_options</key>
+      <value>qt_gui</value>
+    </param>
+    <param>
+      <key>category</key>
+      <value>Custom</value>
+    </param>
+    <param>
+      <key>run_options</key>
+      <value>prompt</value>
+    </param>
+    <param>
+      <key>run</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>max_nouts</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>realtime_scheduling</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(10, 10)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>200000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(208, 11)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_file_sink</key>
+    <param>
+      <key>id</key>
+      <value>gr_file_sink_1</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>file</key>
+      <value>/tmp/received_data.out</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>unbuffered</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(564, 215)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_tag_debug</key>
+    <param>
+      <key>id</key>
+      <value>gr_tag_debug_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>name</key>
+      <value>Test</value>
+    </param>
+    <param>
+      <key>num_inputs</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>display</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(563, 298)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_file_meta_source</key>
+    <param>
+      <key>id</key>
+      <value>gr_file_meta_source_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>file</key>
+      <value>/tmp/metadat_file.out</value>
+    </param>
+    <param>
+      <key>repeat</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>detached</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>hdr_file</key>
+      <value>/tmp/metadat_file.out.hdr</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(51, 199)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>qtgui_time_sink_x</key>
+    <param>
+      <key>id</key>
+      <value>qtgui_time_sink_x_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>name</key>
+      <value>QT GUI Plot</value>
+    </param>
+    <param>
+      <key>size</key>
+      <value>1024</value>
+    </param>
+    <param>
+      <key>bw</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>nconnections</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>gui_hint</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(746, 116)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_throttle</key>
+    <param>
+      <key>id</key>
+      <value>gr_throttle_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>samples_per_second</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(322, 223)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_vector_to_stream</key>
+    <param>
+      <key>id</key>
+      <value>blocks_vector_to_stream_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>num_items</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(526, 132)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <connection>
+    <source_block_id>gr_throttle_0</source_block_id>
+    <sink_block_id>gr_file_sink_1</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>gr_throttle_0</source_block_id>
+    <sink_block_id>gr_tag_debug_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>gr_file_meta_source_0</source_block_id>
+    <sink_block_id>gr_throttle_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>blocks_vector_to_stream_0</source_block_id>
+    <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>gr_throttle_0</source_block_id>
+    <sink_block_id>blocks_vector_to_stream_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+</flow_graph>
diff --git a/gnuradio-core/src/lib/io/gr_file_meta_sink.cc b/gnuradio-core/src/lib/io/gr_file_meta_sink.cc
index b016dd1d39..ab0acbdb44 100644
--- a/gnuradio-core/src/lib/io/gr_file_meta_sink.cc
+++ b/gnuradio-core/src/lib/io/gr_file_meta_sink.cc
@@ -116,10 +116,11 @@ gr_file_meta_sink::gr_file_meta_sink(size_t itemsize, const std::string &filenam
   d_header = pmt_dict_add(d_header, mp("version"), mp(METADATA_VERSION));
   d_header = pmt_dict_add(d_header, mp("rx_rate"), mp(samp_rate));
   d_header = pmt_dict_add(d_header, mp("rx_time"), timestamp);
+  d_header = pmt_dict_add(d_header, mp("size"), pmt_from_long(d_itemsize));
   d_header = pmt_dict_add(d_header, mp("type"), pmt_from_long(type));
   d_header = pmt_dict_add(d_header, mp("cplx"), complex ? PMT_T : PMT_F);
   d_header = pmt_dict_add(d_header, mp("strt"), pmt_from_uint64(METADATA_HEADER_SIZE+d_extra_size));
-  d_header = pmt_dict_add(d_header, mp("size"), pmt_from_uint64(0));
+  d_header = pmt_dict_add(d_header, mp("bytes"), pmt_from_uint64(0));
 
   do_update();
 
@@ -305,7 +306,7 @@ gr_file_meta_sink::update_last_header_inline()
   size_t hdrlen = pmt_to_uint64(pmt_dict_ref(d_header, mp("strt"), PMT_NIL));
   size_t seg_size = d_itemsize*d_total_seg_size;
   pmt_t s = pmt_from_uint64(seg_size);
-  update_header(mp("size"), s);
+  update_header(mp("bytes"), s);
   update_header(mp("strt"), pmt_from_uint64(METADATA_HEADER_SIZE+d_extra_size));
   fseek(d_fp, -seg_size-hdrlen, SEEK_CUR);
   write_header(d_fp, d_header, d_extra);
@@ -320,7 +321,7 @@ gr_file_meta_sink::update_last_header_detached()
   size_t hdrlen = pmt_to_uint64(pmt_dict_ref(d_header, mp("strt"), PMT_NIL));
   size_t seg_size = d_itemsize*d_total_seg_size;
   pmt_t s = pmt_from_uint64(seg_size);
-  update_header(mp("size"), s);
+  update_header(mp("bytes"), s);
   update_header(mp("strt"), pmt_from_uint64(METADATA_HEADER_SIZE+d_extra_size));
   fseek(d_hdr_fp, -hdrlen, SEEK_CUR);
   write_header(d_hdr_fp, d_header, d_extra);
@@ -333,7 +334,7 @@ gr_file_meta_sink::write_and_update()
   // based on current index + header size.
   //uint64_t loc = get_last_header_loc();
   pmt_t s = pmt_from_uint64(0);
-  update_header(mp("size"), s);
+  update_header(mp("bytes"), s);
 
   // If we have multiple tags on the same offset, this makes
   // sure we just overwrite the same header each time instead
diff --git a/gnuradio-core/src/lib/io/gr_file_meta_sink.h b/gnuradio-core/src/lib/io/gr_file_meta_sink.h
index c0219ac251..9b67cc4c8a 100644
--- a/gnuradio-core/src/lib/io/gr_file_meta_sink.h
+++ b/gnuradio-core/src/lib/io/gr_file_meta_sink.h
@@ -31,7 +31,7 @@
 using namespace pmt;
 
 const char METADATA_VERSION = 0;
-const size_t METADATA_HEADER_SIZE = 134;
+const size_t METADATA_HEADER_SIZE = 149;
 
 enum gr_file_types {
   GR_FILE_BYTE=0,
diff --git a/gnuradio-core/src/lib/io/gr_file_meta_sink.i b/gnuradio-core/src/lib/io/gr_file_meta_sink.i
index 743e897304..6fa34913be 100644
--- a/gnuradio-core/src/lib/io/gr_file_meta_sink.i
+++ b/gnuradio-core/src/lib/io/gr_file_meta_sink.i
@@ -23,7 +23,7 @@
 GR_SWIG_BLOCK_MAGIC(gr,file_meta_sink)
 
 const char METADATA_VERSION = 0;
-const size_t METADATA_HEADER_SIZE = 134;
+const size_t METADATA_HEADER_SIZE = 149;
 
 enum gr_file_types {
   GR_FILE_BYTE=0,
diff --git a/gnuradio-core/src/lib/io/gr_file_meta_source.cc b/gnuradio-core/src/lib/io/gr_file_meta_source.cc
index 669c5d4779..d940e5edcd 100644
--- a/gnuradio-core/src/lib/io/gr_file_meta_source.cc
+++ b/gnuradio-core/src/lib/io/gr_file_meta_source.cc
@@ -228,38 +228,17 @@ gr_file_meta_source::parse_header(pmt_t hdr, uint64_t offset,
     throw std::runtime_error("file_meta_source: Could not extract time stamp.\n");
   }
 
-  // GET DATA TYPE
-  if(pmt_dict_has_key(hdr, pmt_string_to_symbol("type"))) {
-    int t = pmt_to_long(pmt_dict_ref(hdr, pmt_string_to_symbol("type"), PMT_NIL));
-    switch(t) {
-    case(GR_FILE_CHAR): d_itemsize = sizeof(char); break;
-    case(GR_FILE_SHORT): d_itemsize = sizeof(short); break;
-    case(GR_FILE_INT): d_itemsize = sizeof(int); break;
-    case(GR_FILE_LONG): d_itemsize = sizeof(long int); break;
-    case(GR_FILE_LONG_LONG): d_itemsize = sizeof(long long int); break;
-    case(GR_FILE_FLOAT): d_itemsize = sizeof(float); break;
-    case(GR_FILE_DOUBLE): d_itemsize = sizeof(double); break;
-    default:
-      throw std::runtime_error("file_meta_source: Could not determine data type size.\n");
-    }
-  }
-  else {
-    throw std::runtime_error("file_meta_source: Could not extract data type.\n");
-  }
-
-  // GET COMPLEX INDICATOR
-  if(pmt_dict_has_key(hdr, pmt_string_to_symbol("cplx"))) {
-    bool cplx = pmt_to_bool(pmt_dict_ref(hdr, pmt_string_to_symbol("cplx"), PMT_NIL));
-    if(cplx)
-      d_itemsize *= 2;
+  // GET ITEM SIZE OF DATA
+  if(pmt_dict_has_key(hdr, pmt_string_to_symbol("size"))) {
+    d_itemsize = pmt_to_long(pmt_dict_ref(hdr, pmt_string_to_symbol("size"), PMT_NIL));
   }
   else {
-    throw std::runtime_error("file_meta_source: Could not extract complex indicator.\n");
+    throw std::runtime_error("file_meta_source: Could not extract item size.\n");
   }
 
   // GET SEGMENT SIZE
-  if(pmt_dict_has_key(hdr, pmt_string_to_symbol("size"))) {
-    d_seg_size = pmt_to_uint64(pmt_dict_ref(hdr, pmt_string_to_symbol("size"), PMT_NIL));
+  if(pmt_dict_has_key(hdr, pmt_string_to_symbol("bytes"))) {
+    d_seg_size = pmt_to_uint64(pmt_dict_ref(hdr, pmt_string_to_symbol("bytes"), PMT_NIL));
 
     // Convert from bytes to items
     d_seg_size /= d_itemsize;
diff --git a/gnuradio-core/src/python/gnuradio/parse_file_metadata.py b/gnuradio-core/src/python/gnuradio/parse_file_metadata.py
index fa54db7465..0cee5a02cc 100644
--- a/gnuradio-core/src/python/gnuradio/parse_file_metadata.py
+++ b/gnuradio-core/src/python/gnuradio/parse_file_metadata.py
@@ -96,6 +96,17 @@ def parse_header(p, VERBOSE=False):
         sys.stderr.write("Could not find key 'time': invalid or corrupt data file.\n")
         sys.exit(1)
 
+    # EXTRACT ITEM SIZE
+    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("size"))):
+        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("size"), dump)
+        dsize = pmt.pmt_to_long(r)
+        info["size"] = dsize
+        if(VERBOSE):
+            print "Item size: {0}".format(dsize)
+    else:
+        sys.stderr.write("Could not find key 'size': invalid or corrupt data file.\n")
+        sys.exit(1)
+
     # EXTRACT DATA TYPE
     if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("type"))):
         r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("type"), dump)
@@ -135,15 +146,11 @@ def parse_header(p, VERBOSE=False):
         sys.exit(1)
 
     # EXTRACT SIZE OF DATA
-    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("size"))):
-        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("size"), dump)
+    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("bytes"))):
+        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("bytes"), dump)
         nbytes = pmt.pmt_to_uint64(r)
 
-        # Multiply itemsize by 2 if complex
-        if(cplx): mult=2
-        else: mult=1
-
-        nitems = nbytes/(ftype_to_size[dtype]*mult)
+        nitems = nbytes/dsize
         info["nitems"] = nitems
         info["nbytes"] = nbytes
 
diff --git a/grc/blocks/gr_file_meta_source.xml b/grc/blocks/gr_file_meta_source.xml
index 9e5fcb0a21..8f667961e4 100644
--- a/grc/blocks/gr_file_meta_source.xml
+++ b/grc/blocks/gr_file_meta_source.xml
@@ -80,9 +80,15 @@
 		<value></value>
 		<type>file_open</type>
 	</param>
+	<param>
+		<name>Vec Length</name>
+		<key>vlen</key>
+		<value>1</value>
+		<type>int</type>
+	</param>
 	<source>
 		<name>out</name>
 		<type>$type</type>
-		<vlen>1</vlen>
+		<vlen>$vlen</vlen>
 	</source>
 </block>
-- 
cgit v1.2.3


From 8e8ed231cd2469e1a39c5ae6af23ac9b29264af7 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Fri, 14 Dec 2012 16:00:27 -0500
Subject: gruel: Enabling serialize/deserialize for PMT vectors.

---
 docs/doxygen/other/metadata.dox    |   6 +-
 gruel/src/include/gruel/pmt.h      |   4 +-
 gruel/src/lib/pmt/pmt_serialize.cc | 344 ++++++++++++++++++++++++++++++++++++-
 gruel/src/python/qa_pmt.py         |  76 +++++++-
 gruel/src/swig/pmt_swig.i          |   8 +-
 5 files changed, 415 insertions(+), 23 deletions(-)

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/metadata.dox b/docs/doxygen/other/metadata.dox
index 4bc310531d..1b3c891a8d 100644
--- a/docs/doxygen/other/metadata.dox
+++ b/docs/doxygen/other/metadata.dox
@@ -301,17 +301,17 @@ file. A QT GUI time sink is used to look at the signal as well.
 The following shows a simple way of creating extra metadata for a
 metadata file. This example is just showing how we can insert a date
 into the metadata to keep track of later. The date in this case is
-encoded as day|month|year.
+encoded as a vector of uint16 with [day, month, year].
 
 \code
   from gruel import pmt
 
   key = pmt.pmt_intern("date")
-  val = pmt.pmt_from_uint64(13122012)
+  val = pmt.pmt_init_u16vector(3, [13,12,2012])
 
   extras = pmt.pmt_make_dict()
   extras = pmt.pmt_dict_add(extras, key, val)
-  extras_str = pmt.pmt_serialize_str(extrasa)
+  extras_str = pmt.pmt_serialize_str(extras)
   self.sink = gr.file_meta_sink(gr.sizeof_gr_complex,
                                 "/tmp/metadat_file.out",
 				 samp_rate, 1,
diff --git a/gruel/src/include/gruel/pmt.h b/gruel/src/include/gruel/pmt.h
index 1dd8eb74b0..68b122105a 100644
--- a/gruel/src/include/gruel/pmt.h
+++ b/gruel/src/include/gruel/pmt.h
@@ -433,9 +433,9 @@ GRUEL_API pmt_t pmt_init_f32vector(size_t k, const std::vector<float> &data);
 GRUEL_API pmt_t pmt_init_f64vector(size_t k, const double *data);
 GRUEL_API pmt_t pmt_init_f64vector(size_t k, const std::vector<double> &data);
 GRUEL_API pmt_t pmt_init_c32vector(size_t k, const std::complex<float> *data);
-GRUEL_API pmt_t pmt_init_c32vector(size_t k, const std::vector< std::complex<float> > &data);
+GRUEL_API pmt_t pmt_init_c32vector(size_t k, const std::vector<std::complex<float> > &data);
 GRUEL_API pmt_t pmt_init_c64vector(size_t k, const std::complex<double> *data);
-GRUEL_API pmt_t pmt_init_c64vector(size_t k, const std::vector< std::complex<double> > &data);
+GRUEL_API pmt_t pmt_init_c64vector(size_t k, const std::vector<std::complex<double> > &data);
 
 GRUEL_API uint8_t  pmt_u8vector_ref(pmt_t v, size_t k);
 GRUEL_API int8_t   pmt_s8vector_ref(pmt_t v, size_t k);
diff --git a/gruel/src/lib/pmt/pmt_serialize.cc b/gruel/src/lib/pmt/pmt_serialize.cc
index a19809a667..1ee7ca1fe7 100644
--- a/gruel/src/lib/pmt/pmt_serialize.cc
+++ b/gruel/src/lib/pmt/pmt_serialize.cc
@@ -309,11 +309,192 @@ pmt_serialize(pmt_t obj, std::streambuf &sb)
 
   }
 
-  if (pmt_is_vector(obj))
-    throw pmt_notimplemented("pmt_serialize (vector)", obj);
+  if (pmt_is_vector(obj)) {
+    size_t vec_len = pmt::pmt_length(obj);
+    ok = serialize_untagged_u8(PST_VECTOR, sb);
+    ok &= serialize_untagged_u32(vec_len, sb);
+    for(size_t i=0; i<vec_len; i++) {
+      ok &= pmt_serialize(pmt_vector_ref(obj, i), sb);
+    }
+    return ok;
+  }
+
+  if (pmt_is_uniform_vector(obj)) {
+    size_t npad = 1;
+    size_t vec_len = pmt::pmt_length(obj);
+
+    if(pmt_is_u8vector(obj)) {
+      ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb);
+      ok &= serialize_untagged_u8(UVI_U8, sb);
+      ok &= serialize_untagged_u32(vec_len, sb);
+      ok &= serialize_untagged_u8(npad, sb);
+      for(size_t i=0; i<npad; i++) {
+	ok &= serialize_untagged_u8(0, sb);
+      }
+      for(size_t i=0; i<vec_len; i++) {
+	ok &= serialize_untagged_u8(pmt_u8vector_ref(obj, i), sb);
+      }
+      return ok;
+    }
+
+    if(pmt_is_s8vector(obj)) {
+      ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb);
+      ok &= serialize_untagged_u8(UVI_S8, sb);
+      ok &= serialize_untagged_u32(vec_len, sb);
+      ok &= serialize_untagged_u8(npad, sb);
+      for(size_t i=0; i<npad; i++) {
+	ok &= serialize_untagged_u8(0, sb);
+      }
+      for(size_t i=0; i<vec_len; i++) {
+	ok &= serialize_untagged_u8(pmt_s8vector_ref(obj, i), sb);
+      }
+      return ok;
+    }
+
+    if(pmt_is_u16vector(obj)) {
+      ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb);
+      ok &= serialize_untagged_u8(UVI_U16, sb);
+      ok &= serialize_untagged_u32(vec_len, sb);
+      ok &= serialize_untagged_u8(npad, sb);
+      for(size_t i=0; i<npad; i++) {
+	ok &= serialize_untagged_u8(0, sb);
+      }
+      for(size_t i=0; i<vec_len; i++) {
+	ok &= serialize_untagged_u16(pmt_u16vector_ref(obj, i), sb);
+      }
+      return ok;
+    }
+
+    if(pmt_is_s16vector(obj)) {
+      ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb);
+      ok &= serialize_untagged_u8(UVI_S16, sb);
+      ok &= serialize_untagged_u32(vec_len, sb);
+      ok &= serialize_untagged_u8(npad, sb);
+      for(size_t i=0; i<npad; i++) {
+	ok &= serialize_untagged_u8(0, sb);
+      }
+      for(size_t i=0; i<vec_len; i++) {
+	ok &= serialize_untagged_u16(pmt_s16vector_ref(obj, i), sb);
+      }
+      return ok;
+    }
 
-  if (pmt_is_uniform_vector(obj))
-    throw pmt_notimplemented("pmt_serialize (uniform-vector)", obj);
+    if(pmt_is_u32vector(obj)) {
+      ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb);
+      ok &= serialize_untagged_u8(UVI_U32, sb);
+      ok &= serialize_untagged_u32(vec_len, sb);
+      ok &= serialize_untagged_u8(npad, sb);
+      for(size_t i=0; i<npad; i++) {
+	ok &= serialize_untagged_u8(0, sb);
+      }
+      for(size_t i=0; i<vec_len; i++) {
+	ok &= serialize_untagged_u32(pmt_u32vector_ref(obj, i), sb);
+      }
+      return ok;
+    }
+
+    if(pmt_is_s32vector(obj)) {
+      ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb);
+      ok &= serialize_untagged_u8(UVI_S32, sb);
+      ok &= serialize_untagged_u32(vec_len, sb);
+      ok &= serialize_untagged_u8(npad, sb);
+      for(size_t i=0; i<npad; i++) {
+	ok &= serialize_untagged_u8(0, sb);
+      }
+      for(size_t i=0; i<vec_len; i++) {
+	ok &= serialize_untagged_u32(pmt_s32vector_ref(obj, i), sb);
+      }
+      return ok;
+    }
+
+    if(pmt_is_u64vector(obj)) {
+      ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb);
+      ok &= serialize_untagged_u8(UVI_U64, sb);
+      ok &= serialize_untagged_u32(vec_len, sb);
+      ok &= serialize_untagged_u8(npad, sb);
+      for(size_t i=0; i<npad; i++) {
+	ok &= serialize_untagged_u8(0, sb);
+      }
+      for(size_t i=0; i<vec_len; i++) {
+	ok &= serialize_untagged_u64(pmt_u64vector_ref(obj, i), sb);
+      }
+      return ok;
+    }
+
+    if(pmt_is_s64vector(obj)) {
+      ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb);
+      ok &= serialize_untagged_u8(UVI_S64, sb);
+      ok &= serialize_untagged_u32(vec_len, sb);
+      ok &= serialize_untagged_u8(npad, sb);
+      for(size_t i=0; i<npad; i++) {
+	ok &= serialize_untagged_u8(0, sb);
+      }
+      for(size_t i=0; i<vec_len; i++) {
+	ok &= serialize_untagged_u64(pmt_s64vector_ref(obj, i), sb);
+      }
+      return ok;
+    }
+
+    if(pmt_is_f32vector(obj)) {
+      ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb);
+      ok &= serialize_untagged_u8(UVI_F32, sb);
+      ok &= serialize_untagged_u32(vec_len, sb);
+      ok &= serialize_untagged_u8(npad, sb);
+      for(size_t i=0; i<npad; i++) {
+	ok &= serialize_untagged_u8(0, sb);
+      }
+      for(size_t i=0; i<vec_len; i++) {
+	ok &= serialize_untagged_f64(pmt_f32vector_ref(obj, i), sb);
+      }
+      return ok;
+    }
+
+    if(pmt_is_f64vector(obj)) {
+      ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb);
+      ok &= serialize_untagged_u8(UVI_F64, sb);
+      ok &= serialize_untagged_u32(vec_len, sb);
+      ok &= serialize_untagged_u8(npad, sb);
+      for(size_t i=0; i<npad; i++) {
+	ok &= serialize_untagged_u8(0, sb);
+      }
+      for(size_t i=0; i<vec_len; i++) {
+	ok &= serialize_untagged_f64(pmt_f64vector_ref(obj, i), sb);
+      }
+      return ok;
+    }
+
+    if(pmt_is_c32vector(obj)) {
+      ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb);
+      ok &= serialize_untagged_u8(UVI_C32, sb);
+      ok &= serialize_untagged_u32(vec_len, sb);
+      ok &= serialize_untagged_u8(npad, sb);
+      for(size_t i=0; i<npad; i++) {
+	ok &= serialize_untagged_u8(0, sb);
+      }
+      for(size_t i=0; i<vec_len; i++) {
+	std::complex<float> c = pmt_c32vector_ref(obj, i);
+	ok &= serialize_untagged_f64(c.real(), sb);
+	ok &= serialize_untagged_f64(c.imag(), sb);
+      }
+      return ok;
+    }
+
+    if(pmt_is_c64vector(obj)) {
+      ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb);
+      ok &= serialize_untagged_u8(UVI_C64, sb);
+      ok &= serialize_untagged_u32(vec_len, sb);
+      ok &= serialize_untagged_u8(npad, sb);
+      for(size_t i=0; i<npad; i++) {
+	ok &= serialize_untagged_u8(0, sb);
+      }
+      for(size_t i=0; i<vec_len; i++) {
+	std::complex<double> c = pmt_c64vector_ref(obj, i);
+	ok &= serialize_untagged_f64(c.real(), sb);
+	ok &= serialize_untagged_f64(c.imag(), sb);
+      }
+      return ok;
+    }
+  }
 
   if (pmt_is_dict(obj))
     throw pmt_notimplemented("pmt_serialize (dict)", obj);
@@ -342,7 +523,7 @@ pmt_t
 pmt_deserialize(std::streambuf &sb)
 {
   uint8_t	tag;
-  //uint8_t	u8;
+  uint8_t	u8;
   uint16_t	u16;
   uint32_t	u32;
   uint64_t	u64;
@@ -408,8 +589,159 @@ pmt_deserialize(std::streambuf &sb)
     }
 
   case PST_VECTOR:
-  case PST_DICT:
+    {
+    uint32_t nitems;
+    if(!deserialize_untagged_u32(&nitems, sb))
+      goto error;
+    pmt_t vec = pmt_make_vector(nitems, PMT_NIL);
+    for(uint32_t i=0; i<nitems; i++) {
+      pmt_t item = pmt_deserialize(sb);
+      pmt_vector_set(vec, i, item);
+    }
+    return vec;
+    }
+
   case PST_UNIFORM_VECTOR:
+    {
+      uint8_t utag, npad;
+      uint32_t nitems;
+
+      if(!deserialize_untagged_u8(&utag, sb))
+	return PMT_EOF;
+
+      if(!deserialize_untagged_u32(&nitems, sb))
+	goto error;
+      
+      deserialize_untagged_u8(&npad, sb);
+      for(size_t i; i < npad; i++)
+	deserialize_untagged_u8(&u8, sb);
+
+      switch(utag) {
+      case(UVI_U8):
+	{
+	  pmt_t vec = pmt_make_u8vector(nitems, 0);
+	  for(uint32_t i=0; i<nitems; i++) {
+	    deserialize_untagged_u8(&u8, sb);
+	    pmt_u8vector_set(vec, i, u8);
+	  }
+	  return vec;
+	}
+      case(UVI_S8):
+	{
+	  pmt_t vec = pmt_make_s8vector(nitems, 0);
+	  for(uint32_t i=0; i<nitems; i++) {
+	    deserialize_untagged_u8(&u8, sb);
+	    pmt_s8vector_set(vec, i, u8);
+	  }
+	  return vec;
+	}
+      case(UVI_U16):
+	{
+	  pmt_t vec = pmt_make_u16vector(nitems, 0);
+	  for(uint32_t i=0; i<nitems; i++) {
+	    deserialize_untagged_u16(&u16, sb);
+	    pmt_u16vector_set(vec, i, u16);
+	  }
+	  return vec;
+	}
+      case(UVI_S16):
+	{
+	  pmt_t vec = pmt_make_s16vector(nitems, 0);
+	  for(uint32_t i=0; i<nitems; i++) {
+	    deserialize_untagged_u16(&u16, sb);
+	    pmt_s16vector_set(vec, i, u16);
+	  }
+	  return vec;
+	}
+      case(UVI_U32):
+	{
+	  pmt_t vec = pmt_make_u32vector(nitems, 0);
+	  for(uint32_t i=0; i<nitems; i++) {
+	    deserialize_untagged_u32(&u32, sb);
+	    pmt_u32vector_set(vec, i, u32);
+	  }
+	  return vec;
+	}
+      case(UVI_S32):
+	{
+	  pmt_t vec = pmt_make_s32vector(nitems, 0);
+	  for(uint32_t i=0; i<nitems; i++) {
+	    deserialize_untagged_u32(&u32, sb);
+	    pmt_s32vector_set(vec, i, u32);
+	  }
+	  return vec;
+	}
+      case(UVI_U64):
+	{
+	  pmt_t vec = pmt_make_u64vector(nitems, 0);
+	  for(uint32_t i=0; i<nitems; i++) {
+	    deserialize_untagged_u64(&u64, sb);
+	    pmt_u64vector_set(vec, i, u64);
+	  }
+	  return vec;
+	}
+      case(UVI_S64):
+	{
+	  pmt_t vec = pmt_make_s64vector(nitems, 0);
+	  for(uint32_t i=0; i<nitems; i++) {
+	    deserialize_untagged_u64(&u64, sb);
+	    pmt_s64vector_set(vec, i, u64);
+	  }
+	  return vec;
+	}
+      case(UVI_F32):
+	{
+	  pmt_t vec = pmt_make_f32vector(nitems, 0);
+	  for(uint32_t i=0; i<nitems; i++) {
+	    deserialize_untagged_f64(&f64, sb);
+	    pmt_f32vector_set(vec, i, static_cast<float>(f64));
+	  }
+	  return vec;
+	}
+      case(UVI_F64):
+	{
+	  pmt_t vec = pmt_make_f64vector(nitems, 0);
+	  for(uint32_t i=0; i<nitems; i++) {
+	    deserialize_untagged_f64(&f64, sb);
+	    pmt_f64vector_set(vec, i, f64);
+	  }
+	  return vec;
+	}
+      case(UVI_C32):
+	{
+	  pmt_t vec = pmt_make_c32vector(nitems, 0);
+	  for(uint32_t i=0; i<nitems; i++) {
+	    std::complex<float> c;
+	    deserialize_untagged_f64(&f64, sb);
+	    c.real(static_cast<float>(f64));
+	    deserialize_untagged_f64(&f64, sb);
+	    c.imag(static_cast<float>(f64));
+	    pmt_c32vector_set(vec, i, c);
+	  }
+	  return vec;
+	}
+
+      case(UVI_C64):
+	{
+	  pmt_t vec = pmt_make_c64vector(nitems, 0);
+	  for(uint32_t i=0; i<nitems; i++) {
+	    std::complex<double> c;
+	    deserialize_untagged_f64(&f64, sb);
+	    c.real(f64);
+	    deserialize_untagged_f64(&f64, sb);
+	    c.imag(f64);
+	    pmt_c64vector_set(vec, i, c);
+	  }
+	  return vec;
+	}
+
+      default:
+	throw pmt_exception("pmt_deserialize: malformed input stream, tag value = ",
+			    pmt_from_long(tag));
+      }
+    }
+
+  case PST_DICT:
   case PST_COMMENT:
     throw pmt_notimplemented("pmt_deserialize: tag value = ",
 			     pmt_from_long(tag));
diff --git a/gruel/src/python/qa_pmt.py b/gruel/src/python/qa_pmt.py
index 1ef4fed15b..59a5725fc4 100755
--- a/gruel/src/python/qa_pmt.py
+++ b/gruel/src/python/qa_pmt.py
@@ -21,22 +21,82 @@
 #
 
 import unittest
-import pmt_swig
+import pmt_swig as pmt
 
 class test_gruel_pmt(unittest.TestCase):
 
     def test01 (self):
-        a = pmt_swig.pmt_intern("a")
-        b = pmt_swig.pmt_from_double(123765)
-        d1 = pmt_swig.pmt_make_dict()
-        d2 = pmt_swig.pmt_dict_add(d1, a, b)
-        pmt_swig.pmt_print(d2)
+        a = pmt.pmt_intern("a")
+        b = pmt.pmt_from_double(123765)
+        d1 = pmt.pmt_make_dict()
+        d2 = pmt.pmt_dict_add(d1, a, b)
+        pmt.pmt_print(d2)
 
     def test02 (self):
         const = 123765
-        x_pmt = pmt_swig.pmt_from_double(const)
-        x_int = pmt_swig.pmt_to_double(x_pmt)
+        x_pmt = pmt.pmt_from_double(const)
+        x_int = pmt.pmt_to_double(x_pmt)
         self.assertEqual(x_int, const)
 
+    def test03(self):
+        v = pmt.pmt_init_f32vector(3, [11, -22, 33])
+        s = pmt.pmt_serialize_str(v)
+        d = pmt.pmt_deserialize_str(s)
+        self.assertTrue(pmt.pmt_equal(v, d))
+
+    def test04(self):
+        v = pmt.pmt_init_f64vector(3, [11, -22, 33])
+        s = pmt.pmt_serialize_str(v)
+        d = pmt.pmt_deserialize_str(s)
+        self.assertTrue(pmt.pmt_equal(v, d))
+
+    def test05(self):
+        v = pmt.pmt_init_u8vector(3, [11, 22, 33])
+        s = pmt.pmt_serialize_str(v)
+        d = pmt.pmt_deserialize_str(s)
+        self.assertTrue(pmt.pmt_equal(v, d))
+
+    def test06(self):
+        v = pmt.pmt_init_s8vector(3, [11, -22, 33])
+        s = pmt.pmt_serialize_str(v)
+        d = pmt.pmt_deserialize_str(s)
+        self.assertTrue(pmt.pmt_equal(v, d))
+
+    def test07(self):
+        v = pmt.pmt_init_u16vector(3, [11, 22, 33])
+        s = pmt.pmt_serialize_str(v)
+        d = pmt.pmt_deserialize_str(s)
+        self.assertTrue(pmt.pmt_equal(v, d))
+
+    def test08(self):
+        v = pmt.pmt_init_s16vector(3, [11, -22, 33])
+        s = pmt.pmt_serialize_str(v)
+        d = pmt.pmt_deserialize_str(s)
+        self.assertTrue(pmt.pmt_equal(v, d))
+
+    def test09(self):
+        v = pmt.pmt_init_u32vector(3, [11, 22, 33])
+        s = pmt.pmt_serialize_str(v)
+        d = pmt.pmt_deserialize_str(s)
+        self.assertTrue(pmt.pmt_equal(v, d))
+
+    def test10(self):
+        v = pmt.pmt_init_s32vector(3, [11, -22, 33])
+        s = pmt.pmt_serialize_str(v)
+        d = pmt.pmt_deserialize_str(s)
+        self.assertTrue(pmt.pmt_equal(v, d))
+
+    def test11(self):
+        v = pmt.pmt_init_c32vector(3, [11 + -101j, -22 + 202j, 33 + -303j])
+        s = pmt.pmt_serialize_str(v)
+        d = pmt.pmt_deserialize_str(s)
+        self.assertTrue(pmt.pmt_equal(v, d))
+
+    def test12(self):
+        v = pmt.pmt_init_c64vector(3, [11 + -101j, -22 + 202j, 33 + -303j])
+        s = pmt.pmt_serialize_str(v)
+        d = pmt.pmt_deserialize_str(s)
+        self.assertTrue(pmt.pmt_equal(v, d))
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/gruel/src/swig/pmt_swig.i b/gruel/src/swig/pmt_swig.i
index 67dda5c3f4..b658571671 100644
--- a/gruel/src/swig/pmt_swig.i
+++ b/gruel/src/swig/pmt_swig.i
@@ -55,8 +55,8 @@ namespace std {
   %template()	  vector<uint32_t>;
   %template()	  vector<float>;
   %template()	  vector<double>;
-  %template()	  vector< complex<float> >;
-  %template()	  vector< complex<double> >;
+  %template()	  vector< std::complex<float> >;
+  %template()	  vector< std::complex<double> >;
 };
 
 ////////////////////////////////////////////////////////////////////////
@@ -410,8 +410,8 @@ pmt_t pmt_init_u32vector(size_t k, const std::vector<uint32_t> &data);
 pmt_t pmt_init_s32vector(size_t k, const std::vector<int32_t> &data);
 pmt_t pmt_init_f32vector(size_t k, const std::vector<float> &data);
 pmt_t pmt_init_f64vector(size_t k, const std::vector<double> &data);
-pmt_t pmt_init_c32vector(size_t k, const std::vector< std::complex<float> > &data);
-pmt_t pmt_init_c64vector(size_t k, const std::vector< std::complex<double> > &data);
+pmt_t pmt_init_c32vector(size_t k, const std::vector<std::complex<float> > &data);
+pmt_t pmt_init_c64vector(size_t k, const std::vector<std::complex<double> > &data);
 
 uint8_t  pmt_u8vector_ref(pmt_t v, size_t k);
 int8_t   pmt_s8vector_ref(pmt_t v, size_t k);
-- 
cgit v1.2.3


From 461ece56b36a44b2405282630157739c7f9a26ba Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Fri, 14 Dec 2012 16:10:30 -0500
Subject: blocks: moving file metadata sink/source to gr-blocks.

---
 docs/doxygen/other/metadata.dox                    |  32 +-
 gnuradio-core/src/examples/CMakeLists.txt          |   1 -
 gnuradio-core/src/examples/metadata/CMakeLists.txt |  28 -
 .../src/examples/metadata/file_metadata_sink.grc   | 951 ---------------------
 .../src/examples/metadata/file_metadata_source.grc | 346 --------
 .../metadata/file_metadata_vector_sink.grc         | 219 -----
 .../metadata/file_metadata_vector_source.grc       | 338 --------
 gnuradio-core/src/lib/io/CMakeLists.txt            |   2 -
 gnuradio-core/src/lib/io/gr_file_meta_sink.cc      | 457 ----------
 gnuradio-core/src/lib/io/gr_file_meta_sink.h       | 169 ----
 gnuradio-core/src/lib/io/gr_file_meta_sink.i       |  63 --
 gnuradio-core/src/lib/io/gr_file_meta_source.cc    | 427 ---------
 gnuradio-core/src/lib/io/gr_file_meta_source.h     | 126 ---
 gnuradio-core/src/lib/io/gr_file_meta_source.i     |  45 -
 gnuradio-core/src/lib/io/io.i                      |   4 -
 gnuradio-core/src/python/gnuradio/CMakeLists.txt   |   1 -
 .../src/python/gnuradio/gr/qa_file_metadata.py     | 196 -----
 .../src/python/gnuradio/parse_file_metadata.py     | 183 ----
 gr-blocks/CMakeLists.txt                           |   1 +
 gr-blocks/examples/CMakeLists.txt                  |  20 +
 gr-blocks/examples/metadata/CMakeLists.txt         |  30 +
 gr-blocks/examples/metadata/file_metadata_sink.grc | 951 +++++++++++++++++++++
 .../examples/metadata/file_metadata_source.grc     | 350 ++++++++
 .../metadata/file_metadata_vector_sink.grc         | 219 +++++
 .../metadata/file_metadata_vector_source.grc       | 338 ++++++++
 gr-blocks/grc/blocks_block_tree.xml                |   5 +
 gr-blocks/grc/blocks_file_meta_sink.xml            | 124 +++
 gr-blocks/grc/blocks_file_meta_source.xml          |  94 ++
 gr-blocks/include/blocks/CMakeLists.txt            |   2 +
 gr-blocks/include/blocks/file_meta_sink.h          | 111 +++
 gr-blocks/include/blocks/file_meta_source.h        |  81 ++
 gr-blocks/lib/CMakeLists.txt                       |   2 +
 gr-blocks/lib/file_meta_sink_impl.cc               | 464 ++++++++++
 gr-blocks/lib/file_meta_sink_impl.h                |  96 +++
 gr-blocks/lib/file_meta_source_impl.cc             | 433 ++++++++++
 gr-blocks/lib/file_meta_source_impl.h              |  89 ++
 gr-blocks/python/CMakeLists.txt                    |   1 +
 gr-blocks/python/parse_file_metadata.py            | 188 ++++
 gr-blocks/python/qa_file_metadata.py               | 197 +++++
 gr-blocks/swig/blocks_swig.i                       |   6 +
 gr-utils/src/python/gr_read_file_metadata          |   8 +-
 grc/blocks/block_tree.xml                          |   2 -
 grc/blocks/gr_file_meta_sink.xml                   | 124 ---
 grc/blocks/gr_file_meta_source.xml                 |  94 --
 44 files changed, 3825 insertions(+), 3793 deletions(-)
 delete mode 100644 gnuradio-core/src/examples/metadata/CMakeLists.txt
 delete mode 100644 gnuradio-core/src/examples/metadata/file_metadata_sink.grc
 delete mode 100644 gnuradio-core/src/examples/metadata/file_metadata_source.grc
 delete mode 100644 gnuradio-core/src/examples/metadata/file_metadata_vector_sink.grc
 delete mode 100644 gnuradio-core/src/examples/metadata/file_metadata_vector_source.grc
 delete mode 100644 gnuradio-core/src/lib/io/gr_file_meta_sink.cc
 delete mode 100644 gnuradio-core/src/lib/io/gr_file_meta_sink.h
 delete mode 100644 gnuradio-core/src/lib/io/gr_file_meta_sink.i
 delete mode 100644 gnuradio-core/src/lib/io/gr_file_meta_source.cc
 delete mode 100644 gnuradio-core/src/lib/io/gr_file_meta_source.h
 delete mode 100644 gnuradio-core/src/lib/io/gr_file_meta_source.i
 delete mode 100644 gnuradio-core/src/python/gnuradio/gr/qa_file_metadata.py
 delete mode 100644 gnuradio-core/src/python/gnuradio/parse_file_metadata.py
 create mode 100644 gr-blocks/examples/CMakeLists.txt
 create mode 100644 gr-blocks/examples/metadata/CMakeLists.txt
 create mode 100644 gr-blocks/examples/metadata/file_metadata_sink.grc
 create mode 100644 gr-blocks/examples/metadata/file_metadata_source.grc
 create mode 100644 gr-blocks/examples/metadata/file_metadata_vector_sink.grc
 create mode 100644 gr-blocks/examples/metadata/file_metadata_vector_source.grc
 create mode 100644 gr-blocks/grc/blocks_file_meta_sink.xml
 create mode 100644 gr-blocks/grc/blocks_file_meta_source.xml
 create mode 100644 gr-blocks/include/blocks/file_meta_sink.h
 create mode 100644 gr-blocks/include/blocks/file_meta_source.h
 create mode 100644 gr-blocks/lib/file_meta_sink_impl.cc
 create mode 100644 gr-blocks/lib/file_meta_sink_impl.h
 create mode 100644 gr-blocks/lib/file_meta_source_impl.cc
 create mode 100644 gr-blocks/lib/file_meta_source_impl.h
 create mode 100644 gr-blocks/python/parse_file_metadata.py
 create mode 100644 gr-blocks/python/qa_file_metadata.py
 delete mode 100644 grc/blocks/gr_file_meta_sink.xml
 delete mode 100644 grc/blocks/gr_file_meta_source.xml

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/metadata.dox b/docs/doxygen/other/metadata.dox
index 1b3c891a8d..9fad7c584c 100644
--- a/docs/doxygen/other/metadata.dox
+++ b/docs/doxygen/other/metadata.dox
@@ -9,8 +9,8 @@ the system state such as sample rate or if a receiver's frequency are
 not conveyed with the data in the file itself. Header of metadata
 solve this problem.
 
-We write metadata files using gr_file_meta_sink and read metadata
-files using gr_file_meta_source.
+We write metadata files using blocks::file_meta_sink and read metadata
+files using blocks::file_meta_source.
 
 Metadata files have headers that carry information about a segment of
 data within the file. The header structure is described in detail in
@@ -88,12 +88,12 @@ keep the sample times exact.
 
 \subsection implementation Implementation
 
-Metadata files are created using gr_file_meta_sink. The default
+Metadata files are created using file_meta_sink. The default
 behavior is to create a single file with inline headers as
 metadata. An option can be set to switch to detached header mode.
 
 Metadata file are read into a flowgraph using
-gr_file_meta_source. This source reads a metadata file, inline by
+file_meta_source. This source reads a metadata file, inline by
 default with a settable option to use detached headers. The data from
 the segments is converted into a standard streaming output. The
 'rx_rate' and 'rx_time' and all key:value pairs in the extra header
@@ -250,13 +250,13 @@ manipulating metadata files. There is a general parser in Python that
 will convert the PMT header and extra header into Python
 dictionaries. This utility is:
 
-- gnuradio-core/src/python/gnuradio/parse_file_metadata.py
+- gr-blocks/python/parse_file_metadata.py
 
 This program is installed into the Python directory under the
 'gnuradio' module, so it can be accessed with:
 
 \code
-from gnuradio import parse_file_metadata
+from gnuradio.blocks import parse_file_metadata
 \endcode
 
 It defines HEADER_LENGTH as the static length of the metadata header
@@ -284,12 +284,14 @@ data with '.hdr' appended to it.
 
 Examples are located in:
 
-- gnuradio-core/src/examples/metadata
+- gr-blocks/examples/metadata
 
-Currently, there are two GRC example programs.
+Currently, there are a few GRC example programs.
 
 - file_metadata_sink: create a metadata file from UHD samples.
 - file_metadata_source: read the metadata file as input to a simple graph.
+- file_metadata_vector_sink: create a metadata file from UHD samples.
+- file_metadata_vector_source: read the metadata file as input to a simple graph.
 
 The file sink example can be switched to use a signal source instead
 of a UHD source, but no extra tagged data is used in this mode.
@@ -298,6 +300,9 @@ The file source example pushes the data stream to a new raw file while
 a tag debugger block prints out any tags observed in the metedata
 file. A QT GUI time sink is used to look at the signal as well.
 
+The versions with 'vector' in the name are similar except they use
+vectors of data.
+
 The following shows a simple way of creating extra metadata for a
 metadata file. This example is just showing how we can insert a date
 into the metadata to keep track of later. The date in this case is
@@ -305,6 +310,7 @@ encoded as a vector of uint16 with [day, month, year].
 
 \code
   from gruel import pmt
+  from gnuradio import blocks
 
   key = pmt.pmt_intern("date")
   val = pmt.pmt_init_u16vector(3, [13,12,2012])
@@ -312,11 +318,11 @@ encoded as a vector of uint16 with [day, month, year].
   extras = pmt.pmt_make_dict()
   extras = pmt.pmt_dict_add(extras, key, val)
   extras_str = pmt.pmt_serialize_str(extras)
-  self.sink = gr.file_meta_sink(gr.sizeof_gr_complex,
-                                "/tmp/metadat_file.out",
-				 samp_rate, 1,
-				 gr.GR_FILE_FLOAT, True,
-				 1000000, extra_str, False)
+  self.sink = blocks.file_meta_sink(gr.sizeof_gr_complex,
+                                    "/tmp/metadat_file.out",
+				    samp_rate, 1,
+				    blocks.GR_FILE_FLOAT, True,
+				    1000000, extra_str, False)
 
 \endcode
 
diff --git a/gnuradio-core/src/examples/CMakeLists.txt b/gnuradio-core/src/examples/CMakeLists.txt
index 36333425cf..01d9eb83e0 100644
--- a/gnuradio-core/src/examples/CMakeLists.txt
+++ b/gnuradio-core/src/examples/CMakeLists.txt
@@ -17,7 +17,6 @@
 # the Free Software Foundation, Inc., 51 Franklin Street,
 # Boston, MA 02110-1301, USA.
 
-add_subdirectory(metadata)
 add_subdirectory(mp-sched)
 add_subdirectory(msg_passing)
 add_subdirectory(network)
diff --git a/gnuradio-core/src/examples/metadata/CMakeLists.txt b/gnuradio-core/src/examples/metadata/CMakeLists.txt
deleted file mode 100644
index 182d9c5438..0000000000
--- a/gnuradio-core/src/examples/metadata/CMakeLists.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2012 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 3, 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., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-
-include(GrPython)
-
-install(
-  FILES
-  file_metadata_sink.grc
-  file_metadata_source.grc
-  DESTINATION ${GR_PKG_DATA_DIR}/examples/metadata
-  COMPONENT "core_python"
-)
diff --git a/gnuradio-core/src/examples/metadata/file_metadata_sink.grc b/gnuradio-core/src/examples/metadata/file_metadata_sink.grc
deleted file mode 100644
index 197ff55729..0000000000
--- a/gnuradio-core/src/examples/metadata/file_metadata_sink.grc
+++ /dev/null
@@ -1,951 +0,0 @@
-<?xml version='1.0' encoding='ASCII'?>
-<flow_graph>
-  <timestamp>Thu Dec 13 14:25:16 2012</timestamp>
-  <block>
-    <key>gr_sig_source_x</key>
-    <param>
-      <key>id</key>
-      <value>gr_sig_source_x_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>False</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>samp_rate</key>
-      <value>samp_rate</value>
-    </param>
-    <param>
-      <key>waveform</key>
-      <value>gr.GR_COS_WAVE</value>
-    </param>
-    <param>
-      <key>freq</key>
-      <value>1000</value>
-    </param>
-    <param>
-      <key>amp</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>offset</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(57, 140)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>variable_qtgui_range</key>
-    <param>
-      <key>id</key>
-      <value>qt_samp_rate</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>label</key>
-      <value></value>
-    </param>
-    <param>
-      <key>value</key>
-      <value>samp_rate</value>
-    </param>
-    <param>
-      <key>start</key>
-      <value>200000</value>
-    </param>
-    <param>
-      <key>stop</key>
-      <value>5000000</value>
-    </param>
-    <param>
-      <key>step</key>
-      <value>200000</value>
-    </param>
-    <param>
-      <key>widget</key>
-      <value>counter_slider</value>
-    </param>
-    <param>
-      <key>orient</key>
-      <value>Qt.Horizontal</value>
-    </param>
-    <param>
-      <key>min_len</key>
-      <value>200</value>
-    </param>
-    <param>
-      <key>gui_hint</key>
-      <value></value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(330, 259)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>gr_head</key>
-    <param>
-      <key>id</key>
-      <value>gr_head_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>num_items</key>
-      <value>20000000</value>
-    </param>
-    <param>
-      <key>vlen</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(309, 172)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>variable</key>
-    <param>
-      <key>id</key>
-      <value>samp_rate</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>value</key>
-      <value>200000</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(208, 11)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>uhd_usrp_source</key>
-    <param>
-      <key>id</key>
-      <value>uhd_usrp_source_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>fc32</value>
-    </param>
-    <param>
-      <key>otw</key>
-      <value></value>
-    </param>
-    <param>
-      <key>stream_args</key>
-      <value></value>
-    </param>
-    <param>
-      <key>dev_addr</key>
-      <value>addr=192.168.11.2</value>
-    </param>
-    <param>
-      <key>sync</key>
-      <value></value>
-    </param>
-    <param>
-      <key>clock_rate</key>
-      <value>0.0</value>
-    </param>
-    <param>
-      <key>num_mboards</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>clock_source0</key>
-      <value></value>
-    </param>
-    <param>
-      <key>time_source0</key>
-      <value></value>
-    </param>
-    <param>
-      <key>sd_spec0</key>
-      <value></value>
-    </param>
-    <param>
-      <key>clock_source1</key>
-      <value></value>
-    </param>
-    <param>
-      <key>time_source1</key>
-      <value></value>
-    </param>
-    <param>
-      <key>sd_spec1</key>
-      <value></value>
-    </param>
-    <param>
-      <key>clock_source2</key>
-      <value></value>
-    </param>
-    <param>
-      <key>time_source2</key>
-      <value></value>
-    </param>
-    <param>
-      <key>sd_spec2</key>
-      <value></value>
-    </param>
-    <param>
-      <key>clock_source3</key>
-      <value></value>
-    </param>
-    <param>
-      <key>time_source3</key>
-      <value></value>
-    </param>
-    <param>
-      <key>sd_spec3</key>
-      <value></value>
-    </param>
-    <param>
-      <key>clock_source4</key>
-      <value></value>
-    </param>
-    <param>
-      <key>time_source4</key>
-      <value></value>
-    </param>
-    <param>
-      <key>sd_spec4</key>
-      <value></value>
-    </param>
-    <param>
-      <key>clock_source5</key>
-      <value></value>
-    </param>
-    <param>
-      <key>time_source5</key>
-      <value></value>
-    </param>
-    <param>
-      <key>sd_spec5</key>
-      <value></value>
-    </param>
-    <param>
-      <key>clock_source6</key>
-      <value></value>
-    </param>
-    <param>
-      <key>time_source6</key>
-      <value></value>
-    </param>
-    <param>
-      <key>sd_spec6</key>
-      <value></value>
-    </param>
-    <param>
-      <key>clock_source7</key>
-      <value></value>
-    </param>
-    <param>
-      <key>time_source7</key>
-      <value></value>
-    </param>
-    <param>
-      <key>sd_spec7</key>
-      <value></value>
-    </param>
-    <param>
-      <key>nchan</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>samp_rate</key>
-      <value>qt_samp_rate</value>
-    </param>
-    <param>
-      <key>center_freq0</key>
-      <value>98.9e6</value>
-    </param>
-    <param>
-      <key>gain0</key>
-      <value>30</value>
-    </param>
-    <param>
-      <key>ant0</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw0</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq1</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain1</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant1</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw1</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq2</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain2</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant2</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw2</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq3</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain3</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant3</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw3</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq4</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain4</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant4</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw4</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq5</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain5</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant5</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw5</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq6</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain6</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant6</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw6</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq7</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain7</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant7</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw7</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq8</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain8</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant8</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw8</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq9</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain9</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant9</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw9</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq10</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain10</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant10</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw10</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq11</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain11</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant11</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw11</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq12</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain12</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant12</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw12</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq13</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain13</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant13</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw13</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq14</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain14</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant14</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw14</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq15</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain15</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant15</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw15</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq16</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain16</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant16</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw16</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq17</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain17</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant17</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw17</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq18</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain18</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant18</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw18</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq19</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain19</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant19</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw19</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq20</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain20</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant20</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw20</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq21</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain21</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant21</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw21</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq22</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain22</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant22</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw22</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq23</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain23</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant23</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw23</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq24</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain24</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant24</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw24</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq25</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain25</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant25</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw25</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq26</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain26</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant26</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw26</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq27</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain27</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant27</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw27</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq28</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain28</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant28</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw28</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq29</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain29</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant29</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw29</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq30</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain30</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant30</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw30</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>center_freq31</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>gain31</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>ant31</key>
-      <value></value>
-    </param>
-    <param>
-      <key>bw31</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(53, 269)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>gr_file_meta_sink</key>
-    <param>
-      <key>id</key>
-      <value>gr_file_meta_sink_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>file</key>
-      <value>/tmp/metadat_file.out</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>samp_rate</key>
-      <value>samp_rate</value>
-    </param>
-    <param>
-      <key>rel_rate</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>vlen</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>max_seg_size</key>
-      <value>1000000</value>
-    </param>
-    <param>
-      <key>extra_dict</key>
-      <value>""</value>
-    </param>
-    <param>
-      <key>detached</key>
-      <value>False</value>
-    </param>
-    <param>
-      <key>unbuffered</key>
-      <value>False</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(555, 148)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>options</key>
-    <param>
-      <key>id</key>
-      <value>file_metadata_sink</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>title</key>
-      <value></value>
-    </param>
-    <param>
-      <key>author</key>
-      <value></value>
-    </param>
-    <param>
-      <key>description</key>
-      <value></value>
-    </param>
-    <param>
-      <key>window_size</key>
-      <value>1280, 1024</value>
-    </param>
-    <param>
-      <key>generate_options</key>
-      <value>qt_gui</value>
-    </param>
-    <param>
-      <key>category</key>
-      <value>Custom</value>
-    </param>
-    <param>
-      <key>run_options</key>
-      <value>prompt</value>
-    </param>
-    <param>
-      <key>run</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>max_nouts</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>realtime_scheduling</key>
-      <value></value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(10, 10)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <connection>
-    <source_block_id>gr_head_0</source_block_id>
-    <sink_block_id>gr_file_meta_sink_0</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-  <connection>
-    <source_block_id>gr_sig_source_x_0</source_block_id>
-    <sink_block_id>gr_head_0</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-  <connection>
-    <source_block_id>uhd_usrp_source_0</source_block_id>
-    <sink_block_id>gr_head_0</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-</flow_graph>
diff --git a/gnuradio-core/src/examples/metadata/file_metadata_source.grc b/gnuradio-core/src/examples/metadata/file_metadata_source.grc
deleted file mode 100644
index cc1383ae1d..0000000000
--- a/gnuradio-core/src/examples/metadata/file_metadata_source.grc
+++ /dev/null
@@ -1,346 +0,0 @@
-<?xml version='1.0' encoding='ASCII'?>
-<flow_graph>
-  <timestamp>Thu Dec 13 14:25:01 2012</timestamp>
-  <block>
-    <key>variable</key>
-    <param>
-      <key>id</key>
-      <value>samp_rate</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>value</key>
-      <value>200000</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(208, 11)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>gr_tag_debug</key>
-    <param>
-      <key>id</key>
-      <value>gr_tag_debug_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>name</key>
-      <value>Test</value>
-    </param>
-    <param>
-      <key>num_inputs</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>vlen</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>display</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(561, 290)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>gr_throttle</key>
-    <param>
-      <key>id</key>
-      <value>gr_throttle_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>samples_per_second</key>
-      <value>samp_rate</value>
-    </param>
-    <param>
-      <key>vlen</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(322, 223)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>gr_file_meta_source</key>
-    <param>
-      <key>id</key>
-      <value>gr_file_meta_source_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>file</key>
-      <value>/tmp/metadat_file.out</value>
-    </param>
-    <param>
-      <key>repeat</key>
-      <value>False</value>
-    </param>
-    <param>
-      <key>detached</key>
-      <value>False</value>
-    </param>
-    <param>
-      <key>hdr_file</key>
-      <value></value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(56, 199)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>analog_agc2_xx</key>
-    <param>
-      <key>id</key>
-      <value>analog_agc2_xx_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>attack_rate</key>
-      <value>1e-1</value>
-    </param>
-    <param>
-      <key>decay_rate</key>
-      <value>1e-2</value>
-    </param>
-    <param>
-      <key>reference</key>
-      <value>1.0</value>
-    </param>
-    <param>
-      <key>gain</key>
-      <value>1.0</value>
-    </param>
-    <param>
-      <key>max_gain</key>
-      <value>0.0</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(561, 82)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>qtgui_time_sink_x</key>
-    <param>
-      <key>id</key>
-      <value>qtgui_time_sink_x_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>name</key>
-      <value>QT GUI Plot</value>
-    </param>
-    <param>
-      <key>size</key>
-      <value>1024</value>
-    </param>
-    <param>
-      <key>bw</key>
-      <value>samp_rate</value>
-    </param>
-    <param>
-      <key>nconnections</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>gui_hint</key>
-      <value></value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(776, 98)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>gr_file_sink</key>
-    <param>
-      <key>id</key>
-      <value>gr_file_sink_1</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>file</key>
-      <value>/tmp/received_data.out</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>vlen</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>unbuffered</key>
-      <value>False</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(564, 215)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>options</key>
-    <param>
-      <key>id</key>
-      <value>file_metadata_source</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>title</key>
-      <value></value>
-    </param>
-    <param>
-      <key>author</key>
-      <value></value>
-    </param>
-    <param>
-      <key>description</key>
-      <value></value>
-    </param>
-    <param>
-      <key>window_size</key>
-      <value>1280, 1024</value>
-    </param>
-    <param>
-      <key>generate_options</key>
-      <value>qt_gui</value>
-    </param>
-    <param>
-      <key>category</key>
-      <value>Custom</value>
-    </param>
-    <param>
-      <key>run_options</key>
-      <value>prompt</value>
-    </param>
-    <param>
-      <key>run</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>max_nouts</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>realtime_scheduling</key>
-      <value></value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(10, 10)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <connection>
-    <source_block_id>gr_throttle_0</source_block_id>
-    <sink_block_id>gr_file_sink_1</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-  <connection>
-    <source_block_id>gr_throttle_0</source_block_id>
-    <sink_block_id>gr_tag_debug_0</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-  <connection>
-    <source_block_id>gr_file_meta_source_0</source_block_id>
-    <sink_block_id>gr_throttle_0</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-  <connection>
-    <source_block_id>gr_throttle_0</source_block_id>
-    <sink_block_id>analog_agc2_xx_0</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-  <connection>
-    <source_block_id>analog_agc2_xx_0</source_block_id>
-    <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-</flow_graph>
diff --git a/gnuradio-core/src/examples/metadata/file_metadata_vector_sink.grc b/gnuradio-core/src/examples/metadata/file_metadata_vector_sink.grc
deleted file mode 100644
index d67af3a660..0000000000
--- a/gnuradio-core/src/examples/metadata/file_metadata_vector_sink.grc
+++ /dev/null
@@ -1,219 +0,0 @@
-<?xml version='1.0' encoding='ASCII'?>
-<flow_graph>
-  <timestamp>Fri Dec 14 13:52:31 2012</timestamp>
-  <block>
-    <key>variable</key>
-    <param>
-      <key>id</key>
-      <value>samp_rate</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>value</key>
-      <value>200000</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(208, 11)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>gr_vector_source_x</key>
-    <param>
-      <key>id</key>
-      <value>gr_vector_source_x_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>vector</key>
-      <value>10*[0,1,2,3,4,5,6,7,8,9]</value>
-    </param>
-    <param>
-      <key>repeat</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>vlen</key>
-      <value>10</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(67, 100)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>gr_file_meta_sink</key>
-    <param>
-      <key>id</key>
-      <value>gr_file_meta_sink_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>file</key>
-      <value>/tmp/metadat_file.out</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>samp_rate</key>
-      <value>samp_rate</value>
-    </param>
-    <param>
-      <key>rel_rate</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>vlen</key>
-      <value>10</value>
-    </param>
-    <param>
-      <key>max_seg_size</key>
-      <value>1000000</value>
-    </param>
-    <param>
-      <key>extra_dict</key>
-      <value></value>
-    </param>
-    <param>
-      <key>detached</key>
-      <value>False</value>
-    </param>
-    <param>
-      <key>unbuffered</key>
-      <value>False</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(559, 60)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>options</key>
-    <param>
-      <key>id</key>
-      <value>file_metadata_vector_sink</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>title</key>
-      <value></value>
-    </param>
-    <param>
-      <key>author</key>
-      <value></value>
-    </param>
-    <param>
-      <key>description</key>
-      <value></value>
-    </param>
-    <param>
-      <key>window_size</key>
-      <value>1280, 1024</value>
-    </param>
-    <param>
-      <key>generate_options</key>
-      <value>no_gui</value>
-    </param>
-    <param>
-      <key>category</key>
-      <value>Custom</value>
-    </param>
-    <param>
-      <key>run_options</key>
-      <value>run</value>
-    </param>
-    <param>
-      <key>run</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>max_nouts</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>realtime_scheduling</key>
-      <value></value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(10, 10)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>gr_head</key>
-    <param>
-      <key>id</key>
-      <value>gr_head_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>num_items</key>
-      <value>10010000</value>
-    </param>
-    <param>
-      <key>vlen</key>
-      <value>10</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(325, 108)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <connection>
-    <source_block_id>gr_vector_source_x_0</source_block_id>
-    <sink_block_id>gr_head_0</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-  <connection>
-    <source_block_id>gr_head_0</source_block_id>
-    <sink_block_id>gr_file_meta_sink_0</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-</flow_graph>
diff --git a/gnuradio-core/src/examples/metadata/file_metadata_vector_source.grc b/gnuradio-core/src/examples/metadata/file_metadata_vector_source.grc
deleted file mode 100644
index 0662865f1d..0000000000
--- a/gnuradio-core/src/examples/metadata/file_metadata_vector_source.grc
+++ /dev/null
@@ -1,338 +0,0 @@
-<?xml version='1.0' encoding='ASCII'?>
-<flow_graph>
-  <timestamp>Fri Dec 14 13:55:43 2012</timestamp>
-  <block>
-    <key>options</key>
-    <param>
-      <key>id</key>
-      <value>file_metadata_source</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>title</key>
-      <value></value>
-    </param>
-    <param>
-      <key>author</key>
-      <value></value>
-    </param>
-    <param>
-      <key>description</key>
-      <value></value>
-    </param>
-    <param>
-      <key>window_size</key>
-      <value>1280, 1024</value>
-    </param>
-    <param>
-      <key>generate_options</key>
-      <value>qt_gui</value>
-    </param>
-    <param>
-      <key>category</key>
-      <value>Custom</value>
-    </param>
-    <param>
-      <key>run_options</key>
-      <value>prompt</value>
-    </param>
-    <param>
-      <key>run</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>max_nouts</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>realtime_scheduling</key>
-      <value></value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(10, 10)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>variable</key>
-    <param>
-      <key>id</key>
-      <value>samp_rate</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>value</key>
-      <value>200000</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(208, 11)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>gr_file_sink</key>
-    <param>
-      <key>id</key>
-      <value>gr_file_sink_1</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>file</key>
-      <value>/tmp/received_data.out</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>vlen</key>
-      <value>10</value>
-    </param>
-    <param>
-      <key>unbuffered</key>
-      <value>False</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(564, 215)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>gr_tag_debug</key>
-    <param>
-      <key>id</key>
-      <value>gr_tag_debug_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>name</key>
-      <value>Test</value>
-    </param>
-    <param>
-      <key>num_inputs</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>vlen</key>
-      <value>10</value>
-    </param>
-    <param>
-      <key>display</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(563, 298)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>gr_file_meta_source</key>
-    <param>
-      <key>id</key>
-      <value>gr_file_meta_source_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>file</key>
-      <value>/tmp/metadat_file.out</value>
-    </param>
-    <param>
-      <key>repeat</key>
-      <value>False</value>
-    </param>
-    <param>
-      <key>detached</key>
-      <value>False</value>
-    </param>
-    <param>
-      <key>hdr_file</key>
-      <value>/tmp/metadat_file.out.hdr</value>
-    </param>
-    <param>
-      <key>vlen</key>
-      <value>10</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(51, 199)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>qtgui_time_sink_x</key>
-    <param>
-      <key>id</key>
-      <value>qtgui_time_sink_x_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>name</key>
-      <value>QT GUI Plot</value>
-    </param>
-    <param>
-      <key>size</key>
-      <value>1024</value>
-    </param>
-    <param>
-      <key>bw</key>
-      <value>samp_rate</value>
-    </param>
-    <param>
-      <key>nconnections</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>gui_hint</key>
-      <value></value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(746, 116)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>gr_throttle</key>
-    <param>
-      <key>id</key>
-      <value>gr_throttle_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>samples_per_second</key>
-      <value>samp_rate</value>
-    </param>
-    <param>
-      <key>vlen</key>
-      <value>10</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(322, 223)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <block>
-    <key>blocks_vector_to_stream</key>
-    <param>
-      <key>id</key>
-      <value>blocks_vector_to_stream_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>num_items</key>
-      <value>10</value>
-    </param>
-    <param>
-      <key>vlen</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(526, 132)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
-    </param>
-  </block>
-  <connection>
-    <source_block_id>gr_throttle_0</source_block_id>
-    <sink_block_id>gr_file_sink_1</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-  <connection>
-    <source_block_id>gr_throttle_0</source_block_id>
-    <sink_block_id>gr_tag_debug_0</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-  <connection>
-    <source_block_id>gr_file_meta_source_0</source_block_id>
-    <sink_block_id>gr_throttle_0</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-  <connection>
-    <source_block_id>blocks_vector_to_stream_0</source_block_id>
-    <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-  <connection>
-    <source_block_id>gr_throttle_0</source_block_id>
-    <sink_block_id>blocks_vector_to_stream_0</sink_block_id>
-    <source_key>0</source_key>
-    <sink_key>0</sink_key>
-  </connection>
-</flow_graph>
diff --git a/gnuradio-core/src/lib/io/CMakeLists.txt b/gnuradio-core/src/lib/io/CMakeLists.txt
index 1cbcd2daf7..59ca06b5a2 100644
--- a/gnuradio-core/src/lib/io/CMakeLists.txt
+++ b/gnuradio-core/src/lib/io/CMakeLists.txt
@@ -85,10 +85,8 @@ endif(ENABLE_PYTHON)
 ########################################################################
 set(gr_core_io_triple_threats
     gr_file_sink
-    gr_file_meta_sink
     gr_file_sink_base
     gr_file_source
-    gr_file_meta_source
     gr_file_descriptor_sink
     gr_file_descriptor_source
     gr_message_debug
diff --git a/gnuradio-core/src/lib/io/gr_file_meta_sink.cc b/gnuradio-core/src/lib/io/gr_file_meta_sink.cc
deleted file mode 100644
index ab0acbdb44..0000000000
--- a/gnuradio-core/src/lib/io/gr_file_meta_sink.cc
+++ /dev/null
@@ -1,457 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2012 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 3, 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., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gr_file_meta_sink.h>
-#include <gr_io_signature.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <gruel/thread.h>
-#include <stdexcept>
-
-// win32 (mingw/msvc) specific
-#ifdef HAVE_IO_H
-#include <io.h>
-#endif
-#ifdef O_BINARY
-#define	OUR_O_BINARY O_BINARY
-#else
-#define	OUR_O_BINARY 0
-#endif
-
-// should be handled via configure
-#ifdef O_LARGEFILE
-#define	OUR_O_LARGEFILE	O_LARGEFILE
-#else
-#define	OUR_O_LARGEFILE 0
-#endif
-
-gr_file_meta_sink_sptr
-gr_make_file_meta_sink(size_t itemsize, const std::string &filename,
-		       double samp_rate, double relative_rate,
-		       gr_file_types type, bool complex,
-		       size_t max_segment_size,
-		       const std::string &extra_dict,
-		       bool detached_header)
-{
-  return gnuradio::get_initial_sptr
-    (new gr_file_meta_sink(itemsize, filename,
-			   samp_rate, relative_rate,
-			   type, complex,
-			   max_segment_size,
-			   extra_dict,
-			   detached_header));
-}
-
-gr_file_meta_sink::gr_file_meta_sink(size_t itemsize, const std::string &filename,
-				     double samp_rate, double relative_rate,
-				     gr_file_types type, bool complex,
-				     size_t max_segment_size,
-				     const std::string &extra_dict,
-				     bool detached_header)
-  : gr_sync_block("file_meta_sink",
-		  gr_make_io_signature(1, 1, itemsize),
-		  gr_make_io_signature(0, 0, 0)),
-    d_itemsize(itemsize),
-    d_samp_rate(samp_rate), d_relative_rate(relative_rate),
-    d_max_seg_size(max_segment_size), d_total_seg_size(0),
-    d_updated(false), d_unbuffered(false)
-{
-  d_fp = 0;
-  d_new_fp = 0;
-  d_hdr_fp = 0;
-  d_new_hdr_fp = 0;
-
-  if(detached_header == true)
-    d_state = STATE_DETACHED;
-  else
-    d_state = STATE_INLINE;
-
-  if(!open(filename))
-    throw std::runtime_error("file_meta_sink: can't open file\n");
-
-  pmt_t timestamp = pmt_make_tuple(pmt_from_uint64(0),
-				   pmt_from_double(0));
-
-  // handle extra dictionary
-  d_extra = pmt_make_dict();
-  if(extra_dict.size() > 0) {
-    pmt_t extras = pmt_deserialize_str(extra_dict);
-    pmt_t keys = pmt_dict_keys(extras);
-    pmt_t vals = pmt_dict_values(extras);
-    size_t nitems = pmt_length(keys);
-    for(size_t i = 0; i < nitems; i++) {
-      d_extra = pmt_dict_add(d_extra,
-			     pmt_nth(i, keys),
-			     pmt_nth(i, vals));
-    }
-  }
-
-  d_extra_size = pmt_serialize_str(d_extra).size();
-
-  d_header = pmt_make_dict();
-  d_header = pmt_dict_add(d_header, mp("version"), mp(METADATA_VERSION));
-  d_header = pmt_dict_add(d_header, mp("rx_rate"), mp(samp_rate));
-  d_header = pmt_dict_add(d_header, mp("rx_time"), timestamp);
-  d_header = pmt_dict_add(d_header, mp("size"), pmt_from_long(d_itemsize));
-  d_header = pmt_dict_add(d_header, mp("type"), pmt_from_long(type));
-  d_header = pmt_dict_add(d_header, mp("cplx"), complex ? PMT_T : PMT_F);
-  d_header = pmt_dict_add(d_header, mp("strt"), pmt_from_uint64(METADATA_HEADER_SIZE+d_extra_size));
-  d_header = pmt_dict_add(d_header, mp("bytes"), pmt_from_uint64(0));
-
-  do_update();
-
-  if(d_state == STATE_DETACHED)
-    write_header(d_hdr_fp, d_header, d_extra);
-  else
-    write_header(d_fp, d_header, d_extra);
-}
-
-gr_file_meta_sink::~gr_file_meta_sink()
-{
-  close();
-
-  if(d_fp) {
-    fclose(d_fp);
-    d_fp = 0;
-  }
-  
-  if(d_state == STATE_DETACHED) {
-    if(d_hdr_fp) {
-      fclose(d_hdr_fp);
-      d_hdr_fp = 0;
-    }
-  }
-}
-
-bool
-gr_file_meta_sink::open(const std::string &filename)
-{
-  bool ret = true;
-  if(d_state == STATE_DETACHED) {
-    std::string s = filename + ".hdr";
-    ret = _open(&d_new_hdr_fp, s.c_str());
-  }
-
-  ret = ret && _open(&d_new_fp, filename.c_str());
-  d_updated = true;
-  return ret;
-}
-
-bool
-gr_file_meta_sink::_open(FILE **fp, const char *filename)
-{
-  gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
-
-  bool ret = true;
-  int fd;
-
-  if((fd = ::open(filename,
-		  O_WRONLY|O_CREAT|O_TRUNC|OUR_O_LARGEFILE|OUR_O_BINARY,
-		  0664)) < 0){
-    perror(filename);
-    return false;
-  }
-
-  if(*fp) {		// if we've already got a new one open, close it
-    fclose(*fp);
-    fp = 0;
-  }
-
-  if((*fp = fdopen(fd, "wb")) == NULL) {
-    perror(filename);
-    ::close(fd);		// don't leak file descriptor if fdopen fails.
-  }
-
-  ret = fp != 0;
-
-  return ret;
-}
-
-void
-gr_file_meta_sink::close()
-{
-  gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
-  update_last_header();
-
-  if(d_state == STATE_DETACHED) {
-    if(d_new_hdr_fp) {
-      fclose(d_new_hdr_fp);
-      d_new_hdr_fp = 0;
-    }
-  }
-
-  if(d_new_fp) {
-    fclose(d_new_fp);
-    d_new_fp = 0;
-  }
-  d_updated = true;
-}
-
-void
-gr_file_meta_sink::do_update()
-{
-  if(d_updated) {
-    gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this block
-    if(d_state == STATE_DETACHED) {
-      if(d_hdr_fp)
-	fclose(d_hdr_fp);
-      d_hdr_fp = d_new_hdr_fp;		// install new file pointer
-      d_new_hdr_fp = 0;
-    }
-
-    if(d_fp)
-      fclose(d_fp);
-    d_fp = d_new_fp;		// install new file pointer
-    d_new_fp = 0;
-
-    d_updated = false;
-  }
-}
-
-void
-gr_file_meta_sink::write_header(FILE *fp, pmt_t header, pmt_t extra)
-{
-  std::string header_str = pmt_serialize_str(header);
-  std::string extra_str = pmt_serialize_str(extra);
-
-  if((header_str.size() != METADATA_HEADER_SIZE) && (extra_str.size() != d_extra_size))
-      throw std::runtime_error("file_meta_sink: header or extras is wrong size.\n");
-
-  size_t nwritten = 0;
-  while(nwritten < header_str.size()) {
-    std::string sub = header_str.substr(nwritten);
-    int count = fwrite(sub.c_str(), sizeof(char), sub.size(), fp);
-    nwritten += count;
-    if((count == 0) && (ferror(fp))) {
-      fclose(fp);
-      throw std::runtime_error("file_meta_sink: error writing header to file.\n");
-    }
-  }
-
-  nwritten = 0;
-  while(nwritten < extra_str.size()) {
-    std::string sub = extra_str.substr(nwritten);
-    int count = fwrite(sub.c_str(), sizeof(char), sub.size(), fp);
-    nwritten += count;
-    if((count == 0) && (ferror(fp))) {
-      fclose(fp);
-      throw std::runtime_error("file_meta_sink: error writing extra to file.\n");
-    }
-  }
-
-  fflush(fp);
-}
-
-void
-gr_file_meta_sink::update_header(pmt_t key, pmt_t value)
-{
-  // Special handling caveat to transform rate from radio source into
-  // the rate at this sink.
-  if(pmt_eq(key, mp("rx_rate"))) {
-    d_samp_rate = pmt_to_double(value);
-    value = pmt_from_double(d_samp_rate*d_relative_rate);
-  }
-
-  // If the tag is not part of the standard header, we put it into the
-  // extra data, which either updates the current dictionary or adds a
-  // new item.
-  if(pmt_dict_has_key(d_header, key)) {
-    d_header = pmt_dict_add(d_header, key, value);
-  }
-  else {
-    d_extra = pmt_dict_add(d_extra, key, value);
-    d_extra_size = pmt_serialize_str(d_extra).size();
-  }
-}
-
-void
-gr_file_meta_sink::update_last_header()
-{
-  if(d_state == STATE_DETACHED)
-    update_last_header_detached();
-  else
-    update_last_header_inline();
-}
-
-void
-gr_file_meta_sink::update_last_header_inline()
-{
-  // Update the last header info with the number of samples this
-  // block represents.
-
-  size_t hdrlen = pmt_to_uint64(pmt_dict_ref(d_header, mp("strt"), PMT_NIL));
-  size_t seg_size = d_itemsize*d_total_seg_size;
-  pmt_t s = pmt_from_uint64(seg_size);
-  update_header(mp("bytes"), s);
-  update_header(mp("strt"), pmt_from_uint64(METADATA_HEADER_SIZE+d_extra_size));
-  fseek(d_fp, -seg_size-hdrlen, SEEK_CUR);
-  write_header(d_fp, d_header, d_extra);
-  fseek(d_fp, seg_size, SEEK_CUR);
-}
-
-void
-gr_file_meta_sink::update_last_header_detached()
-{
-  // Update the last header info with the number of samples this
-  // block represents.
-  size_t hdrlen = pmt_to_uint64(pmt_dict_ref(d_header, mp("strt"), PMT_NIL));
-  size_t seg_size = d_itemsize*d_total_seg_size;
-  pmt_t s = pmt_from_uint64(seg_size);
-  update_header(mp("bytes"), s);
-  update_header(mp("strt"), pmt_from_uint64(METADATA_HEADER_SIZE+d_extra_size));
-  fseek(d_hdr_fp, -hdrlen, SEEK_CUR);
-  write_header(d_hdr_fp, d_header, d_extra);
-}
-
-void
-gr_file_meta_sink::write_and_update()
-{
-  // New header, so set current size of chunk to 0 and start of chunk
-  // based on current index + header size.
-  //uint64_t loc = get_last_header_loc();
-  pmt_t s = pmt_from_uint64(0);
-  update_header(mp("bytes"), s);
-
-  // If we have multiple tags on the same offset, this makes
-  // sure we just overwrite the same header each time instead
-  // of creating a new header per tag.
-  s = pmt_from_uint64(METADATA_HEADER_SIZE + d_extra_size);
-  update_header(mp("strt"), s);
-
-  if(d_state == STATE_DETACHED)
-    write_header(d_hdr_fp, d_header, d_extra);
-  else
-    write_header(d_fp, d_header, d_extra);
-}
-
-void
-gr_file_meta_sink::update_rx_time()
-{
-  pmt_t rx_time = pmt_string_to_symbol("rx_time");
-  pmt_t r = pmt_dict_ref(d_header, rx_time, PMT_NIL);
-  uint64_t secs = pmt_to_uint64(pmt_tuple_ref(r, 0));
-  double fracs = pmt_to_double(pmt_tuple_ref(r, 1));
-  double diff = d_total_seg_size / (d_samp_rate*d_relative_rate);
-
-  //std::cerr << "old secs:  " << secs << std::endl;
-  //std::cerr << "old fracs: " << fracs << std::endl;
-  //std::cerr << "seg size:  " << d_total_seg_size << std::endl;
-  //std::cerr << "diff:      " << diff << std::endl;
-
-  fracs += diff;
-  uint64_t new_secs = static_cast<uint64_t>(fracs);
-  secs += new_secs;
-  fracs -= new_secs;
-
-  //std::cerr << "new secs:  " << secs << std::endl;
-  //std::cerr << "new fracs: " << fracs << std::endl << std::endl;
-
-  r = pmt_make_tuple(pmt_from_uint64(secs), pmt_from_double(fracs));
-  d_header = pmt_dict_add(d_header, rx_time, r);
-}	  
-
-int
-gr_file_meta_sink::work(int noutput_items,
-			gr_vector_const_void_star &input_items,
-			gr_vector_void_star &output_items)
-{
-  char *inbuf = (char*)input_items[0];
-  int  nwritten = 0;
-
-  do_update();				// update d_fp is reqd
-
-  if(!d_fp)
-    return noutput_items;		// drop output on the floor
-
-  uint64_t abs_N = nitems_read(0);
-  uint64_t end_N = abs_N + (uint64_t)(noutput_items);
-  std::vector<gr_tag_t> all_tags;
-  get_tags_in_range(all_tags, 0, abs_N, end_N);
-
-  std::vector<gr_tag_t>::iterator itr;
-  for(itr = all_tags.begin(); itr != all_tags.end(); itr++) {
-    int item_offset = (int)(itr->offset - abs_N);
-
-    // Write date to file up to the next tag location
-    while(nwritten < item_offset) {
-      size_t towrite = std::min(d_max_seg_size - d_total_seg_size,
-				(size_t)(item_offset - nwritten));
-      int count = fwrite(inbuf, d_itemsize, towrite, d_fp);
-      if(count == 0)	// FIXME add error handling
-	break;
-      nwritten += count;
-      inbuf += count * d_itemsize;
-
-      d_total_seg_size += count;
-
-      // Only add a new header if we are not at the position of the
-      // next tag
-      if((d_total_seg_size == d_max_seg_size) &&
-	 (nwritten < item_offset)) {
-	update_last_header();
-	update_rx_time();
-	write_and_update();
-	d_total_seg_size = 0;
-      }
-    }
-
-    if(d_total_seg_size > 0) {
-      update_last_header();
-      update_header(itr->key, itr->value);
-      write_and_update();
-      d_total_seg_size = 0;
-    }
-    else {
-      update_header(itr->key, itr->value);
-      update_last_header();
-    }
-  }
-
-  // Finish up the rest of the data after tags
-  while(nwritten < noutput_items) {
-    size_t towrite = std::min(d_max_seg_size - d_total_seg_size,
-			      (size_t)(noutput_items - nwritten));
-    int count = fwrite(inbuf, d_itemsize, towrite, d_fp);
-    if(count == 0)	// FIXME add error handling
-      break;
-    nwritten += count;
-    inbuf += count * d_itemsize;
-
-    d_total_seg_size += count;
-    if(d_total_seg_size == d_max_seg_size) {
-      update_last_header();
-      update_rx_time();
-      write_and_update();
-      d_total_seg_size = 0;
-    }
-  }
-
-  if(d_unbuffered)
-    fflush(d_fp);
-
-  return nwritten;
-}
diff --git a/gnuradio-core/src/lib/io/gr_file_meta_sink.h b/gnuradio-core/src/lib/io/gr_file_meta_sink.h
deleted file mode 100644
index 9b67cc4c8a..0000000000
--- a/gnuradio-core/src/lib/io/gr_file_meta_sink.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2012 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 3, 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., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef INCLUDED_GR_FILE_META_SINK_H
-#define INCLUDED_GR_FILE_META_SINK_H
-
-#include <gr_core_api.h>
-#include <gr_sync_block.h>
-#include <gruel/pmt.h>
-#include <cstdio>
-
-using namespace pmt;
-
-const char METADATA_VERSION = 0;
-const size_t METADATA_HEADER_SIZE = 149;
-
-enum gr_file_types {
-  GR_FILE_BYTE=0,
-  GR_FILE_CHAR=0,
-  GR_FILE_SHORT=1,
-  GR_FILE_INT,
-  GR_FILE_LONG,
-  GR_FILE_LONG_LONG,
-  GR_FILE_FLOAT,
-  GR_FILE_DOUBLE,
-};
-
-class gr_file_meta_sink;
-typedef boost::shared_ptr<gr_file_meta_sink> gr_file_meta_sink_sptr;
-
-GR_CORE_API gr_file_meta_sink_sptr
-gr_make_file_meta_sink(size_t itemsize, const std::string &filename,
-		       double samp_rate=1, double relative_rate=1,
-		       gr_file_types type=GR_FILE_FLOAT, bool complex=true,
-		       size_t max_segment_size=1000000,
-		       const std::string &extra_dict="",
-		       bool detached_header=false);
-
-/*!
- * \brief Write stream to file with meta-data headers.
- * \ingroup sink_blk
- *
- * These files represent data as binary information in between
- * meta-data headers. The headers contain information about the type
- * of data and properties of the data in the next segment of
- * samples. The information includes:
- *
- *   rx_rate (double): sample rate of data.
- *   rx_time (uint64_t, double): time stamp of first sample in segment.
- *   type (gr_file_types as int32_t): data type.
- *   cplx (bool): Is data complex?
- *   strt (uint64_t): Starting byte of data in this segment.
- *   size (uint64_t): Size in bytes of data in this segment.
- *
- * Tags can be sent to the file to update the information, which will
- * create a new header. Headers are found by searching from the first
- * header (at position 0 in the file) and reading where the data
- * segment starts plus the data segment size. Following will either be
- * a new header or EOF.
- */
-class GR_CORE_API gr_file_meta_sink : public gr_sync_block
-{
-  /*!
-   * \brief Create a meta-data file sink.
-   *
-   * \param itemsize (size_t): Size of data type.
-   * \param filename (string): Name of file to write data to.
-   * \param samp_rate (double): Sample rate of data. If sample rate will be
-   *    set by a tag, such as rx_tag from a UHD source, this is
-   *    basically ignored.
-   * \param relative_rate (double): Rate chance from source of sample
-   *    rate tag to sink.
-   * \param type (gr_file_types): Data type (int, float, etc.)
-   * \param complex (bool): If data stream is complex
-   * \param max_segment_size (size_t): Length of a single segment
-   *    before the header is repeated (in items).
-   * \param extra_dict (string): a serialized PMT dictionary of extra
-   *    information. Currently not supported.
-   * \param detached_header (bool): Set to true to store the header
-   *    info in a separate file (named filename.hdr)
-   */
-  friend GR_CORE_API gr_file_meta_sink_sptr
-    gr_make_file_meta_sink(size_t itemsize, const std::string &filename,
-			   double samp_rate, double relative_rate,
-			   gr_file_types type, bool complex,
-			   size_t max_segment_size,
-			   const std::string &extra_dict,
-			   bool detached_header);
-
- private:
-  enum meta_state_t {
-    STATE_INLINE=0,
-    STATE_DETACHED
-  };
-
-
-  size_t d_itemsize;
-  double d_samp_rate;
-  double d_relative_rate;
-  size_t d_max_seg_size;
-  size_t d_total_seg_size;
-  pmt_t d_header;
-  pmt_t d_extra;
-  size_t d_extra_size;
-  bool d_updated;
-  bool d_unbuffered;
-
-  boost::mutex d_mutex;
-  FILE *d_new_fp, *d_new_hdr_fp;
-  FILE *d_fp, *d_hdr_fp;
-  meta_state_t d_state;
-
- protected:
-  gr_file_meta_sink(size_t itemsize, const std::string &filename,
-		    double samp_rate=1, double relative_rate=1,
-		    gr_file_types type=GR_FILE_FLOAT, bool complex=true,
-		    size_t max_segment_size=1000000,
-		    const std::string &extra_dict="",
-		    bool detached_header=false);
-
-  void write_header(FILE *fp, pmt_t header, pmt_t extra);
-  void update_header(pmt_t key, pmt_t value);
-  void update_last_header();
-  void update_last_header_inline();
-  void update_last_header_detached();
-  void write_and_update();
-  void update_rx_time();
-
-  bool _open(FILE **fp, const char *filename);
-
- public:
-  ~gr_file_meta_sink();
-
-  bool open(const std::string &filename);
-  void close();
-  void do_update();
-
-  void set_unbuffered(bool unbuffered)
-  {
-    d_unbuffered = unbuffered;
-  }
-
-  //FIXME: add setters/getters for properties.
-
-  int work(int noutput_items,
-	   gr_vector_const_void_star &input_items,
-	   gr_vector_void_star &output_items);
-};
-
-#endif /* INCLUDED_GR_FILE_META_SINK_H */
diff --git a/gnuradio-core/src/lib/io/gr_file_meta_sink.i b/gnuradio-core/src/lib/io/gr_file_meta_sink.i
deleted file mode 100644
index 6fa34913be..0000000000
--- a/gnuradio-core/src/lib/io/gr_file_meta_sink.i
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2012 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 3, 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., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-GR_SWIG_BLOCK_MAGIC(gr,file_meta_sink)
-
-const char METADATA_VERSION = 0;
-const size_t METADATA_HEADER_SIZE = 149;
-
-enum gr_file_types {
-  GR_FILE_BYTE=0,
-  GR_FILE_CHAR=0,
-  GR_FILE_SHORT,
-  GR_FILE_INT,
-  GR_FILE_LONG,
-  GR_FILE_LONG_LONG,
-  GR_FILE_FLOAT,
-  GR_FILE_DOUBLE,
-};
-
-gr_file_meta_sink_sptr
-gr_make_file_meta_sink(size_t itemsize, const std::string &filename,
-		       double samp_rate=1, double relative_rate=1,
-		       gr_file_types type=GR_FILE_FLOAT, bool complex=true,
-		       size_t max_segment_size=1000000,
-		       const std::string & extra_dict="",
-		       bool detached_header=false);
-
-class gr_file_meta_sink : public gr_sync_block
-{
- protected:
-  gr_file_meta_sink(size_t itemsize, const std::string &filename,
-		    double samp_rate, double relative_rate,
-		    gr_file_types type, bool complex,
-		    size_t max_segment_size,
-		    const std::string & extra_dict,
-		    bool detached_header);
-
- public:
-  ~gr_file_meta_sink();
-
-  bool open(const std::string &filename);
-  void close();
-  void set_unbuffered(bool unbuffered);
-};
diff --git a/gnuradio-core/src/lib/io/gr_file_meta_source.cc b/gnuradio-core/src/lib/io/gr_file_meta_source.cc
deleted file mode 100644
index d940e5edcd..0000000000
--- a/gnuradio-core/src/lib/io/gr_file_meta_source.cc
+++ /dev/null
@@ -1,427 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2012 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 3, 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., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gr_file_meta_source.h>
-#include <gr_io_signature.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <gruel/thread.h>
-#include <stdexcept>
-
-// win32 (mingw/msvc) specific
-#ifdef HAVE_IO_H
-#include <io.h>
-#endif
-#ifdef O_BINARY
-#define	OUR_O_BINARY O_BINARY
-#else
-#define	OUR_O_BINARY 0
-#endif
-
-// should be handled via configure
-#ifdef O_LARGEFILE
-#define	OUR_O_LARGEFILE	O_LARGEFILE
-#else
-#define	OUR_O_LARGEFILE 0
-#endif
-
-gr_file_meta_source_sptr
-gr_make_file_meta_source(const std::string &filename,
-			 bool repeat,
-			 bool detached_header,
-			 const std::string &hdr_filename)
-{
-  return gnuradio::get_initial_sptr
-    (new gr_file_meta_source(filename,
-			     repeat,
-			     detached_header,
-			     hdr_filename));
-}
-
-gr_file_meta_source::gr_file_meta_source(const std::string &filename,
-					 bool repeat,
-					 bool detached_header,
-					 const std::string &hdr_filename)
-  : gr_sync_block("file_meta_source",
-		  gr_make_io_signature(0, 0, 0),
-		  gr_make_io_signature(1, 1, 1)),
-    d_itemsize(0), d_samp_rate(0),
-    d_seg_size(0),
-    d_updated(false), d_repeat(repeat)
-{
-  d_fp = 0;
-  d_new_fp = 0;
-  d_hdr_fp = 0;
-  d_new_hdr_fp = 0;
-
-  if(detached_header == true) {
-    d_state = STATE_DETACHED;
-  }
-  else
-    d_state = STATE_INLINE;
-
-  if(!open(filename, hdr_filename))
-    throw std::runtime_error("file_meta_source: can't open file\n");
-
-  do_update();
-
-  pmt_t hdr = PMT_NIL, extras = PMT_NIL;
-  if(read_header(hdr, extras)) {
-    parse_header(hdr, 0, d_tags);
-    parse_extras(extras, 0, d_tags);
-  }
-  else
-    throw std::runtime_error("file_meta_source: could not read header.\n");
-
-  // Set output signature based on itemsize info in header
-  set_output_signature(gr_make_io_signature(1, 1, d_itemsize));
-}
-
-gr_file_meta_source::~gr_file_meta_source()
-{
-  close();
-
-  if(d_fp) {
-    fclose(d_fp);
-    d_fp = 0;
-  }
-  
-  if(d_state == STATE_DETACHED) {
-    if(d_hdr_fp) {
-      fclose(d_hdr_fp);
-      d_hdr_fp = 0;
-    }
-  }
-}
-
-bool
-gr_file_meta_source::read_header(pmt_t &hdr, pmt_t &extras)
-{
-  // Select which file handle to read from.
-  FILE *fp;
-  if(d_state == STATE_DETACHED)
-    fp = d_hdr_fp;
-  else
-    fp = d_fp;
-
-  size_t ret;
-  size_t size = 0;
-  std::string str;
-  char *hdr_buffer = new char[METADATA_HEADER_SIZE];
-  while(size < METADATA_HEADER_SIZE) {
-    ret = fread(&hdr_buffer[size], sizeof(char), METADATA_HEADER_SIZE-size, fp);
-    if(ret == 0) {
-      delete [] hdr_buffer;
-      if(feof(fp))
-	return false;
-      else {
-	std::stringstream s;
-	s << "file_meta_source: error occurred extracting header: "
-	  << strerror(errno) << std::endl;
-	throw std::runtime_error(s.str());
-      }
-    }
-    size += ret;
-  }
-
-  // Convert to string or the char array gets confused by the \0
-  str.insert(0, hdr_buffer, METADATA_HEADER_SIZE);
-  hdr = pmt_deserialize_str(str);
-  delete [] hdr_buffer;
-
-  uint64_t seg_start, extra_len;
-  pmt_t r, dump;
-  if(pmt_dict_has_key(hdr, pmt_string_to_symbol("strt"))) {
-    r = pmt_dict_ref(hdr, pmt_string_to_symbol("strt"), dump);
-    seg_start = pmt_to_uint64(r);
-    extra_len = seg_start - METADATA_HEADER_SIZE;
-  }
-
-  if(extra_len > 0) {
-    size = 0;
-    hdr_buffer = new char[extra_len];
-    while(size < extra_len) {
-      ret = fread(&hdr_buffer[size], sizeof(char), extra_len-size, fp);
-      if(ret == 0) {
-	delete [] hdr_buffer;
-	if(feof(fp))
-	  return false;
-	else {
-	  std::stringstream s;
-	  s << "file_meta_source: error occurred extracting extras: "
-	    << strerror(errno) << std::endl;
-	  throw std::runtime_error(s.str());
-	}
-      }
-      size += ret;
-    }
-
-    str.clear();
-    str.insert(0, hdr_buffer, extra_len);
-    extras = pmt_deserialize_str(str);
-    delete [] hdr_buffer;
-  }
-
-  return true;
-}
-
-void
-gr_file_meta_source::parse_header(pmt_t hdr, uint64_t offset,
-				  std::vector<gr_tag_t> &tags)
-{
-  pmt_t r, key;
-
-  // GET SAMPLE RATE
-  key = pmt_string_to_symbol("rx_rate");
-  if(pmt_dict_has_key(hdr, key)) {
-    r = pmt_dict_ref(hdr, key, PMT_NIL);
-    d_samp_rate = pmt_to_double(r);
-
-    gr_tag_t t;
-    t.offset = offset;
-    t.key = key;
-    t.value = r;
-    t.srcid = alias_pmt();
-    tags.push_back(t);
-  }
-  else {
-    throw std::runtime_error("file_meta_source: Could not extract sample rate.\n");
-  }
-
-  // GET TIME STAMP
-  key = pmt_string_to_symbol("rx_time");
-  if(pmt_dict_has_key(hdr, key)) {
-    d_time_stamp = pmt_dict_ref(hdr, key, PMT_NIL);
-
-    gr_tag_t t;
-    t.offset = offset;
-    t.key = key;
-    t.value = d_time_stamp;
-    t.srcid = alias_pmt();
-    tags.push_back(t);
-  }
-  else {
-    throw std::runtime_error("file_meta_source: Could not extract time stamp.\n");
-  }
-
-  // GET ITEM SIZE OF DATA
-  if(pmt_dict_has_key(hdr, pmt_string_to_symbol("size"))) {
-    d_itemsize = pmt_to_long(pmt_dict_ref(hdr, pmt_string_to_symbol("size"), PMT_NIL));
-  }
-  else {
-    throw std::runtime_error("file_meta_source: Could not extract item size.\n");
-  }
-
-  // GET SEGMENT SIZE
-  if(pmt_dict_has_key(hdr, pmt_string_to_symbol("bytes"))) {
-    d_seg_size = pmt_to_uint64(pmt_dict_ref(hdr, pmt_string_to_symbol("bytes"), PMT_NIL));
-
-    // Convert from bytes to items
-    d_seg_size /= d_itemsize;
-  }
-  else {
-    throw std::runtime_error("file_meta_source: Could not extract segment size.\n");
-  }
-}
-
-void
-gr_file_meta_source::parse_extras(pmt_t extras, uint64_t offset,
-				  std::vector<gr_tag_t> &tags)
-{
-  pmt_t item, key, val;
-
-  size_t nitems = pmt_length(extras);
-  for(size_t i = 0; i < nitems; i++) {
-    item = pmt_nth(i, extras);
-    key = pmt_car(item);
-    val = pmt_cdr(item);
-
-    gr_tag_t t;
-    t.offset = offset;
-    t.key = key;
-    t.value = val;
-    t.srcid = alias_pmt();
-    tags.push_back(t);
-  }
-}
-
-bool
-gr_file_meta_source::open(const std::string &filename,
-			  const std::string &hdr_filename)
-{
-  bool ret = true;
-  if(d_state == STATE_DETACHED) {
-    std::string s;
-    if(hdr_filename == "")
-      s = filename + ".hdr";
-    else
-      s = hdr_filename;
-    ret = _open(&d_new_hdr_fp, s.c_str());
-  }
-
-  ret = ret && _open(&d_new_fp, filename.c_str());
-  d_updated = true;
-  return ret;
-}
-
-bool
-gr_file_meta_source::_open(FILE **fp, const char *filename)
-{
-  gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
-
-  bool ret = true;
-  int fd;
-
-  if((fd = ::open(filename,
-		  O_RDONLY|OUR_O_LARGEFILE|OUR_O_BINARY)) < 0) {
-    perror(filename);
-    return false;
-  }
-
-  if(*fp) {		// if we've already got a new one open, close it
-    fclose(*fp);
-    fp = 0;
-  }
-
-  if((*fp = fdopen(fd, "rb")) == NULL) {
-    perror(filename);
-    ::close(fd);		// don't leak file descriptor if fdopen fails.
-  }
-
-  ret = fp != 0;
-
-  return ret;
-}
-
-void
-gr_file_meta_source::close()
-{
-  gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
-  if(d_state == STATE_DETACHED) {
-    if(d_new_hdr_fp) {
-      fclose(d_new_hdr_fp);
-      d_new_hdr_fp = 0;
-    }
-  }
-
-  if(d_new_fp) {
-    fclose(d_new_fp);
-    d_new_fp = 0;
-  }
-  d_updated = true;
-}
-
-void
-gr_file_meta_source::do_update()
-{
-  if(d_updated) {
-    gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this block
-    if(d_state == STATE_DETACHED) {
-      if(d_hdr_fp)
-	fclose(d_hdr_fp);
-      d_hdr_fp = d_new_hdr_fp;		// install new file pointer
-      d_new_hdr_fp = 0;
-    }
-
-    if(d_fp)
-      fclose(d_fp);
-    d_fp = d_new_fp;		// install new file pointer
-    d_new_fp = 0;
-
-    d_updated = false;
-  }
-}
-
-int
-gr_file_meta_source::work(int noutput_items,
-			  gr_vector_const_void_star &input_items,
-			  gr_vector_void_star &output_items)
-{
-  // We've reached the end of a segment; parse the next header and get
-  // the new tags to send and set the next segment size.
-  if(d_seg_size == 0) {
-    pmt_t hdr=PMT_NIL, extras=PMT_NIL;
-    if(read_header(hdr, extras)) {
-      parse_header(hdr, nitems_written(0), d_tags);
-      parse_extras(extras, nitems_written(0), d_tags);
-    }
-    else {
-      return -1;
-    }
-  }
-
-  char *out = (char*)output_items[0];
-  int i;
-  int seg_size = std::min(noutput_items, (int)d_seg_size);
-  int size = seg_size;
-
-  do_update();       // update d_fp is reqd
-  if(d_fp == NULL)
-    throw std::runtime_error("work with file not open");
-
-  // Push all tags onto the stream and remove them from the vector
-  while(!d_tags.empty()) {
-    add_item_tag(0, d_tags.back());
-    d_tags.pop_back();
-  }
-
-  gruel::scoped_lock lock(d_mutex); // hold for the rest of this function
-  while(size) {
-    i = fread(out, d_itemsize, size, d_fp);
-
-    size -= i;
-    d_seg_size -= i;
-    out += i * d_itemsize;
-
-    if(size == 0)		// done
-      break;
-
-    if(i > 0)			// short read, try again
-      continue;
-
-    // We got a zero from fread.  This is either EOF or error.  In
-    // any event, if we're in repeat mode, seek back to the beginning
-    // of the file and try again, else break
-
-    if(!d_repeat)
-      break;
-
-    if(fseek(d_fp, 0, SEEK_SET) == -1) {
-      std::stringstream s;
-      s << "[" << __FILE__ << "]" << " fseek failed" << std::endl;
-      throw std::runtime_error(s.str());
-    }
-  }
-
-  if(size > 0) {			// EOF or error
-    if(size == seg_size)		// we didn't read anything; say we're done
-      return -1;
-    return seg_size - size;	// else return partial result
-  }
-
-  return seg_size;
-}
diff --git a/gnuradio-core/src/lib/io/gr_file_meta_source.h b/gnuradio-core/src/lib/io/gr_file_meta_source.h
deleted file mode 100644
index 95e466936a..0000000000
--- a/gnuradio-core/src/lib/io/gr_file_meta_source.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2012 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 3, 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., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef INCLUDED_GR_FILE_META_SOURCE_H
-#define INCLUDED_GR_FILE_META_SOURCE_H
-
-#include <gr_core_api.h>
-#include <gr_sync_block.h>
-#include <gr_tags.h>
-#include <gruel/pmt.h>
-#include <gruel/thread.h>
-#include <cstdio>
-
-#include <gr_file_meta_sink.h>
-
-class gr_file_meta_source;
-typedef boost::shared_ptr<gr_file_meta_source> gr_file_meta_source_sptr;
-
-GR_CORE_API gr_file_meta_source_sptr
-gr_make_file_meta_source(const std::string &filename,
-			 bool repeat=false,
-			 bool detached_header=false,
-			 const std::string &hdr_filename="");
-
-/*!
- * \brief Reads stream from file with meta-data headers. Headers are
- * parsed into tags.
- * \ingroup source_blk
- *
- * The information in the metadata headers includes:
- *
- *   rx_rate (double): sample rate of data.
- *   rx_time (uint64_t, double): time stamp of first sample in segment.
- *   type (gr_file_types as int32_t): data type.
- *   cplx (bool): Is data complex?
- *   strt (uint64_t): Starting byte of data in this segment.
- *   size (uint64_t): Size in bytes of data in this segment.
- *
- * Any item inside of the extra header dictionary is ready out and
- * made into a stream tag.
- */
-class GR_CORE_API gr_file_meta_source : public gr_sync_block
-{
-  /*!
-   * \brief Create a meta-data file source.
-   *
-   * \param filename (string): Name of file to write data to.
-   * \param repeat (bool): Repeats file when EOF is found.
-   * \param detached_header (bool): Set to true if header
-   *    info is stored in a separate file (usually named filename.hdr)
-   * \param hdr_filename (string): Name of detached header file if used.
-   *    Defaults to 'filename.hdr' if detached_header is true but this
-   *    field is an empty string.
-   */
-  friend GR_CORE_API gr_file_meta_source_sptr
-    gr_make_file_meta_source(const std::string &filename,
-			     bool repeat,
-			     bool detached_header,
-			     const std::string &hdr_filename);
-
- private:
-  enum meta_state_t {
-    STATE_INLINE=0,
-    STATE_DETACHED
-  };
-
-  size_t d_itemsize;
-  double d_samp_rate;
-  pmt_t d_time_stamp;
-  size_t d_seg_size;
-  bool d_updated;
-  bool d_repeat;
-
-  gruel::mutex d_mutex;
-  FILE *d_new_fp, *d_new_hdr_fp;
-  FILE *d_fp, *d_hdr_fp;
-  meta_state_t d_state;
-
-  std::vector<gr_tag_t> d_tags;
-
- protected:
-  gr_file_meta_source(const std::string &filename,
-		      bool repeat=false,
-		      bool detached_header=false,
-		      const std::string &hdr_filename="");
-
-  bool _open(FILE **fp, const char *filename);
-  bool read_header(pmt_t &hdr, pmt_t &extras);
-  void parse_header(pmt_t hdr, uint64_t offset,
-		    std::vector<gr_tag_t> &tags);
-  void parse_extras(pmt_t extras, uint64_t offset,
-		    std::vector<gr_tag_t> &tags);
-
- public:
-  ~gr_file_meta_source();
-
-  bool open(const std::string &filename,
-	    const std::string &hdr_filename="");
-  void close();
-  void do_update();
-
-  int work(int noutput_items,
-	   gr_vector_const_void_star &input_items,
-	   gr_vector_void_star &output_items);
-};
-
-#endif /* INCLUDED_GR_FILE_META_SOURCE_H */
diff --git a/gnuradio-core/src/lib/io/gr_file_meta_source.i b/gnuradio-core/src/lib/io/gr_file_meta_source.i
deleted file mode 100644
index cb1281036a..0000000000
--- a/gnuradio-core/src/lib/io/gr_file_meta_source.i
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2012 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 3, 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., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-GR_SWIG_BLOCK_MAGIC(gr,file_meta_source)
-
-gr_file_meta_source_sptr
-gr_make_file_meta_source(const std::string &filename,
-			 bool repeat=false,
-			 bool detached_header=false,
-			 const std::string &hdr_filename="");
-
-class gr_file_meta_source : public gr_sync_block
-{
- protected:
-  gr_file_meta_source(const std::string &filename,
-		      bool repeat,
-		      bool detached_header,
-		      const std::string &hdr_filename);
-
- public:
-  ~gr_file_meta_source();
-
-  bool open(const std::string &filename,
-	    const std::string &hdr_filename="");
-  void close();
-};
diff --git a/gnuradio-core/src/lib/io/io.i b/gnuradio-core/src/lib/io/io.i
index 5885214d8c..e2de4eb976 100644
--- a/gnuradio-core/src/lib/io/io.i
+++ b/gnuradio-core/src/lib/io/io.i
@@ -27,9 +27,7 @@
 #endif
 
 #include <gr_file_sink.h>
-#include <gr_file_meta_sink.h>
 #include <gr_file_source.h>
-#include <gr_file_meta_source.h>
 #include <gr_file_descriptor_sink.h>
 #include <gr_file_descriptor_source.h>
 #include <gr_histo_sink_f.h>
@@ -57,9 +55,7 @@
 
 %include "gr_file_sink_base.i"
 %include "gr_file_sink.i"
-%include "gr_file_meta_sink.i"
 %include "gr_file_source.i"
-%include "gr_file_meta_source.i"
 %include "gr_file_descriptor_sink.i"
 %include "gr_file_descriptor_source.i"
 %include "gr_histo_sink.i"
diff --git a/gnuradio-core/src/python/gnuradio/CMakeLists.txt b/gnuradio-core/src/python/gnuradio/CMakeLists.txt
index 31cde6921c..bf696e0d34 100644
--- a/gnuradio-core/src/python/gnuradio/CMakeLists.txt
+++ b/gnuradio-core/src/python/gnuradio/CMakeLists.txt
@@ -32,7 +32,6 @@ GR_PYTHON_INSTALL(FILES
     gr_unittest.py
     gr_xmlrunner.py
     optfir.py
-    parse_file_metadata.py
     window.py
     DESTINATION ${GR_PYTHON_DIR}/gnuradio
     COMPONENT "core_python"
diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_file_metadata.py b/gnuradio-core/src/python/gnuradio/gr/qa_file_metadata.py
deleted file mode 100644
index 849f322991..0000000000
--- a/gnuradio-core/src/python/gnuradio/gr/qa_file_metadata.py
+++ /dev/null
@@ -1,196 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2012 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 3, 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., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-#
-
-from gnuradio import gr, gr_unittest
-from gnuradio import parse_file_metadata
-import pmt
-import os, time
-
-class test_file_metadata(gr_unittest.TestCase):
-
-    def setUp(self):
-        self.tb = gr.top_block()
-
-    def tearDown(self):
-        self.tb = None
-
-    def test_001(self):
-	outfile = "test_out.dat"
-
-        detached = False
-        samp_rate = 200000
-        key = pmt.pmt_intern("samp_rate")
-        val = pmt.pmt_from_double(samp_rate)
-        extras = pmt.pmt_make_dict()
-        extras = pmt.pmt_dict_add(extras, key, val)
-        extras_str = pmt.pmt_serialize_str(extras)
-
-        src = gr.sig_source_c(samp_rate, gr.GR_COS_WAVE, 1000, 1, 0)
-        head = gr.head(gr.sizeof_gr_complex, 1000)
-        fsnk = gr.file_meta_sink(gr.sizeof_gr_complex, outfile,
-                                 samp_rate, 1, 
-                                 gr.GR_FILE_FLOAT, True,
-                                 1000000, extras_str, detached)
-        fsnk.set_unbuffered(True)
-
-	self.tb.connect(src, head, fsnk)
-	self.tb.run()
-        fsnk.close()
-
-        handle = open(outfile, "rb")
-        header_str = handle.read(parse_file_metadata.HEADER_LENGTH)
-        if(len(header_str) == 0):
-            self.assertFalse()
-
-        try:
-            header = pmt.pmt_deserialize_str(header_str)
-        except RuntimeError:
-            self.assertFalse()
-
-        info = parse_file_metadata.parse_header(header, False)
-
-        extra_str = handle.read(info["extra_len"])
-        self.assertGreater(len(extra_str), 0)
-        handle.close()
-
-        try:
-            extra = pmt.pmt_deserialize_str(extra_str)
-        except RuntimeError:
-            self.assertFalse()
-
-        extra_info = parse_file_metadata.parse_extra_dict(extra, info, False)
-
-        self.assertEqual(info['rx_rate'], samp_rate)
-        self.assertEqual(pmt.pmt_to_double(extra_info['samp_rate']), samp_rate)
-
-
-        # Test file metadata source
-        # Create a new sig source to start from the beginning
-        src2 = gr.sig_source_c(samp_rate, gr.GR_COS_WAVE, 1000, 1, 0)
-        fsrc = gr.file_meta_source(outfile, False)
-        vsnk = gr.vector_sink_c()
-        tsnk = gr.tag_debug(gr.sizeof_gr_complex, "QA")
-        ssnk = gr.vector_sink_c()
-        head.reset()
-        self.tb.disconnect(src, head, fsnk)
-        self.tb.connect(fsrc, vsnk)
-        self.tb.connect(fsrc, tsnk)
-        self.tb.connect(src2, head, ssnk)
-        self.tb.run()
-
-        # Test to make sure tags with 'samp_rate' and 'rx_rate' keys
-        # were generated and received correctly.
-        tags = tsnk.current_tags()
-        for t in tags:
-            if(pmt.pmt_eq(t.key, pmt.pmt_intern("samp_rate"))):
-                self.assertEqual(pmt.pmt_to_double(t.value), samp_rate)
-            elif(pmt.pmt_eq(t.key, pmt.pmt_intern("rx_rate"))):
-                self.assertEqual(pmt.pmt_to_double(t.value), samp_rate)
-
-        # Test that the data portion was extracted and received correctly.
-        self.assertComplexTuplesAlmostEqual(vsnk.data(), ssnk.data(), 5)
-
-	os.remove(outfile)
-
-    def test_002(self):
-	outfile = "test_out.dat"
-	outfile_hdr = "test_out.dat.hdr"
-
-        detached = True
-        samp_rate = 200000
-        key = pmt.pmt_intern("samp_rate")
-        val = pmt.pmt_from_double(samp_rate)
-        extras = pmt.pmt_make_dict()
-        extras = pmt.pmt_dict_add(extras, key, val)
-        extras_str = pmt.pmt_serialize_str(extras)
-
-        src = gr.sig_source_c(samp_rate, gr.GR_COS_WAVE, 1000, 1, 0)
-        head = gr.head(gr.sizeof_gr_complex, 1000)
-        fsnk = gr.file_meta_sink(gr.sizeof_gr_complex, outfile,
-                                 samp_rate, 1, 
-                                 gr.GR_FILE_FLOAT, True,
-                                 1000000, extras_str, detached)
-        fsnk.set_unbuffered(True)
-
-	self.tb.connect(src, head, fsnk)
-	self.tb.run()
-        fsnk.close()
-
-        # Open detached header for reading
-        handle = open(outfile_hdr, "rb")
-        header_str = handle.read(parse_file_metadata.HEADER_LENGTH)
-        if(len(header_str) == 0):
-            self.assertFalse()
-
-        try:
-            header = pmt.pmt_deserialize_str(header_str)
-        except RuntimeError:
-            self.assertFalse()
-
-        info = parse_file_metadata.parse_header(header, False)
-
-        extra_str = handle.read(info["extra_len"])
-        self.assertGreater(len(extra_str), 0)
-        handle.close()
-
-        try:
-            extra = pmt.pmt_deserialize_str(extra_str)
-        except RuntimeError:
-            self.assertFalse()
-
-        extra_info = parse_file_metadata.parse_extra_dict(extra, info, False)
-
-        self.assertEqual(info['rx_rate'], samp_rate)
-        self.assertEqual(pmt.pmt_to_double(extra_info['samp_rate']), samp_rate)
-
-
-        # Test file metadata source
-        # Create a new sig source to start from the beginning
-        src2 = gr.sig_source_c(samp_rate, gr.GR_COS_WAVE, 1000, 1, 0)
-        fsrc = gr.file_meta_source(outfile, False, detached, outfile_hdr)
-        vsnk = gr.vector_sink_c()
-        tsnk = gr.tag_debug(gr.sizeof_gr_complex, "QA")
-        ssnk = gr.vector_sink_c()
-        head.reset()
-        self.tb.disconnect(src, head, fsnk)
-        self.tb.connect(fsrc, vsnk)
-        self.tb.connect(fsrc, tsnk)
-        self.tb.connect(src2, head, ssnk)
-        self.tb.run()
-
-        # Test to make sure tags with 'samp_rate' and 'rx_rate' keys
-        # were generated and received correctly.
-        tags = tsnk.current_tags()
-        for t in tags:
-            if(pmt.pmt_eq(t.key, pmt.pmt_intern("samp_rate"))):
-                self.assertEqual(pmt.pmt_to_double(t.value), samp_rate)
-            elif(pmt.pmt_eq(t.key, pmt.pmt_intern("rx_rate"))):
-                self.assertEqual(pmt.pmt_to_double(t.value), samp_rate)
-
-        # Test that the data portion was extracted and received correctly.
-        self.assertComplexTuplesAlmostEqual(vsnk.data(), ssnk.data(), 5)
-
-	os.remove(outfile)
-	os.remove(outfile_hdr)
-
-if __name__ == '__main__':
-    gr_unittest.run(test_file_metadata, "test_file_metadata.xml")
diff --git a/gnuradio-core/src/python/gnuradio/parse_file_metadata.py b/gnuradio-core/src/python/gnuradio/parse_file_metadata.py
deleted file mode 100644
index 0cee5a02cc..0000000000
--- a/gnuradio-core/src/python/gnuradio/parse_file_metadata.py
+++ /dev/null
@@ -1,183 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2012 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 3, 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., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-#
-
-import sys
-from gnuradio import gr
-from gruel import pmt
-
-'''
-sr    Sample rate (samples/second)
-time  Time as uint64(secs), double(fractional secs)
-type  Type of data (see gr_file_types enum)
-cplx  is complex? (True or False)
-strt  Start of data (or size of header) in bytes
-size  Size of data in bytes
-'''
-
-HEADER_LENGTH = gr.METADATA_HEADER_SIZE
-
-ftype_to_string = {gr.GR_FILE_BYTE: "bytes",
-                   gr.GR_FILE_SHORT: "short",
-                   gr.GR_FILE_INT: "int",
-                   gr.GR_FILE_LONG: "long",
-                   gr.GR_FILE_LONG_LONG: "long long",
-                   gr.GR_FILE_FLOAT: "float",
-                   gr.GR_FILE_DOUBLE: "double" }
-
-ftype_to_size = {gr.GR_FILE_BYTE: gr.sizeof_char,
-                 gr.GR_FILE_SHORT: gr.sizeof_short,
-                 gr.GR_FILE_INT: gr.sizeof_int,
-                 gr.GR_FILE_LONG: gr.sizeof_int,
-                 gr.GR_FILE_LONG_LONG: 2*gr.sizeof_int,
-                 gr.GR_FILE_FLOAT: gr.sizeof_float,
-                 gr.GR_FILE_DOUBLE: gr.sizeof_double}
-
-def parse_header(p, VERBOSE=False):
-    dump = pmt.PMT_NIL
-
-    info = dict()
-
-    if(pmt.pmt_is_dict(p) is False):
-        sys.stderr.write("Header is not a PMT dictionary: invalid or corrupt data file.\n")
-        sys.exit(1)
-
-    # GET FILE FORMAT VERSION NUMBER
-    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("version"))):
-        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("version"), dump)
-        version = pmt.pmt_to_long(r)
-        if(VERBOSE):
-            print "Version Number: {0}".format(version)
-    else:
-        sys.stderr.write("Could not find key 'sr': invalid or corrupt data file.\n")
-        sys.exit(1)
-
-    # EXTRACT SAMPLE RATE
-    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("rx_rate"))):
-        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("rx_rate"), dump)
-        samp_rate = pmt.pmt_to_double(r)
-        info["rx_rate"] = samp_rate
-        if(VERBOSE):
-            print "Sample Rate: {0:.2f} sps".format(samp_rate)
-    else:
-        sys.stderr.write("Could not find key 'sr': invalid or corrupt data file.\n")
-        sys.exit(1)
-
-    # EXTRACT TIME STAMP
-    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("rx_time"))):
-        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("rx_time"), dump)
-        pmt_secs = pmt.pmt_tuple_ref(r, 0)
-        pmt_fracs = pmt.pmt_tuple_ref(r, 1)
-        secs = float(pmt.pmt_to_uint64(pmt_secs))
-        fracs = pmt.pmt_to_double(pmt_fracs)
-        t = secs + fracs
-        info["rx_time"] = t
-        if(VERBOSE):
-            print "Seconds: {0:.6f}".format(t)
-    else:
-        sys.stderr.write("Could not find key 'time': invalid or corrupt data file.\n")
-        sys.exit(1)
-
-    # EXTRACT ITEM SIZE
-    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("size"))):
-        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("size"), dump)
-        dsize = pmt.pmt_to_long(r)
-        info["size"] = dsize
-        if(VERBOSE):
-            print "Item size: {0}".format(dsize)
-    else:
-        sys.stderr.write("Could not find key 'size': invalid or corrupt data file.\n")
-        sys.exit(1)
-
-    # EXTRACT DATA TYPE
-    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("type"))):
-        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("type"), dump)
-        dtype = pmt.pmt_to_long(r)
-        stype = ftype_to_string[dtype]
-        info["type"] = stype
-        if(VERBOSE):
-            print "Data Type: {0} ({1})".format(stype, dtype)
-    else:
-        sys.stderr.write("Could not find key 'type': invalid or corrupt data file.\n")
-        sys.exit(1)
-
-    # EXTRACT COMPLEX
-    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("cplx"))):
-        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("cplx"), dump)
-        cplx = pmt.pmt_to_bool(r)
-        info["cplx"] = cplx
-        if(VERBOSE):
-            print "Complex? {0}".format(cplx)
-    else:
-        sys.stderr.write("Could not find key 'cplx': invalid or corrupt data file.\n")
-        sys.exit(1)
-
-    # EXTRACT WHERE CURRENT SEGMENT STARTS
-    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("strt"))):
-        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("strt"), dump)
-        seg_start = pmt.pmt_to_uint64(r)
-        info["hdr_len"] = seg_start
-        info["extra_len"] = seg_start - HEADER_LENGTH
-        info["has_extra"] = info["extra_len"] > 0
-        if(VERBOSE):
-            print "Header Length: {0} bytes".format(info["hdr_len"])
-            print "Extra Length:  {0}".format((info["extra_len"]))
-            print "Extra Header?  {0}".format(info["has_extra"])
-    else:
-        sys.stderr.write("Could not find key 'strt': invalid or corrupt data file.\n")
-        sys.exit(1)
-
-    # EXTRACT SIZE OF DATA
-    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("bytes"))):
-        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("bytes"), dump)
-        nbytes = pmt.pmt_to_uint64(r)
-
-        nitems = nbytes/dsize
-        info["nitems"] = nitems
-        info["nbytes"] = nbytes
-
-        if(VERBOSE):
-            print "Size of Data: {0} bytes".format(nbytes)
-            print "              {0} items".format(nitems)
-    else:
-        sys.stderr.write("Could not find key 'size': invalid or corrupt data file.\n")
-        sys.exit(1)
-
-    return info
-
-# IF THERE IS EXTRA DATA, PULL OUT THE DICTIONARY AND PARSE IT
-def parse_extra_dict(p, info, VERBOSE=False):
-    if(pmt.pmt_is_dict(p) is False):
-        sys.stderr.write("Extra header is not a PMT dictionary: invalid or corrupt data file.\n")
-        sys.exit(1)
-
-    items = pmt.pmt_dict_items(p)
-    nitems = pmt.pmt_length(items)
-    for i in xrange(nitems):
-        item = pmt.pmt_nth(i, items)
-        key = pmt.pmt_symbol_to_string(pmt.pmt_car(item))
-        val = pmt.pmt_cdr(item)
-        info[key] = val
-        if(VERBOSE):
-            print "{0}: ".format(key)
-            pmt.pmt_print(val)
-
-    return info
diff --git a/gr-blocks/CMakeLists.txt b/gr-blocks/CMakeLists.txt
index 9c81ba6bf9..7e2f43562f 100644
--- a/gr-blocks/CMakeLists.txt
+++ b/gr-blocks/CMakeLists.txt
@@ -85,6 +85,7 @@ if(ENABLE_PYTHON)
      add_subdirectory(swig)
      add_subdirectory(grc)
      add_subdirectory(doc)
+     add_subdirectory(examples)
 endif(ENABLE_PYTHON)
 
 ########################################################################
diff --git a/gr-blocks/examples/CMakeLists.txt b/gr-blocks/examples/CMakeLists.txt
new file mode 100644
index 0000000000..79535daa05
--- /dev/null
+++ b/gr-blocks/examples/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright 2012 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+
+add_subdirectory(metadata)
diff --git a/gr-blocks/examples/metadata/CMakeLists.txt b/gr-blocks/examples/metadata/CMakeLists.txt
new file mode 100644
index 0000000000..53a54b9d5a
--- /dev/null
+++ b/gr-blocks/examples/metadata/CMakeLists.txt
@@ -0,0 +1,30 @@
+# Copyright 2012 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+
+include(GrPython)
+
+install(
+  FILES
+  file_metadata_sink.grc
+  file_metadata_source.grc
+  file_metadata_vector_sink.grc
+  file_metadata_vector_source.grc
+  DESTINATION ${GR_PKG_DATA_DIR}/examples/metadata
+  COMPONENT "core_python"
+)
diff --git a/gr-blocks/examples/metadata/file_metadata_sink.grc b/gr-blocks/examples/metadata/file_metadata_sink.grc
new file mode 100644
index 0000000000..198b0725f9
--- /dev/null
+++ b/gr-blocks/examples/metadata/file_metadata_sink.grc
@@ -0,0 +1,951 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+  <timestamp>Fri Dec 14 17:09:06 2012</timestamp>
+  <block>
+    <key>options</key>
+    <param>
+      <key>id</key>
+      <value>file_metadata_sink</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>title</key>
+      <value></value>
+    </param>
+    <param>
+      <key>author</key>
+      <value></value>
+    </param>
+    <param>
+      <key>description</key>
+      <value></value>
+    </param>
+    <param>
+      <key>window_size</key>
+      <value>1280, 1024</value>
+    </param>
+    <param>
+      <key>generate_options</key>
+      <value>qt_gui</value>
+    </param>
+    <param>
+      <key>category</key>
+      <value>Custom</value>
+    </param>
+    <param>
+      <key>run_options</key>
+      <value>prompt</value>
+    </param>
+    <param>
+      <key>run</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>max_nouts</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>realtime_scheduling</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(10, 10)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_sig_source_x</key>
+    <param>
+      <key>id</key>
+      <value>gr_sig_source_x_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>samp_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>waveform</key>
+      <value>gr.GR_COS_WAVE</value>
+    </param>
+    <param>
+      <key>freq</key>
+      <value>1000</value>
+    </param>
+    <param>
+      <key>amp</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>offset</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(57, 140)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable_qtgui_range</key>
+    <param>
+      <key>id</key>
+      <value>qt_samp_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>label</key>
+      <value></value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>start</key>
+      <value>200000</value>
+    </param>
+    <param>
+      <key>stop</key>
+      <value>5000000</value>
+    </param>
+    <param>
+      <key>step</key>
+      <value>200000</value>
+    </param>
+    <param>
+      <key>widget</key>
+      <value>counter_slider</value>
+    </param>
+    <param>
+      <key>orient</key>
+      <value>Qt.Horizontal</value>
+    </param>
+    <param>
+      <key>min_len</key>
+      <value>200</value>
+    </param>
+    <param>
+      <key>gui_hint</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(330, 259)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>200000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(208, 11)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>uhd_usrp_source</key>
+    <param>
+      <key>id</key>
+      <value>uhd_usrp_source_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>fc32</value>
+    </param>
+    <param>
+      <key>otw</key>
+      <value></value>
+    </param>
+    <param>
+      <key>stream_args</key>
+      <value></value>
+    </param>
+    <param>
+      <key>dev_addr</key>
+      <value>addr=192.168.11.2</value>
+    </param>
+    <param>
+      <key>sync</key>
+      <value></value>
+    </param>
+    <param>
+      <key>clock_rate</key>
+      <value>0.0</value>
+    </param>
+    <param>
+      <key>num_mboards</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>clock_source0</key>
+      <value></value>
+    </param>
+    <param>
+      <key>time_source0</key>
+      <value></value>
+    </param>
+    <param>
+      <key>sd_spec0</key>
+      <value></value>
+    </param>
+    <param>
+      <key>clock_source1</key>
+      <value></value>
+    </param>
+    <param>
+      <key>time_source1</key>
+      <value></value>
+    </param>
+    <param>
+      <key>sd_spec1</key>
+      <value></value>
+    </param>
+    <param>
+      <key>clock_source2</key>
+      <value></value>
+    </param>
+    <param>
+      <key>time_source2</key>
+      <value></value>
+    </param>
+    <param>
+      <key>sd_spec2</key>
+      <value></value>
+    </param>
+    <param>
+      <key>clock_source3</key>
+      <value></value>
+    </param>
+    <param>
+      <key>time_source3</key>
+      <value></value>
+    </param>
+    <param>
+      <key>sd_spec3</key>
+      <value></value>
+    </param>
+    <param>
+      <key>clock_source4</key>
+      <value></value>
+    </param>
+    <param>
+      <key>time_source4</key>
+      <value></value>
+    </param>
+    <param>
+      <key>sd_spec4</key>
+      <value></value>
+    </param>
+    <param>
+      <key>clock_source5</key>
+      <value></value>
+    </param>
+    <param>
+      <key>time_source5</key>
+      <value></value>
+    </param>
+    <param>
+      <key>sd_spec5</key>
+      <value></value>
+    </param>
+    <param>
+      <key>clock_source6</key>
+      <value></value>
+    </param>
+    <param>
+      <key>time_source6</key>
+      <value></value>
+    </param>
+    <param>
+      <key>sd_spec6</key>
+      <value></value>
+    </param>
+    <param>
+      <key>clock_source7</key>
+      <value></value>
+    </param>
+    <param>
+      <key>time_source7</key>
+      <value></value>
+    </param>
+    <param>
+      <key>sd_spec7</key>
+      <value></value>
+    </param>
+    <param>
+      <key>nchan</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>samp_rate</key>
+      <value>qt_samp_rate</value>
+    </param>
+    <param>
+      <key>center_freq0</key>
+      <value>98.9e6</value>
+    </param>
+    <param>
+      <key>gain0</key>
+      <value>30</value>
+    </param>
+    <param>
+      <key>ant0</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant1</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant2</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant3</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant4</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq5</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain5</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant5</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw5</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq6</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain6</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant6</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw6</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq7</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain7</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant7</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw7</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq8</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain8</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant8</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw8</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq9</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain9</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant9</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw9</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq10</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain10</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant10</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw10</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq11</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain11</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant11</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw11</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq12</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain12</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant12</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw12</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq13</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain13</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant13</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw13</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq14</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain14</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant14</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw14</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq15</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain15</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant15</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw15</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq16</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain16</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant16</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw16</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq17</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain17</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant17</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw17</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq18</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain18</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant18</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw18</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq19</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain19</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant19</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw19</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq20</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain20</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant20</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw20</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq21</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain21</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant21</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw21</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq22</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain22</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant22</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw22</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq23</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain23</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant23</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw23</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq24</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain24</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant24</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw24</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq25</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain25</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant25</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw25</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq26</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain26</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant26</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw26</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq27</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain27</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant27</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw27</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq28</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain28</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant28</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw28</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq29</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain29</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant29</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw29</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq30</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain30</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant30</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw30</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>center_freq31</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain31</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>ant31</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw31</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(53, 269)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_head</key>
+    <param>
+      <key>id</key>
+      <value>gr_head_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>num_items</key>
+      <value>20000000</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(309, 172)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_file_meta_sink</key>
+    <param>
+      <key>id</key>
+      <value>blocks_file_meta_sink_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>file</key>
+      <value>/tmp/metadat_file.out</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>samp_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>rel_rate</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>max_seg_size</key>
+      <value>1000000</value>
+    </param>
+    <param>
+      <key>extra_dict</key>
+      <value>""</value>
+    </param>
+    <param>
+      <key>detached</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>unbuffered</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(569, 124)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <connection>
+    <source_block_id>gr_sig_source_x_0</source_block_id>
+    <sink_block_id>gr_head_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>uhd_usrp_source_0</source_block_id>
+    <sink_block_id>gr_head_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>gr_head_0</source_block_id>
+    <sink_block_id>blocks_file_meta_sink_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+</flow_graph>
diff --git a/gr-blocks/examples/metadata/file_metadata_source.grc b/gr-blocks/examples/metadata/file_metadata_source.grc
new file mode 100644
index 0000000000..23757881bc
--- /dev/null
+++ b/gr-blocks/examples/metadata/file_metadata_source.grc
@@ -0,0 +1,350 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+  <timestamp>Fri Dec 14 17:08:09 2012</timestamp>
+  <block>
+    <key>options</key>
+    <param>
+      <key>id</key>
+      <value>file_metadata_source</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>title</key>
+      <value></value>
+    </param>
+    <param>
+      <key>author</key>
+      <value></value>
+    </param>
+    <param>
+      <key>description</key>
+      <value></value>
+    </param>
+    <param>
+      <key>window_size</key>
+      <value>1280, 1024</value>
+    </param>
+    <param>
+      <key>generate_options</key>
+      <value>qt_gui</value>
+    </param>
+    <param>
+      <key>category</key>
+      <value>Custom</value>
+    </param>
+    <param>
+      <key>run_options</key>
+      <value>prompt</value>
+    </param>
+    <param>
+      <key>run</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>max_nouts</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>realtime_scheduling</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(10, 10)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>200000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(208, 11)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_tag_debug</key>
+    <param>
+      <key>id</key>
+      <value>gr_tag_debug_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>name</key>
+      <value>Test</value>
+    </param>
+    <param>
+      <key>num_inputs</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>display</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(561, 290)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>analog_agc2_xx</key>
+    <param>
+      <key>id</key>
+      <value>analog_agc2_xx_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>attack_rate</key>
+      <value>1e-1</value>
+    </param>
+    <param>
+      <key>decay_rate</key>
+      <value>1e-2</value>
+    </param>
+    <param>
+      <key>reference</key>
+      <value>1.0</value>
+    </param>
+    <param>
+      <key>gain</key>
+      <value>1.0</value>
+    </param>
+    <param>
+      <key>max_gain</key>
+      <value>0.0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(561, 82)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>qtgui_time_sink_x</key>
+    <param>
+      <key>id</key>
+      <value>qtgui_time_sink_x_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>name</key>
+      <value>QT GUI Plot</value>
+    </param>
+    <param>
+      <key>size</key>
+      <value>1024</value>
+    </param>
+    <param>
+      <key>bw</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>nconnections</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>gui_hint</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(776, 98)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_file_sink</key>
+    <param>
+      <key>id</key>
+      <value>gr_file_sink_1</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>file</key>
+      <value>/tmp/received_data.out</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>unbuffered</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(564, 215)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_throttle</key>
+    <param>
+      <key>id</key>
+      <value>gr_throttle_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>samples_per_second</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(322, 222)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_file_meta_source</key>
+    <param>
+      <key>id</key>
+      <value>blocks_file_meta_source_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>file</key>
+      <value>/tmp/metadat_file.out</value>
+    </param>
+    <param>
+      <key>repeat</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>detached</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>hdr_file</key>
+      <value></value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(50, 198)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <connection>
+    <source_block_id>gr_throttle_0</source_block_id>
+    <sink_block_id>gr_file_sink_1</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>gr_throttle_0</source_block_id>
+    <sink_block_id>gr_tag_debug_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>gr_throttle_0</source_block_id>
+    <sink_block_id>analog_agc2_xx_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>analog_agc2_xx_0</source_block_id>
+    <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>blocks_file_meta_source_0</source_block_id>
+    <sink_block_id>gr_throttle_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+</flow_graph>
diff --git a/gr-blocks/examples/metadata/file_metadata_vector_sink.grc b/gr-blocks/examples/metadata/file_metadata_vector_sink.grc
new file mode 100644
index 0000000000..05b7cbc922
--- /dev/null
+++ b/gr-blocks/examples/metadata/file_metadata_vector_sink.grc
@@ -0,0 +1,219 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+  <timestamp>Fri Dec 14 17:08:29 2012</timestamp>
+  <block>
+    <key>options</key>
+    <param>
+      <key>id</key>
+      <value>file_metadata_vector_sink</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>title</key>
+      <value></value>
+    </param>
+    <param>
+      <key>author</key>
+      <value></value>
+    </param>
+    <param>
+      <key>description</key>
+      <value></value>
+    </param>
+    <param>
+      <key>window_size</key>
+      <value>1280, 1024</value>
+    </param>
+    <param>
+      <key>generate_options</key>
+      <value>no_gui</value>
+    </param>
+    <param>
+      <key>category</key>
+      <value>Custom</value>
+    </param>
+    <param>
+      <key>run_options</key>
+      <value>run</value>
+    </param>
+    <param>
+      <key>run</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>max_nouts</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>realtime_scheduling</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(10, 10)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>200000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(208, 11)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_vector_source_x</key>
+    <param>
+      <key>id</key>
+      <value>gr_vector_source_x_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>vector</key>
+      <value>10*[0,1,2,3,4,5,6,7,8,9]</value>
+    </param>
+    <param>
+      <key>repeat</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(67, 100)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_head</key>
+    <param>
+      <key>id</key>
+      <value>gr_head_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>num_items</key>
+      <value>10010000</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(325, 108)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_file_meta_sink</key>
+    <param>
+      <key>id</key>
+      <value>blocks_file_meta_sink_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>file</key>
+      <value>/tmp/metadat_vector.out</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>samp_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>rel_rate</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>max_seg_size</key>
+      <value>1000000</value>
+    </param>
+    <param>
+      <key>extra_dict</key>
+      <value>""</value>
+    </param>
+    <param>
+      <key>detached</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>unbuffered</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(544, 60)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <connection>
+    <source_block_id>gr_vector_source_x_0</source_block_id>
+    <sink_block_id>gr_head_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>gr_head_0</source_block_id>
+    <sink_block_id>blocks_file_meta_sink_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+</flow_graph>
diff --git a/gr-blocks/examples/metadata/file_metadata_vector_source.grc b/gr-blocks/examples/metadata/file_metadata_vector_source.grc
new file mode 100644
index 0000000000..d52257e06d
--- /dev/null
+++ b/gr-blocks/examples/metadata/file_metadata_vector_source.grc
@@ -0,0 +1,338 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+  <timestamp>Fri Dec 14 17:11:02 2012</timestamp>
+  <block>
+    <key>options</key>
+    <param>
+      <key>id</key>
+      <value>file_metadata_vector_source</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>title</key>
+      <value></value>
+    </param>
+    <param>
+      <key>author</key>
+      <value></value>
+    </param>
+    <param>
+      <key>description</key>
+      <value></value>
+    </param>
+    <param>
+      <key>window_size</key>
+      <value>1280, 1024</value>
+    </param>
+    <param>
+      <key>generate_options</key>
+      <value>qt_gui</value>
+    </param>
+    <param>
+      <key>category</key>
+      <value>Custom</value>
+    </param>
+    <param>
+      <key>run_options</key>
+      <value>prompt</value>
+    </param>
+    <param>
+      <key>run</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>max_nouts</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>realtime_scheduling</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(10, 10)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>200000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(208, 11)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_file_sink</key>
+    <param>
+      <key>id</key>
+      <value>gr_file_sink_1</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>file</key>
+      <value>/tmp/received_data.out</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>unbuffered</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(564, 215)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_tag_debug</key>
+    <param>
+      <key>id</key>
+      <value>gr_tag_debug_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>name</key>
+      <value>Test</value>
+    </param>
+    <param>
+      <key>num_inputs</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>display</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(563, 298)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>qtgui_time_sink_x</key>
+    <param>
+      <key>id</key>
+      <value>qtgui_time_sink_x_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>name</key>
+      <value>QT GUI Plot</value>
+    </param>
+    <param>
+      <key>size</key>
+      <value>1024</value>
+    </param>
+    <param>
+      <key>bw</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>nconnections</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>gui_hint</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(746, 116)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_vector_to_stream</key>
+    <param>
+      <key>id</key>
+      <value>blocks_vector_to_stream_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>num_items</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(526, 132)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>gr_throttle</key>
+    <param>
+      <key>id</key>
+      <value>gr_throttle_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>samples_per_second</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(322, 223)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_file_meta_source</key>
+    <param>
+      <key>id</key>
+      <value>blocks_file_meta_source_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>file</key>
+      <value>/tmp/metadat_vector.out</value>
+    </param>
+    <param>
+      <key>repeat</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>detached</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>hdr_file</key>
+      <value></value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(42, 199)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <connection>
+    <source_block_id>gr_throttle_0</source_block_id>
+    <sink_block_id>gr_file_sink_1</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>gr_throttle_0</source_block_id>
+    <sink_block_id>gr_tag_debug_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>blocks_vector_to_stream_0</source_block_id>
+    <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>gr_throttle_0</source_block_id>
+    <sink_block_id>blocks_vector_to_stream_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>blocks_file_meta_source_0</source_block_id>
+    <sink_block_id>gr_throttle_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+</flow_graph>
diff --git a/gr-blocks/grc/blocks_block_tree.xml b/gr-blocks/grc/blocks_block_tree.xml
index ea5e552d1d..797b3dbc5a 100644
--- a/gr-blocks/grc/blocks_block_tree.xml
+++ b/gr-blocks/grc/blocks_block_tree.xml
@@ -31,6 +31,11 @@
 	<cat>
 	        <name>Sources (New)</name>
 		<block>blocks_file_source</block>
+		<block>blocks_file_meta_source</block>
+	</cat>
+	<cat>
+	        <name>Sinks (New)</name>
+		<block>blocks_file_meta_sink</block>
 	</cat>
 	<cat>
 		<name>Math Operations (New) </name>
diff --git a/gr-blocks/grc/blocks_file_meta_sink.xml b/gr-blocks/grc/blocks_file_meta_sink.xml
new file mode 100644
index 0000000000..f6490d507d
--- /dev/null
+++ b/gr-blocks/grc/blocks_file_meta_sink.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##File Meta Sink
+###################################################
+ -->
+<block>
+	<name>File Meta Sink</name>
+	<key>blocks_file_meta_sink</key>
+	<import>from gnuradio import gr, blocks</import>
+	<make>blocks.file_meta_sink($type.size*$vlen, $file, $samp_rate, $rel_rate, $type.dtype, $type.cplx, $max_seg_size, $extra_dict, $detached)
+self.$(id).set_unbuffered($unbuffered)</make>
+	<callback>set_unbuffered($unbuffered)</callback>
+	<callback>open($file)</callback>
+	<param>
+		<name>File</name>
+		<key>file</key>
+		<value></value>
+		<type>file_save</type>
+	</param>
+	<param>
+		<name>Input Type</name>
+		<key>type</key>
+		<type>enum</type>
+		<option>
+			<name>Complex</name>
+			<key>complex</key>
+			<opt>size:gr.sizeof_gr_complex</opt>
+			<opt>dtype:blocks.GR_FILE_FLOAT</opt>
+			<opt>cplx:True</opt>
+		</option>
+		<option>
+			<name>Float</name>
+			<key>float</key>
+			<opt>size:gr.sizeof_float</opt>
+			<opt>dtype:blocks.GR_FILE_FLOAT</opt>
+			<opt>cplx:False</opt>
+		</option>
+		<option>
+			<name>Int</name>
+			<key>int</key>
+			<opt>size:gr.sizeof_int</opt>
+			<opt>dtype:blocks.GR_FILE_INT</opt>
+			<opt>cplx:False</opt>
+		</option>
+		<option>
+			<name>Short</name>
+			<key>short</key>
+			<opt>size:gr.sizeof_short</opt>
+			<opt>dtype:blocks.GR_FILE_SHORT</opt>
+			<opt>cplx:False</opt>
+		</option>
+		<option>
+			<name>Byte</name>
+			<key>byte</key>
+			<opt>size:gr.sizeof_char</opt>
+			<opt>dtype:blocks.GR_FILE_BYTE</opt>
+			<opt>cplx:False</opt>
+		</option>
+	</param>
+	<param>
+		<name>Sample Rate</name>
+		<key>samp_rate</key>
+		<value>samp_rate</value>
+		<type>real</type>
+	</param>
+	<param>
+		<name>Relative Rate Change</name>
+		<key>rel_rate</key>
+		<value>1</value>
+		<type>real</type>
+	</param>
+	<param>
+		<name>Vec Length</name>
+		<key>vlen</key>
+		<value>1</value>
+		<type>int</type>
+	</param>
+	<param>
+		<name>Max Seg. Size</name>
+		<key>max_seg_size</key>
+		<value>1000000</value>
+		<type>int</type>
+	</param>
+	<param>
+		<name>Extra Dict.</name>
+		<key>extra_dict</key>
+		<value>""</value>
+		<type>string</type>
+	</param>
+	<param>
+		<name>Detached</name>
+		<key>detached</key>
+		<value>False</value>
+		<type>bool</type>
+		<option>
+		  <name>Off</name>
+		  <key>False</key>
+		</option>
+		<option>
+		  <name>On</name>
+		  <key>True</key>
+		</option>
+	</param>	<param>
+		<name>Unbuffered</name>
+		<key>unbuffered</key>
+		<value>False</value>
+		<type>bool</type>
+		<option>
+				<name>Off</name>
+				<key>False</key>
+		</option>
+		<option>
+				<name>On</name>
+				<key>True</key>
+		</option>
+	</param>
+	<check>$vlen &gt; 0</check>
+	<sink>
+		<name>in</name>
+		<type>$type</type>
+		<vlen>$vlen</vlen>
+	</sink>
+</block>
diff --git a/gr-blocks/grc/blocks_file_meta_source.xml b/gr-blocks/grc/blocks_file_meta_source.xml
new file mode 100644
index 0000000000..aa7e349551
--- /dev/null
+++ b/gr-blocks/grc/blocks_file_meta_source.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##File Source
+###################################################
+ -->
+<block>
+	<name>File Meta Source</name>
+	<key>blocks_file_meta_source</key>
+	<import>from gnuradio import gr, blocks</import>
+	<make>blocks.file_meta_source($file, $repeat, $detached, $hdr_file)</make>
+	<callback>open($file, $repeat)</callback>
+	<param>
+		<name>Output Type</name>
+		<key>type</key>
+		<type>enum</type>
+		<option>
+			<name>Complex</name>
+			<key>complex</key>
+			<opt>size:gr.sizeof_gr_complex</opt>
+		</option>
+		<option>
+			<name>Float</name>
+			<key>float</key>
+			<opt>size:gr.sizeof_float</opt>
+		</option>
+		<option>
+			<name>Int</name>
+			<key>int</key>
+			<opt>size:gr.sizeof_int</opt>
+		</option>
+		<option>
+			<name>Short</name>
+			<key>short</key>
+			<opt>size:gr.sizeof_short</opt>
+		</option>
+		<option>
+			<name>Byte</name>
+			<key>byte</key>
+			<opt>size:gr.sizeof_char</opt>
+		</option>
+	</param>
+	<param>
+		<name>File</name>
+		<key>file</key>
+		<value></value>
+		<type>file_open</type>
+	</param>
+	<param>
+		<name>Repeat</name>
+		<key>repeat</key>
+		<value>True</value>
+		<type>enum</type>
+		<option>
+			<name>Yes</name>
+			<key>True</key>
+		</option>
+		<option>
+			<name>No</name>
+			<key>False</key>
+		</option>
+	</param>
+	<param>
+		<name>Detached Header</name>
+		<key>detached</key>
+		<value>False</value>
+		<type>enum</type>
+		<option>
+			<name>Yes</name>
+			<key>True</key>
+		</option>
+		<option>
+			<name>No</name>
+			<key>False</key>
+		</option>
+	</param>
+	<param>
+		<name>Header File</name>
+		<key>hdr_file</key>
+		<value></value>
+		<type>file_open</type>
+	</param>
+	<param>
+		<name>Vec Length</name>
+		<key>vlen</key>
+		<value>1</value>
+		<type>int</type>
+	</param>
+	<source>
+		<name>out</name>
+		<type>$type</type>
+		<vlen>$vlen</vlen>
+	</source>
+</block>
diff --git a/gr-blocks/include/blocks/CMakeLists.txt b/gr-blocks/include/blocks/CMakeLists.txt
index 787fddba37..0459097b0d 100644
--- a/gr-blocks/include/blocks/CMakeLists.txt
+++ b/gr-blocks/include/blocks/CMakeLists.txt
@@ -102,6 +102,8 @@ install(FILES
     conjugate_cc.h
     deinterleave.h
     file_source.h
+    file_meta_sink.h
+    file_meta_source.h
     float_to_char.h
     float_to_complex.h
     float_to_int.h
diff --git a/gr-blocks/include/blocks/file_meta_sink.h b/gr-blocks/include/blocks/file_meta_sink.h
new file mode 100644
index 0000000000..ef64887cf9
--- /dev/null
+++ b/gr-blocks/include/blocks/file_meta_sink.h
@@ -0,0 +1,111 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_BLOCKS_FILE_META_SINK_H
+#define INCLUDED_BLOCKS_FILE_META_SINK_H
+
+#include <blocks/api.h>
+#include <gr_sync_block.h>
+
+namespace gr {
+  namespace blocks {
+
+    const char METADATA_VERSION = 0;
+    const size_t METADATA_HEADER_SIZE = 149;
+
+    enum gr_file_types {
+      GR_FILE_BYTE=0,
+      GR_FILE_CHAR=0,
+      GR_FILE_SHORT=1,
+      GR_FILE_INT,
+      GR_FILE_LONG,
+      GR_FILE_LONG_LONG,
+      GR_FILE_FLOAT,
+      GR_FILE_DOUBLE,
+    };
+
+    /*!
+     * \brief Write stream to file with meta-data headers.
+     * \ingroup sink_blk
+     *
+     * These files represent data as binary information in between
+     * meta-data headers. The headers contain information about the
+     * type of data and properties of the data in the next segment of
+     * samples. The information includes:
+     *
+     *   rx_rate (double): sample rate of data.
+     *   rx_time (uint64_t, double): time stamp of first sample in segment.
+     *   size (uint32_t): item size in bytes.
+     *   type (gr_file_types as int32_t): data type.
+     *   cplx (bool): Is data complex?
+     *   strt (uint64_t): Starting byte of data in this segment.
+     *   bytes (uint64_t): Size in bytes of data in this segment.
+     *
+     * Tags can be sent to the file to update the information, which
+     * will create a new header. Headers are found by searching from
+     * the first header (at position 0 in the file) and reading where
+     * the data segment starts plus the data segment size. Following
+     * will either be a new header or EOF.
+     */
+    class BLOCKS_API file_meta_sink : virtual public gr_sync_block
+    {
+    public:
+      // gr::blocks::file_meta_sink::sptr
+      typedef boost::shared_ptr<file_meta_sink> sptr;
+
+      /*!
+       * \brief Create a meta-data file sink.
+       *
+       * \param itemsize (size_t): Size of data type.
+       * \param filename (string): Name of file to write data to.
+       * \param samp_rate (double): Sample rate of data. If sample rate will be
+       *    set by a tag, such as rx_tag from a UHD source, this is
+       *    basically ignored.
+       * \param relative_rate (double): Rate chance from source of sample
+       *    rate tag to sink.
+       * \param type (gr_file_types): Data type (int, float, etc.)
+       * \param complex (bool): If data stream is complex
+       * \param max_segment_size (size_t): Length of a single segment
+       *    before the header is repeated (in items).
+       * \param extra_dict (string): a serialized PMT dictionary of extra
+       *    information. Currently not supported.
+       * \param detached_header (bool): Set to true to store the header
+       *    info in a separate file (named filename.hdr)
+       */
+      static sptr make(size_t itemsize, const std::string &filename,
+		       double samp_rate=1, double relative_rate=1,
+		       gr_file_types type=GR_FILE_FLOAT, bool complex=true,
+		       size_t max_segment_size=1000000,
+		       const std::string &extra_dict="",
+		       bool detached_header=false);
+
+      virtual bool open(const std::string &filename) = 0;
+      virtual void close() = 0;
+      virtual void do_update() = 0;
+
+      virtual void set_unbuffered(bool unbuffered) = 0;
+    };
+
+  } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_BLOCKS_FILE_META_SINK_H */
diff --git a/gr-blocks/include/blocks/file_meta_source.h b/gr-blocks/include/blocks/file_meta_source.h
new file mode 100644
index 0000000000..a992d52432
--- /dev/null
+++ b/gr-blocks/include/blocks/file_meta_source.h
@@ -0,0 +1,81 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_BLOCKS_FILE_META_SOURCE_H
+#define INCLUDED_BLOCKS_FILE_META_SOURCE_H
+
+#include <blocks/api.h>
+#include <gr_sync_block.h>
+
+namespace gr {
+  namespace blocks {
+
+    /*!
+     * \brief Reads stream from file with meta-data headers. Headers
+     * are parsed into tags.
+     * \ingroup source_blk
+     *
+     * The information in the metadata headers includes:
+     *
+     *   rx_rate (double): sample rate of data.
+     *   rx_time (uint64_t, double): time stamp of first sample in segment.
+     *   size (uint32_t): item size in bytes.
+     *   type (gr_file_types as int32_t): data type.
+     *   cplx (bool): Is data complex?
+     *   strt (uint64_t): Starting byte of data in this segment.
+     *   bytes (uint64_t): Size in bytes of data in this segment.
+     *
+     * Any item inside of the extra header dictionary is ready out and
+     * made into a stream tag.
+     */
+    class BLOCKS_API file_meta_source : virtual public gr_sync_block
+    {
+    public:
+      // gr::blocks::file_meta_source::sptr
+      typedef boost::shared_ptr<file_meta_source> sptr;
+
+      /*!
+       * \brief Create a meta-data file source.
+       *
+       * \param filename (string): Name of file to write data to.
+       * \param repeat (bool): Repeats file when EOF is found.
+       * \param detached_header (bool): Set to true if header
+       *    info is stored in a separate file (usually named filename.hdr)
+       * \param hdr_filename (string): Name of detached header file if used.
+       *    Defaults to 'filename.hdr' if detached_header is true but this
+       *    field is an empty string.
+       */
+      static sptr make(const std::string &filename,
+		       bool repeat=false,
+		       bool detached_header=false,
+		       const std::string &hdr_filename="");
+
+      virtual bool open(const std::string &filename,
+			const std::string &hdr_filename="") = 0;
+      virtual void close() = 0;
+      virtual void do_update() = 0;
+    };
+
+  } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_BLOCKS_FILE_META_SOURCE_H */
diff --git a/gr-blocks/lib/CMakeLists.txt b/gr-blocks/lib/CMakeLists.txt
index 3a8ffac753..ab989fc782 100644
--- a/gr-blocks/lib/CMakeLists.txt
+++ b/gr-blocks/lib/CMakeLists.txt
@@ -141,6 +141,8 @@ list(APPEND gr_blocks_sources
     conjugate_cc_impl.cc
     deinterleave_impl.cc
     file_source_impl.cc
+    file_meta_sink_impl.cc
+    file_meta_source_impl.cc
     float_to_char_impl.cc
     float_to_complex_impl.cc
     float_array_to_int.cc
diff --git a/gr-blocks/lib/file_meta_sink_impl.cc b/gr-blocks/lib/file_meta_sink_impl.cc
new file mode 100644
index 0000000000..ad16e9fcac
--- /dev/null
+++ b/gr-blocks/lib/file_meta_sink_impl.cc
@@ -0,0 +1,464 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "file_meta_sink_impl.h"
+#include <gr_io_signature.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdexcept>
+#include <cstdio>
+
+namespace gr {
+  namespace blocks {
+
+// win32 (mingw/msvc) specific
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+#ifdef O_BINARY
+#define	OUR_O_BINARY O_BINARY
+#else
+#define	OUR_O_BINARY 0
+#endif
+
+// should be handled via configure
+#ifdef O_LARGEFILE
+#define	OUR_O_LARGEFILE	O_LARGEFILE
+#else
+#define	OUR_O_LARGEFILE 0
+#endif
+
+    file_meta_sink::sptr
+    file_meta_sink::make(size_t itemsize, const std::string &filename,
+			 double samp_rate, double relative_rate,
+			 gr_file_types type, bool complex,
+			 size_t max_segment_size,
+			 const std::string &extra_dict,
+			 bool detached_header)
+    {
+      return gnuradio::get_initial_sptr
+	(new file_meta_sink_impl(itemsize, filename,
+				 samp_rate, relative_rate,
+				 type, complex,
+				 max_segment_size,
+				 extra_dict,
+				 detached_header));
+    }
+
+    file_meta_sink_impl::file_meta_sink_impl(size_t itemsize,
+					     const std::string &filename,
+					     double samp_rate, double relative_rate,
+					     gr_file_types type, bool complex,
+					     size_t max_segment_size,
+					     const std::string &extra_dict,
+					     bool detached_header)
+      : gr_sync_block("file_meta_sink",
+		      gr_make_io_signature(1, 1, itemsize),
+		      gr_make_io_signature(0, 0, 0)),
+	d_itemsize(itemsize),
+	d_samp_rate(samp_rate), d_relative_rate(relative_rate),
+	d_max_seg_size(max_segment_size), d_total_seg_size(0),
+	d_updated(false), d_unbuffered(false)
+    {
+      d_fp = 0;
+      d_new_fp = 0;
+      d_hdr_fp = 0;
+      d_new_hdr_fp = 0;
+
+      if(detached_header == true)
+	d_state = STATE_DETACHED;
+      else
+	d_state = STATE_INLINE;
+
+      if(!open(filename))
+	throw std::runtime_error("file_meta_sink: can't open file\n");
+
+      pmt_t timestamp = pmt_make_tuple(pmt_from_uint64(0),
+				       pmt_from_double(0));
+
+      // handle extra dictionary
+      d_extra = pmt_make_dict();
+      if(extra_dict.size() > 0) {
+	pmt_t extras = pmt_deserialize_str(extra_dict);
+	pmt_t keys = pmt_dict_keys(extras);
+	pmt_t vals = pmt_dict_values(extras);
+	size_t nitems = pmt_length(keys);
+	for(size_t i = 0; i < nitems; i++) {
+	  d_extra = pmt_dict_add(d_extra,
+				 pmt_nth(i, keys),
+				 pmt_nth(i, vals));
+	}
+      }
+
+      d_extra_size = pmt_serialize_str(d_extra).size();
+
+      d_header = pmt_make_dict();
+      d_header = pmt_dict_add(d_header, mp("version"), mp(METADATA_VERSION));
+      d_header = pmt_dict_add(d_header, mp("rx_rate"), mp(samp_rate));
+      d_header = pmt_dict_add(d_header, mp("rx_time"), timestamp);
+      d_header = pmt_dict_add(d_header, mp("size"), pmt_from_long(d_itemsize));
+      d_header = pmt_dict_add(d_header, mp("type"), pmt_from_long(type));
+      d_header = pmt_dict_add(d_header, mp("cplx"), complex ? PMT_T : PMT_F);
+      d_header = pmt_dict_add(d_header, mp("strt"), pmt_from_uint64(METADATA_HEADER_SIZE+d_extra_size));
+      d_header = pmt_dict_add(d_header, mp("bytes"), pmt_from_uint64(0));
+
+      do_update();
+
+      if(d_state == STATE_DETACHED)
+	write_header(d_hdr_fp, d_header, d_extra);
+      else
+	write_header(d_fp, d_header, d_extra);
+    }
+
+    file_meta_sink_impl::~file_meta_sink_impl()
+    {
+      close();
+
+      if(d_fp) {
+	fclose(d_fp);
+	d_fp = 0;
+      }
+  
+      if(d_state == STATE_DETACHED) {
+	if(d_hdr_fp) {
+	  fclose(d_hdr_fp);
+	  d_hdr_fp = 0;
+	}
+      }
+    }
+
+    bool
+    file_meta_sink_impl::open(const std::string &filename)
+    {
+      bool ret = true;
+      if(d_state == STATE_DETACHED) {
+	std::string s = filename + ".hdr";
+	ret = _open(&d_new_hdr_fp, s.c_str());
+      }
+
+      ret = ret && _open(&d_new_fp, filename.c_str());
+      d_updated = true;
+      return ret;
+    }
+
+    bool
+    file_meta_sink_impl::_open(FILE **fp, const char *filename)
+    {
+      gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
+
+      bool ret = true;
+      int fd;
+
+      if((fd = ::open(filename,
+		      O_WRONLY|O_CREAT|O_TRUNC|OUR_O_LARGEFILE|OUR_O_BINARY,
+		      0664)) < 0){
+	perror(filename);
+	return false;
+      }
+
+      if(*fp) {		// if we've already got a new one open, close it
+	fclose(*fp);
+	fp = 0;
+      }
+
+      if((*fp = fdopen(fd, "wb")) == NULL) {
+	perror(filename);
+	::close(fd);		// don't leak file descriptor if fdopen fails.
+      }
+
+      ret = fp != 0;
+
+      return ret;
+    }
+
+    void
+    file_meta_sink_impl::close()
+    {
+      gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
+      update_last_header();
+
+      if(d_state == STATE_DETACHED) {
+	if(d_new_hdr_fp) {
+	  fclose(d_new_hdr_fp);
+	  d_new_hdr_fp = 0;
+	}
+      }
+
+      if(d_new_fp) {
+	fclose(d_new_fp);
+	d_new_fp = 0;
+      }
+      d_updated = true;
+    }
+
+    void
+    file_meta_sink_impl::do_update()
+    {
+      if(d_updated) {
+	gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this block
+	if(d_state == STATE_DETACHED) {
+	  if(d_hdr_fp)
+	    fclose(d_hdr_fp);
+	  d_hdr_fp = d_new_hdr_fp;		// install new file pointer
+	  d_new_hdr_fp = 0;
+	}
+
+	if(d_fp)
+	  fclose(d_fp);
+	d_fp = d_new_fp;		// install new file pointer
+	d_new_fp = 0;
+
+	d_updated = false;
+      }
+    }
+
+    void
+    file_meta_sink_impl::write_header(FILE *fp, pmt_t header, pmt_t extra)
+    {
+      std::string header_str = pmt_serialize_str(header);
+      std::string extra_str = pmt_serialize_str(extra);
+
+      if((header_str.size() != METADATA_HEADER_SIZE) && (extra_str.size() != d_extra_size))
+	throw std::runtime_error("file_meta_sink: header or extras is wrong size.\n");
+
+      size_t nwritten = 0;
+      while(nwritten < header_str.size()) {
+	std::string sub = header_str.substr(nwritten);
+	int count = fwrite(sub.c_str(), sizeof(char), sub.size(), fp);
+	nwritten += count;
+	if((count == 0) && (ferror(fp))) {
+	  fclose(fp);
+	  throw std::runtime_error("file_meta_sink: error writing header to file.\n");
+	}
+      }
+
+      nwritten = 0;
+      while(nwritten < extra_str.size()) {
+	std::string sub = extra_str.substr(nwritten);
+	int count = fwrite(sub.c_str(), sizeof(char), sub.size(), fp);
+	nwritten += count;
+	if((count == 0) && (ferror(fp))) {
+	  fclose(fp);
+	  throw std::runtime_error("file_meta_sink: error writing extra to file.\n");
+	}
+      }
+
+      fflush(fp);
+    }
+
+    void
+    file_meta_sink_impl::update_header(pmt_t key, pmt_t value)
+    {
+      // Special handling caveat to transform rate from radio source into
+      // the rate at this sink.
+      if(pmt_eq(key, mp("rx_rate"))) {
+	d_samp_rate = pmt_to_double(value);
+	value = pmt_from_double(d_samp_rate*d_relative_rate);
+      }
+
+      // If the tag is not part of the standard header, we put it into the
+      // extra data, which either updates the current dictionary or adds a
+      // new item.
+      if(pmt_dict_has_key(d_header, key)) {
+	d_header = pmt_dict_add(d_header, key, value);
+      }
+      else {
+	d_extra = pmt_dict_add(d_extra, key, value);
+	d_extra_size = pmt_serialize_str(d_extra).size();
+      }
+    }
+
+    void
+    file_meta_sink_impl::update_last_header()
+    {
+      if(d_state == STATE_DETACHED)
+	update_last_header_detached();
+      else
+	update_last_header_inline();
+    }
+
+    void
+    file_meta_sink_impl::update_last_header_inline()
+    {
+      // Update the last header info with the number of samples this
+      // block represents.
+
+      size_t hdrlen = pmt_to_uint64(pmt_dict_ref(d_header, mp("strt"), PMT_NIL));
+      size_t seg_size = d_itemsize*d_total_seg_size;
+      pmt_t s = pmt_from_uint64(seg_size);
+      update_header(mp("bytes"), s);
+      update_header(mp("strt"), pmt_from_uint64(METADATA_HEADER_SIZE+d_extra_size));
+      fseek(d_fp, -seg_size-hdrlen, SEEK_CUR);
+      write_header(d_fp, d_header, d_extra);
+      fseek(d_fp, seg_size, SEEK_CUR);
+    }
+
+    void
+    file_meta_sink_impl::update_last_header_detached()
+    {
+      // Update the last header info with the number of samples this
+      // block represents.
+      size_t hdrlen = pmt_to_uint64(pmt_dict_ref(d_header, mp("strt"), PMT_NIL));
+      size_t seg_size = d_itemsize*d_total_seg_size;
+      pmt_t s = pmt_from_uint64(seg_size);
+      update_header(mp("bytes"), s);
+      update_header(mp("strt"), pmt_from_uint64(METADATA_HEADER_SIZE+d_extra_size));
+      fseek(d_hdr_fp, -hdrlen, SEEK_CUR);
+      write_header(d_hdr_fp, d_header, d_extra);
+    }
+
+    void
+    file_meta_sink_impl::write_and_update()
+    {
+      // New header, so set current size of chunk to 0 and start of chunk
+      // based on current index + header size.
+      //uint64_t loc = get_last_header_loc();
+      pmt_t s = pmt_from_uint64(0);
+      update_header(mp("bytes"), s);
+
+      // If we have multiple tags on the same offset, this makes
+      // sure we just overwrite the same header each time instead
+      // of creating a new header per tag.
+      s = pmt_from_uint64(METADATA_HEADER_SIZE + d_extra_size);
+      update_header(mp("strt"), s);
+
+      if(d_state == STATE_DETACHED)
+	write_header(d_hdr_fp, d_header, d_extra);
+      else
+	write_header(d_fp, d_header, d_extra);
+    }
+
+    void
+    file_meta_sink_impl::update_rx_time()
+    {
+      pmt_t rx_time = pmt_string_to_symbol("rx_time");
+      pmt_t r = pmt_dict_ref(d_header, rx_time, PMT_NIL);
+      uint64_t secs = pmt_to_uint64(pmt_tuple_ref(r, 0));
+      double fracs = pmt_to_double(pmt_tuple_ref(r, 1));
+      double diff = d_total_seg_size / (d_samp_rate*d_relative_rate);
+
+      //std::cerr << "old secs:  " << secs << std::endl;
+      //std::cerr << "old fracs: " << fracs << std::endl;
+      //std::cerr << "seg size:  " << d_total_seg_size << std::endl;
+      //std::cerr << "diff:      " << diff << std::endl;
+
+      fracs += diff;
+      uint64_t new_secs = static_cast<uint64_t>(fracs);
+      secs += new_secs;
+      fracs -= new_secs;
+
+      //std::cerr << "new secs:  " << secs << std::endl;
+      //std::cerr << "new fracs: " << fracs << std::endl << std::endl;
+
+      r = pmt_make_tuple(pmt_from_uint64(secs), pmt_from_double(fracs));
+      d_header = pmt_dict_add(d_header, rx_time, r);
+    }
+
+    int
+    file_meta_sink_impl::work(int noutput_items,
+			      gr_vector_const_void_star &input_items,
+			      gr_vector_void_star &output_items)
+    {
+      char *inbuf = (char*)input_items[0];
+      int  nwritten = 0;
+
+      do_update();				// update d_fp is reqd
+
+      if(!d_fp)
+	return noutput_items;		// drop output on the floor
+
+      uint64_t abs_N = nitems_read(0);
+      uint64_t end_N = abs_N + (uint64_t)(noutput_items);
+      std::vector<gr_tag_t> all_tags;
+      get_tags_in_range(all_tags, 0, abs_N, end_N);
+
+      std::vector<gr_tag_t>::iterator itr;
+      for(itr = all_tags.begin(); itr != all_tags.end(); itr++) {
+	int item_offset = (int)(itr->offset - abs_N);
+
+	// Write date to file up to the next tag location
+	while(nwritten < item_offset) {
+	  size_t towrite = std::min(d_max_seg_size - d_total_seg_size,
+				    (size_t)(item_offset - nwritten));
+	  int count = fwrite(inbuf, d_itemsize, towrite, d_fp);
+	  if(count == 0)	// FIXME add error handling
+	    break;
+	  nwritten += count;
+	  inbuf += count * d_itemsize;
+
+	  d_total_seg_size += count;
+
+	  // Only add a new header if we are not at the position of the
+	  // next tag
+	  if((d_total_seg_size == d_max_seg_size) &&
+	     (nwritten < item_offset)) {
+	    update_last_header();
+	    update_rx_time();
+	    write_and_update();
+	    d_total_seg_size = 0;
+	  }
+	}
+
+	if(d_total_seg_size > 0) {
+	  update_last_header();
+	  update_header(itr->key, itr->value);
+	  write_and_update();
+	  d_total_seg_size = 0;
+	}
+	else {
+	  update_header(itr->key, itr->value);
+	  update_last_header();
+	}
+      }
+
+      // Finish up the rest of the data after tags
+      while(nwritten < noutput_items) {
+	size_t towrite = std::min(d_max_seg_size - d_total_seg_size,
+				  (size_t)(noutput_items - nwritten));
+	int count = fwrite(inbuf, d_itemsize, towrite, d_fp);
+	if(count == 0)	// FIXME add error handling
+	  break;
+	nwritten += count;
+	inbuf += count * d_itemsize;
+
+	d_total_seg_size += count;
+	if(d_total_seg_size == d_max_seg_size) {
+	  update_last_header();
+	  update_rx_time();
+	  write_and_update();
+	  d_total_seg_size = 0;
+	}
+      }
+
+      if(d_unbuffered)
+	fflush(d_fp);
+
+      return nwritten;
+    }
+
+  } /* namespace blocks */
+} /* namespace gr */
diff --git a/gr-blocks/lib/file_meta_sink_impl.h b/gr-blocks/lib/file_meta_sink_impl.h
new file mode 100644
index 0000000000..566c997b3d
--- /dev/null
+++ b/gr-blocks/lib/file_meta_sink_impl.h
@@ -0,0 +1,96 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_BLOCKS_FILE_META_SINK_IMPL_H
+#define INCLUDED_BLOCKS_FILE_META_SINK_IMPL_H
+
+#include <blocks/file_meta_sink.h>
+#include <gruel/pmt.h>
+#include <gruel/thread.h>
+
+using namespace pmt;
+
+namespace gr {
+  namespace blocks {
+
+    class file_meta_sink_impl : public file_meta_sink
+    {
+    private:
+      enum meta_state_t {
+	STATE_INLINE=0,
+	STATE_DETACHED
+      };
+
+      size_t d_itemsize;
+      double d_samp_rate;
+      double d_relative_rate;
+      size_t d_max_seg_size;
+      size_t d_total_seg_size;
+      pmt_t d_header;
+      pmt_t d_extra;
+      size_t d_extra_size;
+      bool d_updated;
+      bool d_unbuffered;
+
+      boost::mutex d_mutex;
+      FILE *d_new_fp, *d_new_hdr_fp;
+      FILE *d_fp, *d_hdr_fp;
+      meta_state_t d_state;
+
+    protected:
+      void write_header(FILE *fp, pmt_t header, pmt_t extra);
+      void update_header(pmt_t key, pmt_t value);
+      void update_last_header();
+      void update_last_header_inline();
+      void update_last_header_detached();
+      void write_and_update();
+      void update_rx_time();
+
+      bool _open(FILE **fp, const char *filename);
+
+    public:
+      file_meta_sink_impl(size_t itemsize, const std::string &filename,
+			  double samp_rate=1, double relative_rate=1,
+			  gr_file_types type=GR_FILE_FLOAT, bool complex=true,
+			  size_t max_segment_size=1000000,
+			  const std::string &extra_dict="",
+			  bool detached_header=false);
+      ~file_meta_sink_impl();
+
+      bool open(const std::string &filename);
+      void close();
+      void do_update();
+
+      void set_unbuffered(bool unbuffered)
+      {
+	d_unbuffered = unbuffered;
+      }
+
+      int work(int noutput_items,
+	       gr_vector_const_void_star &input_items,
+	       gr_vector_void_star &output_items);
+    };
+
+  } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_BLOCKS_FILE_META_SINK_IMPL_H */
diff --git a/gr-blocks/lib/file_meta_source_impl.cc b/gr-blocks/lib/file_meta_source_impl.cc
new file mode 100644
index 0000000000..fb39b205b4
--- /dev/null
+++ b/gr-blocks/lib/file_meta_source_impl.cc
@@ -0,0 +1,433 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "file_meta_source_impl.h"
+#include <gr_io_signature.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdexcept>
+#include <cstdio>
+
+namespace gr {
+  namespace blocks {
+
+// win32 (mingw/msvc) specific
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+#ifdef O_BINARY
+#define	OUR_O_BINARY O_BINARY
+#else
+#define	OUR_O_BINARY 0
+#endif
+
+// should be handled via configure
+#ifdef O_LARGEFILE
+#define	OUR_O_LARGEFILE	O_LARGEFILE
+#else
+#define	OUR_O_LARGEFILE 0
+#endif
+
+    file_meta_source::sptr
+    file_meta_source::make(const std::string &filename,
+			   bool repeat,
+			   bool detached_header,
+			   const std::string &hdr_filename)
+    {
+      return gnuradio::get_initial_sptr
+	(new file_meta_source_impl(filename,
+				   repeat,
+				   detached_header,
+				   hdr_filename));
+    }
+
+    file_meta_source_impl::file_meta_source_impl(const std::string &filename,
+						 bool repeat,
+						 bool detached_header,
+						 const std::string &hdr_filename)
+      : gr_sync_block("file_meta_source",
+		      gr_make_io_signature(0, 0, 0),
+		      gr_make_io_signature(1, 1, 1)),
+	d_itemsize(0), d_samp_rate(0),
+	d_seg_size(0),
+	d_updated(false), d_repeat(repeat)
+    {
+      d_fp = 0;
+      d_new_fp = 0;
+      d_hdr_fp = 0;
+      d_new_hdr_fp = 0;
+
+      if(detached_header == true) {
+	d_state = STATE_DETACHED;
+      }
+      else
+	d_state = STATE_INLINE;
+
+      if(!open(filename, hdr_filename))
+	throw std::runtime_error("file_meta_source: can't open file\n");
+
+      do_update();
+
+      pmt_t hdr = PMT_NIL, extras = PMT_NIL;
+      if(read_header(hdr, extras)) {
+	parse_header(hdr, 0, d_tags);
+	parse_extras(extras, 0, d_tags);
+      }
+      else
+	throw std::runtime_error("file_meta_source: could not read header.\n");
+
+      // Set output signature based on itemsize info in header
+      set_output_signature(gr_make_io_signature(1, 1, d_itemsize));
+    }
+
+    file_meta_source_impl::~file_meta_source_impl()
+    {
+      close();
+
+      if(d_fp) {
+	fclose(d_fp);
+	d_fp = 0;
+      }
+  
+      if(d_state == STATE_DETACHED) {
+	if(d_hdr_fp) {
+	  fclose(d_hdr_fp);
+	  d_hdr_fp = 0;
+	}
+      }
+    }
+
+    bool
+    file_meta_source_impl::read_header(pmt_t &hdr, pmt_t &extras)
+    {
+      // Select which file handle to read from.
+      FILE *fp;
+      if(d_state == STATE_DETACHED)
+	fp = d_hdr_fp;
+      else
+	fp = d_fp;
+
+      size_t ret;
+      size_t size = 0;
+      std::string str;
+      char *hdr_buffer = new char[METADATA_HEADER_SIZE];
+      while(size < METADATA_HEADER_SIZE) {
+	ret = fread(&hdr_buffer[size], sizeof(char), METADATA_HEADER_SIZE-size, fp);
+	if(ret == 0) {
+	  delete [] hdr_buffer;
+	  if(feof(fp))
+	    return false;
+	  else {
+	    std::stringstream s;
+	    s << "file_meta_source: error occurred extracting header: "
+	      << strerror(errno) << std::endl;
+	    throw std::runtime_error(s.str());
+	  }
+	}
+	size += ret;
+      }
+
+      // Convert to string or the char array gets confused by the \0
+      str.insert(0, hdr_buffer, METADATA_HEADER_SIZE);
+      hdr = pmt_deserialize_str(str);
+      delete [] hdr_buffer;
+
+      uint64_t seg_start, extra_len;
+      pmt_t r, dump;
+      if(pmt_dict_has_key(hdr, pmt_string_to_symbol("strt"))) {
+	r = pmt_dict_ref(hdr, pmt_string_to_symbol("strt"), dump);
+	seg_start = pmt_to_uint64(r);
+	extra_len = seg_start - METADATA_HEADER_SIZE;
+      }
+
+      if(extra_len > 0) {
+	size = 0;
+	hdr_buffer = new char[extra_len];
+	while(size < extra_len) {
+	  ret = fread(&hdr_buffer[size], sizeof(char), extra_len-size, fp);
+	  if(ret == 0) {
+	    delete [] hdr_buffer;
+	    if(feof(fp))
+	      return false;
+	    else {
+	      std::stringstream s;
+	      s << "file_meta_source: error occurred extracting extras: "
+		<< strerror(errno) << std::endl;
+	      throw std::runtime_error(s.str());
+	    }
+	  }
+	  size += ret;
+	}
+
+	str.clear();
+	str.insert(0, hdr_buffer, extra_len);
+	extras = pmt_deserialize_str(str);
+	delete [] hdr_buffer;
+      }
+
+      return true;
+    }
+
+    void
+    file_meta_source_impl::parse_header(pmt_t hdr, uint64_t offset,
+					std::vector<gr_tag_t> &tags)
+    {
+      pmt_t r, key;
+
+      // GET SAMPLE RATE
+      key = pmt_string_to_symbol("rx_rate");
+      if(pmt_dict_has_key(hdr, key)) {
+	r = pmt_dict_ref(hdr, key, PMT_NIL);
+	d_samp_rate = pmt_to_double(r);
+
+	gr_tag_t t;
+	t.offset = offset;
+	t.key = key;
+	t.value = r;
+	t.srcid = alias_pmt();
+	tags.push_back(t);
+      }
+      else {
+	throw std::runtime_error("file_meta_source: Could not extract sample rate.\n");
+      }
+
+      // GET TIME STAMP
+      key = pmt_string_to_symbol("rx_time");
+      if(pmt_dict_has_key(hdr, key)) {
+	d_time_stamp = pmt_dict_ref(hdr, key, PMT_NIL);
+
+	gr_tag_t t;
+	t.offset = offset;
+	t.key = key;
+	t.value = d_time_stamp;
+	t.srcid = alias_pmt();
+	tags.push_back(t);
+      }
+      else {
+	throw std::runtime_error("file_meta_source: Could not extract time stamp.\n");
+      }
+
+      // GET ITEM SIZE OF DATA
+      if(pmt_dict_has_key(hdr, pmt_string_to_symbol("size"))) {
+	d_itemsize = pmt_to_long(pmt_dict_ref(hdr, pmt_string_to_symbol("size"), PMT_NIL));
+      }
+      else {
+	throw std::runtime_error("file_meta_source: Could not extract item size.\n");
+      }
+
+      // GET SEGMENT SIZE
+      if(pmt_dict_has_key(hdr, pmt_string_to_symbol("bytes"))) {
+	d_seg_size = pmt_to_uint64(pmt_dict_ref(hdr, pmt_string_to_symbol("bytes"), PMT_NIL));
+
+	// Convert from bytes to items
+	d_seg_size /= d_itemsize;
+      }
+      else {
+	throw std::runtime_error("file_meta_source: Could not extract segment size.\n");
+      }
+    }
+
+    void
+    file_meta_source_impl::parse_extras(pmt_t extras, uint64_t offset,
+					std::vector<gr_tag_t> &tags)
+    {
+      pmt_t item, key, val;
+
+      size_t nitems = pmt_length(extras);
+      for(size_t i = 0; i < nitems; i++) {
+	item = pmt_nth(i, extras);
+	key = pmt_car(item);
+	val = pmt_cdr(item);
+
+	gr_tag_t t;
+	t.offset = offset;
+	t.key = key;
+	t.value = val;
+	t.srcid = alias_pmt();
+	tags.push_back(t);
+      }
+    }
+
+    bool
+    file_meta_source_impl::open(const std::string &filename,
+				const std::string &hdr_filename)
+    {
+      bool ret = true;
+      if(d_state == STATE_DETACHED) {
+	std::string s;
+	if(hdr_filename == "")
+	  s = filename + ".hdr";
+	else
+	  s = hdr_filename;
+	ret = _open(&d_new_hdr_fp, s.c_str());
+      }
+
+      ret = ret && _open(&d_new_fp, filename.c_str());
+      d_updated = true;
+      return ret;
+    }
+
+    bool
+    file_meta_source_impl::_open(FILE **fp, const char *filename)
+    {
+      gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
+
+      bool ret = true;
+      int fd;
+
+      if((fd = ::open(filename,
+		      O_RDONLY|OUR_O_LARGEFILE|OUR_O_BINARY)) < 0) {
+	perror(filename);
+	return false;
+      }
+
+      if(*fp) {		// if we've already got a new one open, close it
+	fclose(*fp);
+	fp = 0;
+      }
+
+      if((*fp = fdopen(fd, "rb")) == NULL) {
+	perror(filename);
+	::close(fd);		// don't leak file descriptor if fdopen fails.
+      }
+
+      ret = fp != 0;
+
+      return ret;
+    }
+
+    void
+    file_meta_source_impl::close()
+    {
+      gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
+      if(d_state == STATE_DETACHED) {
+	if(d_new_hdr_fp) {
+	  fclose(d_new_hdr_fp);
+	  d_new_hdr_fp = 0;
+	}
+      }
+
+      if(d_new_fp) {
+	fclose(d_new_fp);
+	d_new_fp = 0;
+      }
+      d_updated = true;
+    }
+
+    void
+    file_meta_source_impl::do_update()
+    {
+      if(d_updated) {
+	gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this block
+	if(d_state == STATE_DETACHED) {
+	  if(d_hdr_fp)
+	    fclose(d_hdr_fp);
+	  d_hdr_fp = d_new_hdr_fp;		// install new file pointer
+	  d_new_hdr_fp = 0;
+	}
+
+	if(d_fp)
+	  fclose(d_fp);
+	d_fp = d_new_fp;		// install new file pointer
+	d_new_fp = 0;
+
+	d_updated = false;
+      }
+    }
+
+    int
+    file_meta_source_impl::work(int noutput_items,
+				gr_vector_const_void_star &input_items,
+				gr_vector_void_star &output_items)
+    {
+      // We've reached the end of a segment; parse the next header and get
+      // the new tags to send and set the next segment size.
+      if(d_seg_size == 0) {
+	pmt_t hdr=PMT_NIL, extras=PMT_NIL;
+	if(read_header(hdr, extras)) {
+	  parse_header(hdr, nitems_written(0), d_tags);
+	  parse_extras(extras, nitems_written(0), d_tags);
+	}
+	else {
+	  return -1;
+	}
+      }
+
+      char *out = (char*)output_items[0];
+      int i;
+      int seg_size = std::min(noutput_items, (int)d_seg_size);
+      int size = seg_size;
+
+      do_update();       // update d_fp is reqd
+      if(d_fp == NULL)
+	throw std::runtime_error("work with file not open");
+
+      // Push all tags onto the stream and remove them from the vector
+      while(!d_tags.empty()) {
+	add_item_tag(0, d_tags.back());
+	d_tags.pop_back();
+      }
+
+      gruel::scoped_lock lock(d_mutex); // hold for the rest of this function
+      while(size) {
+	i = fread(out, d_itemsize, size, d_fp);
+
+	size -= i;
+	d_seg_size -= i;
+	out += i * d_itemsize;
+
+	if(size == 0)		// done
+	  break;
+
+	if(i > 0)			// short read, try again
+	  continue;
+
+	// We got a zero from fread.  This is either EOF or error.  In
+	// any event, if we're in repeat mode, seek back to the beginning
+	// of the file and try again, else break
+
+	if(!d_repeat)
+	  break;
+
+	if(fseek(d_fp, 0, SEEK_SET) == -1) {
+	  std::stringstream s;
+	  s << "[" << __FILE__ << "]" << " fseek failed" << std::endl;
+	  throw std::runtime_error(s.str());
+	}
+      }
+
+      if(size > 0) {			// EOF or error
+	if(size == seg_size)		// we didn't read anything; say we're done
+	  return -1;
+	return seg_size - size;	// else return partial result
+      }
+
+      return seg_size;
+    }
+
+  } /* namespace blocks */
+} /* namespace gr */
diff --git a/gr-blocks/lib/file_meta_source_impl.h b/gr-blocks/lib/file_meta_source_impl.h
new file mode 100644
index 0000000000..ca7ddc6e10
--- /dev/null
+++ b/gr-blocks/lib/file_meta_source_impl.h
@@ -0,0 +1,89 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_BLOCKS_FILE_META_SOURCE_IMPL_H
+#define INCLUDED_BLOCKS_FILE_META_SOURCE_IMPL_H
+
+#include <blocks/file_meta_source.h>
+#include <gr_tags.h>
+#include <gruel/pmt.h>
+#include <gruel/thread.h>
+
+#include <blocks/file_meta_sink.h>
+
+using namespace pmt;
+
+namespace gr {
+  namespace blocks {
+
+    class file_meta_source_impl : public file_meta_source
+    {
+    private:
+      enum meta_state_t {
+	STATE_INLINE=0,
+	STATE_DETACHED
+      };
+
+      size_t d_itemsize;
+      double d_samp_rate;
+      pmt_t d_time_stamp;
+      size_t d_seg_size;
+      bool d_updated;
+      bool d_repeat;
+
+      gruel::mutex d_mutex;
+      FILE *d_new_fp, *d_new_hdr_fp;
+      FILE *d_fp, *d_hdr_fp;
+      meta_state_t d_state;
+
+      std::vector<gr_tag_t> d_tags;
+
+    protected:
+      bool _open(FILE **fp, const char *filename);
+      bool read_header(pmt_t &hdr, pmt_t &extras);
+      void parse_header(pmt_t hdr, uint64_t offset,
+			std::vector<gr_tag_t> &tags);
+      void parse_extras(pmt_t extras, uint64_t offset,
+			std::vector<gr_tag_t> &tags);
+
+    public:
+      file_meta_source_impl(const std::string &filename,
+			    bool repeat=false,
+			    bool detached_header=false,
+			    const std::string &hdr_filename="");
+
+      ~file_meta_source_impl();
+
+      bool open(const std::string &filename,
+		const std::string &hdr_filename="");
+      void close();
+      void do_update();
+
+      int work(int noutput_items,
+	       gr_vector_const_void_star &input_items,
+	       gr_vector_void_star &output_items);
+    };
+
+  } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_BLOCKS_FILE_META_SOURCE_IMPL_H */
diff --git a/gr-blocks/python/CMakeLists.txt b/gr-blocks/python/CMakeLists.txt
index 710ab155ce..cab0b956f7 100644
--- a/gr-blocks/python/CMakeLists.txt
+++ b/gr-blocks/python/CMakeLists.txt
@@ -23,6 +23,7 @@ include(GrPython)
 GR_PYTHON_INSTALL(
     FILES
     __init__.py
+    parse_file_metadata.py
     DESTINATION ${GR_PYTHON_DIR}/gnuradio/blocks
     COMPONENT "blocks_python"
 )
diff --git a/gr-blocks/python/parse_file_metadata.py b/gr-blocks/python/parse_file_metadata.py
new file mode 100644
index 0000000000..ec7bf6e804
--- /dev/null
+++ b/gr-blocks/python/parse_file_metadata.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import sys
+from gnuradio import gr
+from gruel import pmt
+
+try:
+    import blocks_swig as blocks
+except:
+    from gnuradio import blocks
+
+'''
+sr    Sample rate (samples/second)
+time  Time as uint64(secs), double(fractional secs)
+type  Type of data (see gr_file_types enum)
+cplx  is complex? (True or False)
+strt  Start of data (or size of header) in bytes
+size  Size of data in bytes
+'''
+
+HEADER_LENGTH = blocks.METADATA_HEADER_SIZE
+
+ftype_to_string = {blocks.GR_FILE_BYTE: "bytes",
+                   blocks.GR_FILE_SHORT: "short",
+                   blocks.GR_FILE_INT: "int",
+                   blocks.GR_FILE_LONG: "long",
+                   blocks.GR_FILE_LONG_LONG: "long long",
+                   blocks.GR_FILE_FLOAT: "float",
+                   blocks.GR_FILE_DOUBLE: "double" }
+
+ftype_to_size = {blocks.GR_FILE_BYTE: gr.sizeof_char,
+                 blocks.GR_FILE_SHORT: gr.sizeof_short,
+                 blocks.GR_FILE_INT: gr.sizeof_int,
+                 blocks.GR_FILE_LONG: gr.sizeof_int,
+                 blocks.GR_FILE_LONG_LONG: 2*gr.sizeof_int,
+                 blocks.GR_FILE_FLOAT: gr.sizeof_float,
+                 blocks.GR_FILE_DOUBLE: gr.sizeof_double}
+
+def parse_header(p, VERBOSE=False):
+    dump = pmt.PMT_NIL
+
+    info = dict()
+
+    if(pmt.pmt_is_dict(p) is False):
+        sys.stderr.write("Header is not a PMT dictionary: invalid or corrupt data file.\n")
+        sys.exit(1)
+
+    # GET FILE FORMAT VERSION NUMBER
+    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("version"))):
+        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("version"), dump)
+        version = pmt.pmt_to_long(r)
+        if(VERBOSE):
+            print "Version Number: {0}".format(version)
+    else:
+        sys.stderr.write("Could not find key 'sr': invalid or corrupt data file.\n")
+        sys.exit(1)
+
+    # EXTRACT SAMPLE RATE
+    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("rx_rate"))):
+        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("rx_rate"), dump)
+        samp_rate = pmt.pmt_to_double(r)
+        info["rx_rate"] = samp_rate
+        if(VERBOSE):
+            print "Sample Rate: {0:.2f} sps".format(samp_rate)
+    else:
+        sys.stderr.write("Could not find key 'sr': invalid or corrupt data file.\n")
+        sys.exit(1)
+
+    # EXTRACT TIME STAMP
+    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("rx_time"))):
+        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("rx_time"), dump)
+        pmt_secs = pmt.pmt_tuple_ref(r, 0)
+        pmt_fracs = pmt.pmt_tuple_ref(r, 1)
+        secs = float(pmt.pmt_to_uint64(pmt_secs))
+        fracs = pmt.pmt_to_double(pmt_fracs)
+        t = secs + fracs
+        info["rx_time"] = t
+        if(VERBOSE):
+            print "Seconds: {0:.6f}".format(t)
+    else:
+        sys.stderr.write("Could not find key 'time': invalid or corrupt data file.\n")
+        sys.exit(1)
+
+    # EXTRACT ITEM SIZE
+    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("size"))):
+        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("size"), dump)
+        dsize = pmt.pmt_to_long(r)
+        info["size"] = dsize
+        if(VERBOSE):
+            print "Item size: {0}".format(dsize)
+    else:
+        sys.stderr.write("Could not find key 'size': invalid or corrupt data file.\n")
+        sys.exit(1)
+
+    # EXTRACT DATA TYPE
+    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("type"))):
+        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("type"), dump)
+        dtype = pmt.pmt_to_long(r)
+        stype = ftype_to_string[dtype]
+        info["type"] = stype
+        if(VERBOSE):
+            print "Data Type: {0} ({1})".format(stype, dtype)
+    else:
+        sys.stderr.write("Could not find key 'type': invalid or corrupt data file.\n")
+        sys.exit(1)
+
+    # EXTRACT COMPLEX
+    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("cplx"))):
+        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("cplx"), dump)
+        cplx = pmt.pmt_to_bool(r)
+        info["cplx"] = cplx
+        if(VERBOSE):
+            print "Complex? {0}".format(cplx)
+    else:
+        sys.stderr.write("Could not find key 'cplx': invalid or corrupt data file.\n")
+        sys.exit(1)
+
+    # EXTRACT WHERE CURRENT SEGMENT STARTS
+    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("strt"))):
+        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("strt"), dump)
+        seg_start = pmt.pmt_to_uint64(r)
+        info["hdr_len"] = seg_start
+        info["extra_len"] = seg_start - HEADER_LENGTH
+        info["has_extra"] = info["extra_len"] > 0
+        if(VERBOSE):
+            print "Header Length: {0} bytes".format(info["hdr_len"])
+            print "Extra Length:  {0}".format((info["extra_len"]))
+            print "Extra Header?  {0}".format(info["has_extra"])
+    else:
+        sys.stderr.write("Could not find key 'strt': invalid or corrupt data file.\n")
+        sys.exit(1)
+
+    # EXTRACT SIZE OF DATA
+    if(pmt.pmt_dict_has_key(p, pmt.pmt_string_to_symbol("bytes"))):
+        r = pmt.pmt_dict_ref(p, pmt.pmt_string_to_symbol("bytes"), dump)
+        nbytes = pmt.pmt_to_uint64(r)
+
+        nitems = nbytes/dsize
+        info["nitems"] = nitems
+        info["nbytes"] = nbytes
+
+        if(VERBOSE):
+            print "Size of Data: {0} bytes".format(nbytes)
+            print "              {0} items".format(nitems)
+    else:
+        sys.stderr.write("Could not find key 'size': invalid or corrupt data file.\n")
+        sys.exit(1)
+
+    return info
+
+# IF THERE IS EXTRA DATA, PULL OUT THE DICTIONARY AND PARSE IT
+def parse_extra_dict(p, info, VERBOSE=False):
+    if(pmt.pmt_is_dict(p) is False):
+        sys.stderr.write("Extra header is not a PMT dictionary: invalid or corrupt data file.\n")
+        sys.exit(1)
+
+    items = pmt.pmt_dict_items(p)
+    nitems = pmt.pmt_length(items)
+    for i in xrange(nitems):
+        item = pmt.pmt_nth(i, items)
+        key = pmt.pmt_symbol_to_string(pmt.pmt_car(item))
+        val = pmt.pmt_cdr(item)
+        info[key] = val
+        if(VERBOSE):
+            print "{0}: ".format(key)
+            pmt.pmt_print(val)
+
+    return info
diff --git a/gr-blocks/python/qa_file_metadata.py b/gr-blocks/python/qa_file_metadata.py
new file mode 100644
index 0000000000..9f4a331d65
--- /dev/null
+++ b/gr-blocks/python/qa_file_metadata.py
@@ -0,0 +1,197 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import parse_file_metadata
+import blocks_swig as blocks
+import pmt
+import os, time
+
+class test_file_metadata(gr_unittest.TestCase):
+
+    def setUp(self):
+        self.tb = gr.top_block()
+
+    def tearDown(self):
+        self.tb = None
+
+    def test_001(self):
+	outfile = "test_out.dat"
+
+        detached = False
+        samp_rate = 200000
+        key = pmt.pmt_intern("samp_rate")
+        val = pmt.pmt_from_double(samp_rate)
+        extras = pmt.pmt_make_dict()
+        extras = pmt.pmt_dict_add(extras, key, val)
+        extras_str = pmt.pmt_serialize_str(extras)
+
+        src = gr.sig_source_c(samp_rate, gr.GR_COS_WAVE, 1000, 1, 0)
+        head = gr.head(gr.sizeof_gr_complex, 1000)
+        fsnk = blocks.file_meta_sink(gr.sizeof_gr_complex, outfile,
+                                     samp_rate, 1, 
+                                     blocks.GR_FILE_FLOAT, True,
+                                     1000000, extras_str, detached)
+        fsnk.set_unbuffered(True)
+
+	self.tb.connect(src, head, fsnk)
+	self.tb.run()
+        fsnk.close()
+
+        handle = open(outfile, "rb")
+        header_str = handle.read(parse_file_metadata.HEADER_LENGTH)
+        if(len(header_str) == 0):
+            self.assertFalse()
+
+        try:
+            header = pmt.pmt_deserialize_str(header_str)
+        except RuntimeError:
+            self.assertFalse()
+
+        info = parse_file_metadata.parse_header(header, False)
+
+        extra_str = handle.read(info["extra_len"])
+        self.assertGreater(len(extra_str), 0)
+        handle.close()
+
+        try:
+            extra = pmt.pmt_deserialize_str(extra_str)
+        except RuntimeError:
+            self.assertFalse()
+
+        extra_info = parse_file_metadata.parse_extra_dict(extra, info, False)
+
+        self.assertEqual(info['rx_rate'], samp_rate)
+        self.assertEqual(pmt.pmt_to_double(extra_info['samp_rate']), samp_rate)
+
+
+        # Test file metadata source
+        # Create a new sig source to start from the beginning
+        src2 = gr.sig_source_c(samp_rate, gr.GR_COS_WAVE, 1000, 1, 0)
+        fsrc = blocks.file_meta_source(outfile, False)
+        vsnk = gr.vector_sink_c()
+        tsnk = gr.tag_debug(gr.sizeof_gr_complex, "QA")
+        ssnk = gr.vector_sink_c()
+        head.reset()
+        self.tb.disconnect(src, head, fsnk)
+        self.tb.connect(fsrc, vsnk)
+        self.tb.connect(fsrc, tsnk)
+        self.tb.connect(src2, head, ssnk)
+        self.tb.run()
+
+        # Test to make sure tags with 'samp_rate' and 'rx_rate' keys
+        # were generated and received correctly.
+        tags = tsnk.current_tags()
+        for t in tags:
+            if(pmt.pmt_eq(t.key, pmt.pmt_intern("samp_rate"))):
+                self.assertEqual(pmt.pmt_to_double(t.value), samp_rate)
+            elif(pmt.pmt_eq(t.key, pmt.pmt_intern("rx_rate"))):
+                self.assertEqual(pmt.pmt_to_double(t.value), samp_rate)
+
+        # Test that the data portion was extracted and received correctly.
+        self.assertComplexTuplesAlmostEqual(vsnk.data(), ssnk.data(), 5)
+
+	os.remove(outfile)
+
+    def test_002(self):
+	outfile = "test_out.dat"
+	outfile_hdr = "test_out.dat.hdr"
+
+        detached = True
+        samp_rate = 200000
+        key = pmt.pmt_intern("samp_rate")
+        val = pmt.pmt_from_double(samp_rate)
+        extras = pmt.pmt_make_dict()
+        extras = pmt.pmt_dict_add(extras, key, val)
+        extras_str = pmt.pmt_serialize_str(extras)
+
+        src = gr.sig_source_c(samp_rate, gr.GR_COS_WAVE, 1000, 1, 0)
+        head = gr.head(gr.sizeof_gr_complex, 1000)
+        fsnk = blocks.file_meta_sink(gr.sizeof_gr_complex, outfile,
+                                     samp_rate, 1, 
+                                     blocks.GR_FILE_FLOAT, True,
+                                     1000000, extras_str, detached)
+        fsnk.set_unbuffered(True)
+
+	self.tb.connect(src, head, fsnk)
+	self.tb.run()
+        fsnk.close()
+
+        # Open detached header for reading
+        handle = open(outfile_hdr, "rb")
+        header_str = handle.read(parse_file_metadata.HEADER_LENGTH)
+        if(len(header_str) == 0):
+            self.assertFalse()
+
+        try:
+            header = pmt.pmt_deserialize_str(header_str)
+        except RuntimeError:
+            self.assertFalse()
+
+        info = parse_file_metadata.parse_header(header, False)
+
+        extra_str = handle.read(info["extra_len"])
+        self.assertGreater(len(extra_str), 0)
+        handle.close()
+
+        try:
+            extra = pmt.pmt_deserialize_str(extra_str)
+        except RuntimeError:
+            self.assertFalse()
+
+        extra_info = parse_file_metadata.parse_extra_dict(extra, info, False)
+
+        self.assertEqual(info['rx_rate'], samp_rate)
+        self.assertEqual(pmt.pmt_to_double(extra_info['samp_rate']), samp_rate)
+
+
+        # Test file metadata source
+        # Create a new sig source to start from the beginning
+        src2 = gr.sig_source_c(samp_rate, gr.GR_COS_WAVE, 1000, 1, 0)
+        fsrc = blocks.file_meta_source(outfile, False, detached, outfile_hdr)
+        vsnk = gr.vector_sink_c()
+        tsnk = gr.tag_debug(gr.sizeof_gr_complex, "QA")
+        ssnk = gr.vector_sink_c()
+        head.reset()
+        self.tb.disconnect(src, head, fsnk)
+        self.tb.connect(fsrc, vsnk)
+        self.tb.connect(fsrc, tsnk)
+        self.tb.connect(src2, head, ssnk)
+        self.tb.run()
+
+        # Test to make sure tags with 'samp_rate' and 'rx_rate' keys
+        # were generated and received correctly.
+        tags = tsnk.current_tags()
+        for t in tags:
+            if(pmt.pmt_eq(t.key, pmt.pmt_intern("samp_rate"))):
+                self.assertEqual(pmt.pmt_to_double(t.value), samp_rate)
+            elif(pmt.pmt_eq(t.key, pmt.pmt_intern("rx_rate"))):
+                self.assertEqual(pmt.pmt_to_double(t.value), samp_rate)
+
+        # Test that the data portion was extracted and received correctly.
+        self.assertComplexTuplesAlmostEqual(vsnk.data(), ssnk.data(), 5)
+
+	os.remove(outfile)
+	os.remove(outfile_hdr)
+
+if __name__ == '__main__':
+    gr_unittest.run(test_file_metadata, "test_file_metadata.xml")
diff --git a/gr-blocks/swig/blocks_swig.i b/gr-blocks/swig/blocks_swig.i
index 7ec6bb423f..53eea818fb 100644
--- a/gr-blocks/swig/blocks_swig.i
+++ b/gr-blocks/swig/blocks_swig.i
@@ -62,6 +62,8 @@
 #include "blocks/divide_ii.h"
 #include "blocks/divide_cc.h"
 #include "blocks/file_source.h"
+#include "blocks/file_meta_sink.h"
+#include "blocks/file_meta_source.h"
 #include "blocks/float_to_char.h"
 #include "blocks/float_to_complex.h"
 #include "blocks/float_to_int.h"
@@ -147,6 +149,8 @@
 %include "blocks/conjugate_cc.h"
 %include "blocks/deinterleave.h"
 %include "blocks/file_source.h"
+%include "blocks/file_meta_sink.h"
+%include "blocks/file_meta_source.h"
 %include "blocks/divide_ff.h"
 %include "blocks/divide_ss.h"
 %include "blocks/divide_ii.h"
@@ -239,6 +243,8 @@ GR_SWIG_BLOCK_MAGIC2(blocks, divide_ss);
 GR_SWIG_BLOCK_MAGIC2(blocks, divide_ii);
 GR_SWIG_BLOCK_MAGIC2(blocks, divide_cc);
 GR_SWIG_BLOCK_MAGIC2(blocks, file_source);
+GR_SWIG_BLOCK_MAGIC2(blocks, file_meta_sink);
+GR_SWIG_BLOCK_MAGIC2(blocks, file_meta_source);
 GR_SWIG_BLOCK_MAGIC2(blocks, float_to_char);
 GR_SWIG_BLOCK_MAGIC2(blocks, float_to_complex);
 GR_SWIG_BLOCK_MAGIC2(blocks, float_to_int);
diff --git a/gr-utils/src/python/gr_read_file_metadata b/gr-utils/src/python/gr_read_file_metadata
index efbf8d15d3..cf0cd5b116 100644
--- a/gr-utils/src/python/gr_read_file_metadata
+++ b/gr-utils/src/python/gr_read_file_metadata
@@ -23,8 +23,8 @@
 import sys
 from optparse import OptionParser
 
-from gnuradio import gr
-from gnuradio import parse_file_metadata
+from gruel import pmt
+from gnuradio.blocks import parse_file_metadata
 
 def main(filename, detached=False):
     handle = open(filename, "rb")
@@ -40,7 +40,7 @@ def main(filename, detached=False):
 
         # Convert from string to PMT (should be a dictionary)
         try:
-            header = gr.pmt_deserialize_str(header_str)
+            header = pmt.pmt_deserialize_str(header_str)
         except RuntimeError:
             sys.stderr.write("Could not deserialize header: invalid or corrupt data file.\n")
             sys.exit(1)
@@ -54,7 +54,7 @@ def main(filename, detached=False):
                 break
 
             try:
-                extra = gr.pmt_deserialize_str(extra_str)
+                extra = pmt.pmt_deserialize_str(extra_str)
             except RuntimeError:
                 sys.stderr.write("Could not deserialize extras: invalid or corrupt data file.\n")
                 sys.exit(1)
diff --git a/grc/blocks/block_tree.xml b/grc/blocks/block_tree.xml
index f1c68c7c93..183883959d 100644
--- a/grc/blocks/block_tree.xml
+++ b/grc/blocks/block_tree.xml
@@ -29,8 +29,6 @@
 		<block>gr_vector_sink_x</block>
 		<block>gr_null_sink</block>
 		<block>gr_file_sink</block>
-		<block>gr_file_meta_source</block>
-		<block>gr_file_meta_sink</block>
 		<block>blks2_tcp_sink</block>
 		<block>gr_udp_sink</block>
 		<block>gr_wavfile_sink</block>
diff --git a/grc/blocks/gr_file_meta_sink.xml b/grc/blocks/gr_file_meta_sink.xml
deleted file mode 100644
index ba9bf4ee1c..0000000000
--- a/grc/blocks/gr_file_meta_sink.xml
+++ /dev/null
@@ -1,124 +0,0 @@
-<?xml version="1.0"?>
-<!--
-###################################################
-##File Meta Sink
-###################################################
- -->
-<block>
-	<name>File Meta Sink</name>
-	<key>gr_file_meta_sink</key>
-	<import>from gnuradio import gr</import>
-	<make>gr.file_meta_sink($type.size*$vlen, $file, $samp_rate, $rel_rate, $type.dtype, $type.cplx, $max_seg_size, $extra_dict, $detached)
-self.$(id).set_unbuffered($unbuffered)</make>
-	<callback>set_unbuffered($unbuffered)</callback>
-	<callback>open($file)</callback>
-	<param>
-		<name>File</name>
-		<key>file</key>
-		<value></value>
-		<type>file_save</type>
-	</param>
-	<param>
-		<name>Input Type</name>
-		<key>type</key>
-		<type>enum</type>
-		<option>
-			<name>Complex</name>
-			<key>complex</key>
-			<opt>size:gr.sizeof_gr_complex</opt>
-			<opt>dtype:gr.GR_FILE_FLOAT</opt>
-			<opt>cplx:True</opt>
-		</option>
-		<option>
-			<name>Float</name>
-			<key>float</key>
-			<opt>size:gr.sizeof_float</opt>
-			<opt>dtype:gr.GR_FILE_FLOAT</opt>
-			<opt>cplx:False</opt>
-		</option>
-		<option>
-			<name>Int</name>
-			<key>int</key>
-			<opt>size:gr.sizeof_int</opt>
-			<opt>dtype:gr.GR_FILE_INT</opt>
-			<opt>cplx:False</opt>
-		</option>
-		<option>
-			<name>Short</name>
-			<key>short</key>
-			<opt>size:gr.sizeof_short</opt>
-			<opt>dtype:gr.GR_FILE_SHORT</opt>
-			<opt>cplx:False</opt>
-		</option>
-		<option>
-			<name>Byte</name>
-			<key>byte</key>
-			<opt>size:gr.sizeof_char</opt>
-			<opt>dtype:gr.GR_FILE_BYTE</opt>
-			<opt>cplx:False</opt>
-		</option>
-	</param>
-	<param>
-		<name>Sample Rate</name>
-		<key>samp_rate</key>
-		<value>samp_rate</value>
-		<type>real</type>
-	</param>
-	<param>
-		<name>Relative Rate Change</name>
-		<key>rel_rate</key>
-		<value>1</value>
-		<type>real</type>
-	</param>
-	<param>
-		<name>Vec Length</name>
-		<key>vlen</key>
-		<value>1</value>
-		<type>int</type>
-	</param>
-	<param>
-		<name>Max Seg. Size</name>
-		<key>max_seg_size</key>
-		<value>1000000</value>
-		<type>int</type>
-	</param>
-	<param>
-		<name>Extra Dict.</name>
-		<key>extra_dict</key>
-		<value>""</value>
-		<type>string</type>
-	</param>
-	<param>
-		<name>Detached</name>
-		<key>detached</key>
-		<value>False</value>
-		<type>bool</type>
-		<option>
-		  <name>Off</name>
-		  <key>False</key>
-		</option>
-		<option>
-		  <name>On</name>
-		  <key>True</key>
-		</option>
-	</param>	<param>
-		<name>Unbuffered</name>
-		<key>unbuffered</key>
-		<value>False</value>
-		<type>bool</type>
-		<option>
-				<name>Off</name>
-				<key>False</key>
-		</option>
-		<option>
-				<name>On</name>
-				<key>True</key>
-		</option>
-	</param>
-	<check>$vlen &gt; 0</check>
-	<sink>
-		<name>in</name>
-		<type>$type</type>
-		<vlen>$vlen</vlen>
-	</sink>
-</block>
diff --git a/grc/blocks/gr_file_meta_source.xml b/grc/blocks/gr_file_meta_source.xml
deleted file mode 100644
index 8f667961e4..0000000000
--- a/grc/blocks/gr_file_meta_source.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0"?>
-<!--
-###################################################
-##File Source
-###################################################
- -->
-<block>
-	<name>File Meta Source</name>
-	<key>gr_file_meta_source</key>
-	<import>from gnuradio import gr</import>
-	<make>gr.file_meta_source($file, $repeat, $detached, $hdr_file)</make>
-	<callback>open($file, $repeat)</callback>
-	<param>
-		<name>Output Type</name>
-		<key>type</key>
-		<type>enum</type>
-		<option>
-			<name>Complex</name>
-			<key>complex</key>
-			<opt>size:gr.sizeof_gr_complex</opt>
-		</option>
-		<option>
-			<name>Float</name>
-			<key>float</key>
-			<opt>size:gr.sizeof_float</opt>
-		</option>
-		<option>
-			<name>Int</name>
-			<key>int</key>
-			<opt>size:gr.sizeof_int</opt>
-		</option>
-		<option>
-			<name>Short</name>
-			<key>short</key>
-			<opt>size:gr.sizeof_short</opt>
-		</option>
-		<option>
-			<name>Byte</name>
-			<key>byte</key>
-			<opt>size:gr.sizeof_char</opt>
-		</option>
-	</param>
-	<param>
-		<name>File</name>
-		<key>file</key>
-		<value></value>
-		<type>file_open</type>
-	</param>
-	<param>
-		<name>Repeat</name>
-		<key>repeat</key>
-		<value>True</value>
-		<type>enum</type>
-		<option>
-			<name>Yes</name>
-			<key>True</key>
-		</option>
-		<option>
-			<name>No</name>
-			<key>False</key>
-		</option>
-	</param>
-	<param>
-		<name>Detached Header</name>
-		<key>detached</key>
-		<value>False</value>
-		<type>enum</type>
-		<option>
-			<name>Yes</name>
-			<key>True</key>
-		</option>
-		<option>
-			<name>No</name>
-			<key>False</key>
-		</option>
-	</param>
-	<param>
-		<name>Header File</name>
-		<key>hdr_file</key>
-		<value></value>
-		<type>file_open</type>
-	</param>
-	<param>
-		<name>Vec Length</name>
-		<key>vlen</key>
-		<value>1</value>
-		<type>int</type>
-	</param>
-	<source>
-		<name>out</name>
-		<type>$type</type>
-		<vlen>$vlen</vlen>
-	</source>
-</block>
-- 
cgit v1.2.3


From c866b5ea38dbabcfa08ae3e9989ad5ddfbebfbbe Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Mon, 17 Dec 2012 11:02:58 -0500
Subject: docs: using full namspace for references in metadata.dox for proper
 linking.

---
 docs/doxygen/other/metadata.dox | 45 +++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 22 deletions(-)

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/metadata.dox b/docs/doxygen/other/metadata.dox
index 9fad7c584c..f867a06f28 100644
--- a/docs/doxygen/other/metadata.dox
+++ b/docs/doxygen/other/metadata.dox
@@ -9,8 +9,8 @@ the system state such as sample rate or if a receiver's frequency are
 not conveyed with the data in the file itself. Header of metadata
 solve this problem.
 
-We write metadata files using blocks::file_meta_sink and read metadata
-files using blocks::file_meta_source.
+We write metadata files using gr::blocks::file_meta_sink and read metadata
+files using gr::blocks::file_meta_source.
 
 Metadata files have headers that carry information about a segment of
 data within the file. The header structure is described in detail in
@@ -88,28 +88,29 @@ keep the sample times exact.
 
 \subsection implementation Implementation
 
-Metadata files are created using file_meta_sink. The default
-behavior is to create a single file with inline headers as
+Metadata files are created using gr::blocks::file_meta_sink. The
+default behavior is to create a single file with inline headers as
 metadata. An option can be set to switch to detached header mode.
 
 Metadata file are read into a flowgraph using
-file_meta_source. This source reads a metadata file, inline by
-default with a settable option to use detached headers. The data from
-the segments is converted into a standard streaming output. The
-'rx_rate' and 'rx_time' and all key:value pairs in the extra header
-are converted into tags and added to the stream tags interface.
+gr::blocks::file_meta_source. This source reads a metadata file,
+inline by default with a settable option to use detached headers. The
+data from the segments is converted into a standard streaming
+output. The 'rx_rate' and 'rx_time' and all key:value pairs in the
+extra header are converted into tags and added to the stream tags
+interface.
 
 
 \section structure Structure
 
 The file metadata consists of a static mandatory header and a dynamic
 optional extras header. Each header is a separate PMT
-dictionary. Headers are created by building a PMT dictionary of
-key:value pairs, then the dictionary is serialized into a string to be
-written to file. The header is always the same length that is
-predetermined by the version of the header (this must be known
-already). The header will then indicate if there is an extra data to
-be extracted as a separate serialized dictionary.
+dictionary. Headers are created by building a PMT dictionary
+(pmt::pmt_make_dict) of key:value pairs, then the dictionary is
+serialized into a string to be written to file. The header is always
+the same length that is predetermined by the version of the header
+(this must be known already). The header will then indicate if there
+is an extra data to be extracted as a separate serialized dictionary.
 
 To work with the PMTs for creating and extracting header information,
 we use PMT operators. For example, we create a simplified version of
@@ -125,7 +126,7 @@ the header in C++ like this:
   std::string hdr_str = pmt_serialize_str(header);
 \endcode
 
-The call to pmt_dict_add adds a new key:value pair to the
+The call to pmt::pmt_dict_add adds a new key:value pair to the
 dictionary. Notice that it both takes and returns the 'header'
 variable. This is because we are actually creating a new dictionary
 with this function, so we just assign it to the same variable.
@@ -133,10 +134,10 @@ with this function, so we just assign it to the same variable.
 The 'mp' functions are convenience functions provided by the PMT
 library. They interpret the data type of the value being inserted and
 call the correct 'pmt_from_xxx' function. For more direct control over
-the data type, see PMT functions in pmt.h, such as pmt_from_uint64 or
-pmt_from_double.
+the data type, see PMT functions in pmt.h, such as
+pmt::pmt_from_uint64 or pmt::pmt_from_double.
 
-We finish this off by using 'pmt_serialize_str' to convert the PMT
+We finish this off by using pmt::pmt_serialize_str to convert the PMT
 dictionary into a specialized string format that makes it easy to
 write to a file.
 
@@ -189,7 +190,7 @@ must be the same length and structure. As of now, we only have version
 
 - version: (char) version number (usually set to METADATA_VERSION)
 - rx_rate: (double) Stream's sample rate
-- rx_time: (pmt_t pair - (uint64_t, double)) Time stamp (format from UHD)
+- rx_time: (pmt::pmt_t pair - (uint64_t, double)) Time stamp (format from UHD)
 - size: (int) item size in bytes - reflects vector length if any.
 - type: (int) data type (enum below)
 - cplx: (bool) true if data is complex
@@ -220,7 +221,7 @@ a PMT dictionary of key:value pairs. The extras header can contain
 anything and can grow while a program is running.
 
 We can insert extra data into the header at the beginning if we
-wish. All we need to do is use the 'pmt_dict_add' function to insert
+wish. All we need to do is use the pmt::pmt_dict_add function to insert
 our hand-made metadata. This can be useful to add our own markers and
 information.
 
@@ -238,7 +239,7 @@ When reading out data from the extras, we do not necessarily know the
 data type of the PMT value. The key is always a PMT symbol, but the
 value can be any other PMT type. There are PMT functions that allow us
 to query the PMT to test if it is a particular type. We also have the
-ability to do 'pmt_print' on any PMT object to print it to
+ability to do pmt::pmt_print on any PMT object to print it to
 screen. Before converting from a PMT to it's natural data type, it is
 necessary to know the data type.
 
-- 
cgit v1.2.3


From a21c5f703a2030b4109811ccf3bcb2906df5d466 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Tue, 18 Dec 2012 13:36:17 -0500
Subject: docs: Adding a page describing the message passing interface.

---
 docs/doxygen/other/msg_passing.dox | 266 +++++++++++++++++++++++++++++++++++++
 1 file changed, 266 insertions(+)
 create mode 100644 docs/doxygen/other/msg_passing.dox

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/msg_passing.dox b/docs/doxygen/other/msg_passing.dox
new file mode 100644
index 0000000000..564a71c4ae
--- /dev/null
+++ b/docs/doxygen/other/msg_passing.dox
@@ -0,0 +1,266 @@
+/*! \page page_msg_passing Message Passing
+
+\section intro Introduction
+
+GNU Radio was originally a streaming system with no other mechanism to
+pass data between blocks. Streams of data are a model that work well
+for samples, bits, etc., but are not really the right mechanism for
+control data, metadata, and, often, packet structures (at least at
+some point in the processing chain).
+
+We solved part of this problem a few years ago by introducing the tag
+stream. This is a parallel stream to the data streaming. The
+difference is that tags are designed to hold metadata and control
+information. Tags are specifically associated with a particular sample
+in the data stream and flow downstream alongside the data. This model
+allows other blocks to identify that an event or action has occurred
+or should occur on a particular item. The major limitation is that the
+tag stream is really only accessible inside a work function and only
+flows in one direction. Its benefit is that it is isosynchronous with
+the data.
+
+We want a more general message passing system for a couple of
+reasons. The first is to allow blocks downstream to communicate back
+to blocks upstream. The second is to allow an easier way for us to
+communicate back and forth between external applications and GNU
+Radio. The new message passing interface handles these cases, although
+it does so on an asynchronous basis.
+
+
+\section api Message Passing API
+
+The message passing interface is designed into the gr_basic_block,
+which is the parent class for all blocks in GNU Radio. Each block has
+a set of message queues to hold incoming messages and can post
+messages to the message queues of other blocks. The blocks also
+distinguish between input and output ports.
+
+A block has to declare its input and output message ports in its
+constructor. The message ports are described by a name, which is in
+practice a PMT symbol (<em>i.e.</em>, an interned string). The API calls
+to register a new port are:
+
+\code
+  void message_port_register_in(pmt::pmt_t port_id)
+  void message_port_register_out(pmt::pmt_t port_id)
+\endcode
+
+The ports are now identifiable by that port name. Other blocks who may
+want to post or receive messages on a port must subscribe to it. When
+a block has a message to send, they are published on a particular
+port. The subscribe and publish API looks like:
+
+\code
+  void message_port_pub(pmt::pmt_t port_id,
+                        pmt::pmt_t msg);
+  void message_port_sub(pmt::pmt_t port_id,
+                        pmt::pmt_t target);
+  void message_port_unsub(pmt::pmt_t port_id,
+                          pmt::pmt_t target);
+\endcode
+
+Any block that has a subscription to another block's output message
+port will receive the message when it is published. Internally, when a
+block publishes a message, it simply iterates through all blocks that
+have subscribed and uses the gr_basic_block::_post method to send the
+message to that block's message queue.
+
+From the flowgraph level, we have instrumented a gr_hier_block2::msg_connect
+method to make it easy to subscribe blocks to other blocks'
+messages. The message connection method looks like the following
+code. Assume that the block \b src has an output message port named
+\a pdus and the block \b dbg has an input port named \a print.
+
+\code
+    self.tb.msg_connect(src, "pdus", dbg, "print")
+\endcode
+
+All messages published by the \b src block on port \a pdus will be
+received by \b dbg on port \a print. Note here how we are just using
+strings to define the ports, not PMT symbols. This is a convenience to
+the user to be able to more easily type in the port names (for
+reference, you can create a PMT symbol in Python using the 
+pmt::pmt_intern function as pmt.pmt_intern("string")).
+
+Users can also query blocks for the names of their input and output
+ports using the following API calls:
+
+\code
+    pmt::pmt_t message_ports_in();
+    pmt::pmt_t message_ports_out();
+\endcode
+
+The return value for these are a PMT vector filled with PMT symbols,
+so PMT operators must be used to manipulate them.
+
+Each block has internal methods to handle posting and receiving of
+messages. The gr_basic_block::_post method takes in a message and
+places it into its queue. The publishing model uses the
+gr_basic_block::_post method of the blocks as the way to access the
+message queue. So the message queue of the right name will have a new
+message. Posting messages also has the benefit of waking up the
+block's thread if it is in a wait state. So if idle, as soon as a
+message is posted, it will wake up and and call the message handler.
+
+The other side of the action in a block is in the message
+handler. When a block has an input message port, it needs a callback
+function to handle messages received on that port. We use a Boost bind
+operator to bind the message port to the message handling
+function. When a new message is pushed onto a port's message queue,
+it is this function that is used to process the message.
+
+
+\section examples Code Examples
+
+The following is snippets of code from blocks current in GNU Radio
+that take advantage of message passing. We will be using
+gr_message_debug and gr_tagged_stream_to_pdu below to show setting up
+both input and output message passing capabilities.
+
+The gr_message_debug block is used for debugging the message passing
+system. It describes two input message ports: \a print and \a
+store. The \a print port simply prints out all messages to standard
+out while the \a store port keeps a list of all messages posted to
+it. This latter port works in conjunction with a
+gr_message_debug::get_message(int i) call that allows us to retrieve
+message \p i afterward.
+
+The constructor of this block looks like this:
+
+\code
+{
+  message_port_register_in(pmt::mp("print"));
+  set_msg_handler(pmt::mp("print"),
+    boost::bind(&gr_message_debug::print, this, _1));
+
+  message_port_register_in(pmt::mp("store"));
+  set_msg_handler(pmt::mp("store"),
+    boost::bind(&gr_message_debug::store, this, _1));
+}
+\endcode
+
+So the two ports are registered by their respective names. We then use
+the gr_basic_block::set_msg_handler function to identify this
+particular port name with a callback function. The Boost \a bind
+function (<a target="_blank"
+href="http://www.boost.org/doc/libs/1_52_0/libs/bind/bind.html">Boost::bind</a>)
+here binds the callback to a function of this block's class. So now
+the block's gr_message_debug::print and gr_message_debug::store
+functions are assigned to handle messages passed to them. Below is the
+\a print function for reference.
+
+\code
+void
+gr_message_debug::print(pmt::pmt_t msg)
+{
+  std::cout << "***** MESSAGE DEBUG PRINT ********\n";
+  pmt::pmt_print(msg);
+  std::cout << "**********************************\n";
+}
+\endcode
+
+The function simply takes in the PMT message and prints it. The method
+pmt::pmt_print is a function in the PMT library to print the
+PMT in a friendly, (mostly) pretty manner.
+
+The gr_tagged_stream_to_pdu block only defines a single
+output message port. In this case, its constructor looks like:
+
+\code
+{
+  message_port_register_out(pdu_port_id);
+}
+\endcode
+
+So we are only creating a single output port where \a pdu_port_id
+is defined in the file gr_pdu.h as \a pdus.
+
+This blocks purpose is to take in a stream of samples along with
+stream tags and construct a predefined PDU message from this. In GNU
+Radio, we define a PDU as a PMT pair of (metadata, data). The metadata
+describes the samples found in the data portion of the
+pair. Specifically, the metadata can contain the length of the data
+segment and any other information (sample rate, etc.). The PMT vectors
+know their own length, so the length value is not actually necessary
+unless useful for purposes down the line. The metadata is a PMT
+dictionary while the data segment is a PMT uniform vector of either
+bytes, floats, or complex values.
+
+In the end, when a PDU message is ready, the block calls its
+gr_tagged_stream_to_pdu::send_message function that is shown below.
+
+\code
+void
+gr_tagged_stream_to_pdu::send_meassage()
+{
+  if(pmt::pmt_length(d_pdu_vector) != d_pdu_length) {
+    throw std::runtime_error("msg length not correct");
+  }
+
+  pmt::pmt_t msg = pmt::pmt_cons(d_pdu_meta,
+                                 d_pdu_vector);
+  message_port_pub(pdu_port_id, msg);
+
+  d_pdu_meta = pmt::PMT_NIL;
+  d_pdu_vector = pmt::PMT_NIL;
+  d_pdu_length = 0;
+  d_pdu_remain = 0;
+  d_inpdu = false;
+}
+\endcode
+
+This function does a bit of checking to make sure the PDU is ok as
+well as some cleanup in the end. But it is the line where the message
+is published that is important to this discussion. Here, the block
+posts the PDU message to any subscribers by calling
+gr_basic_block::message_port_pub publishing method.
+
+There is similarly a gr_pdu_to_tagged_stream block that essentially
+does the opposite. It acts as a source to a flowgraph and waits for
+PDU messages to be posted to it on its input port \a pdus. It extracts
+the metadata and data and processes them. The metadata dictionary is
+split up into key:value pairs and stream tags are created out of
+them. The data is then converted into an output stream of items and
+passed along. The next section describes how PDUs can be passed into a
+flowgraph using the gr_pdu_to_tagged_stream block.
+
+\section posting Posting from External Sources
+
+The last feature of the message passing architecture to discuss here
+is how it can be used to take in messages from an external source. We
+can call a block's gr_basic_block::_post method directly and pass it a
+message. So any block with an input message port can receive messages
+from the outside in this way.
+
+The following example uses a gr_pdu_to_tagged_stream block
+as the source block to a flowgraph. Its purpose is to wait for
+messages as PDUs posted to it and convert them to a normal stream. The
+payload will be sent on as a normal stream while the meta data will be
+decoded into tags and sent on the tagged stream.
+
+So if we have created a \b src block as a PDU to stream, it has a \a
+pdus input port, which is how we will inject PDU messages to the
+flowgraph. These PDUs could come from another block or flowgraph, but
+here, we will create and insert them by hand.
+
+\code
+  port = pmt.pmt_intern("pdus")
+  msg = pmt.pmt_cons(pmt.PMT_NIL,
+                     pmt.pmt_make_u8vector(16, 0xFF))
+  src.to_basic_block()._post(port, msg)
+\endcode
+
+The PDU's metadata section is empty, hence the pmt::PMT_NIL
+object. The payload is now just a simple vector of 16 bytes of all
+1's. To post the message, we have to access the block's gr_basic_block
+class, which we do using the gr_basic_block::to_basic_block method and
+then call the gr_basic_block::_post method to pass the PDU to the
+right port.
+
+All of these mechanisms are explored and tested in the QA code of the
+file qa_pdu.py.
+
+There are some examples of using the message passing infrastructure
+through GRC in gnuradio-core/src/examples/msg_passing.
+
+*/
-- 
cgit v1.2.3


From 77ea309277382d198681476976bd353a2a98e908 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Tue, 18 Dec 2012 15:30:58 -0500
Subject: docs: added a doxygen manual page describing PMT types and how to use
 them.

---
 docs/doxygen/other/pmt.dox | 348 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 348 insertions(+)
 create mode 100644 docs/doxygen/other/pmt.dox

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/pmt.dox b/docs/doxygen/other/pmt.dox
new file mode 100644
index 0000000000..61b73bca13
--- /dev/null
+++ b/docs/doxygen/other/pmt.dox
@@ -0,0 +1,348 @@
+/*! \page page_pmt Polymorphic Types
+
+\section intro Introduction
+
+Polymorphic Types are opaque data types that are designed as generic
+containers of data that can be safely passed around between blocks and
+threads in GNU Radio. They are heavily used in the stream tags and
+message passing interfaces. The most complete list of PMT function is,
+of course, the source code, specifically the header file pmt.h. This
+manual page summarizes the most important features and points of PMTs.
+
+
+\section datatype PMT Data Type
+
+All PMTs are of the type pmt::pmt_t. This is an opaque container and
+PMT functions must be used to manipulate and even do things like
+compare PMTs. PMTs are also \a immutable (except PMT vectors). We
+never change the data in a PMT; instead, we create a new PMT with the
+new data. The main reason for this is thread safety. We can pass PMTs
+as tags and messages between blocks and each receives its own copy
+that we can read from. However, we can never write to this object, and
+so if multiple blocks have a reference to the same PMT, there is no
+possibility of thread-safety issues of one reading the PMT data while
+another is writing the data. If a block is trying to write new data to
+a PMT, it actually creates a new PMT to put the data into. Thus we
+allow easy access to data in the PMT format without worrying about
+mutex locking and unlocking while manipulating them.
+
+PMTs can represent the following:
+
+- Boolean values of true/false
+- Strings (as symbols)
+- Integers (long and uint64)
+- Floats (as doubles)
+- Complex (as two doubles)
+- Pairs
+- Tuples
+- Vectors (of PMTs)
+- Uniform vectors (of any standard data type)
+- Dictionaries (list of key:value pairs)
+- Any (contains a boost::any pointer to hold anything)
+
+The PMT library also defines a set of functions that operate directly
+on PMTs such as:
+
+- Equal/equivalence between PMTs
+- Length (of a tuple or vector)
+- Map (apply a function to all elements in the PMT)
+- Reverse
+- Get a PMT at a position in a list
+- Serialize and deserialize
+- Printing
+
+The constants in the PMT library are:
+
+- pmt::PMT_T - a PMT True
+- pmt::PMT_F - a PMT False
+- pmt::PMT_NIL - an empty PMT (think Python's 'None')
+
+\section insert Inserting and Extracting Data
+
+Use pmt.h for a complete guide to the list of functions used to create
+PMTs and get the data from a PMT. When using these functions, remember
+that while PMTs are opaque and designed to hold any data, the data
+underneath is still a C++ typed object, and so the right type of
+set/get function must be used for the data type.
+
+Typically, a PMT object can be made from a scalar item using a call
+like "pmt::pmt_from_<type>". Similarly, when getting data out of a
+PMT, we use a call like "pmt::pmt_to_<type>". For example:
+
+\code
+double a = 1.2345;
+pmt::pmt_t pmt_a = pmt::pmt_from_double(a);
+double b = pmt::pmt_to_double(pmt_a);
+
+int c = 12345;
+pmt::pmt_t pmt_c = pmt::pmt_from_long(c);
+int d = pmt::pmt_to_long(pmt_c);
+\endcode
+
+As a side-note, making a PMT from a complex number is not obvious:
+
+\code
+std::complex<double> a(1.2, 3.4);
+pmt::pmt_t pmt_a = pmt::pmt_make_rectangular(a.real(), b.imag());
+std::complex<double> b = pmt::pmt_to_complex(pmt_a);
+\endcode
+
+Pairs, dictionaries, and vectors have different constructors and ways
+to manipulate them, and these are explained in their own sections.
+
+
+\section strings Strings
+
+PMTs have a way of representing short strings. These strings are
+actually stored as interned symbols in a hash table, so in other
+words, only one PMT object for a given string exists. If creating a
+new symbol from a string, if that string already exists in the hash
+table, the constructor will return a reference to the existing PMT.
+
+We create strings with the following functions, where the second
+function, pmt::pmt_intern, is simply an alias of the first.
+
+\code
+pmt::pmt_t str0 = pmt::pmt_string_to_symbol(std::string("some string"));
+pmt::pmt_t str1 = pmt::pmt_intern(std::string("some string"));
+\endcode
+
+The string can be retrieved using the inverse function:
+
+\code
+std::string s = pmt::pmt_symbol_to_string(str0);
+\endcode
+
+
+\section tests Tests and Comparisons
+
+The PMT library comes with a number of functions to test and compare
+PMT objects. In general, for any PMT data type, there is an equivalent
+"pmt::pmt_is_<type>". We can use these to test the PMT before trying
+to access the data inside. Expanding our examples above, we have:
+
+\code
+pmt::pmt_t str0 = pmt::pmt_string_to_symbol(std::string("some string"));
+if(pmt::pmt_is_symbol(str0))
+    std::string s = pmt::pmt_symbol_to_string(str0);
+
+double a = 1.2345;
+pmt::pmt_t pmt_a = pmt::pmt_from_double(a);
+if(pmt::pmt_is_double(pmt_a))
+    double b = pmt::pmt_to_double(pmt_a);
+
+int c = 12345;
+pmt::pmt_t pmt_c = pmt::pmt_from_long(c);
+if(pmt::pmt_is_long(pmt_a))
+    int d = pmt::pmt_to_long(pmt_c);
+
+\\ This will fail the test. Otherwise, trying to coerce \b pmt_c as a
+\\ double when internally it is a long will result in an exception.
+if(pmt::pmt_is_double(pmt_a))
+    double d = pmt::pmt_to_double(pmt_c);
+
+\endcode
+
+
+\section dict Dictionaries
+
+PMT dictionaries and lists of key:value pairs. They have a
+well-defined interface for creating, adding, removing, and accessing
+items in the dictionary. Note that every operation that changes the
+dictionary both takes a PMT dictionary as an argument and returns a
+PMT dictionary. The dictionary used as an input is not changed and the
+returned dictionary is a new PMT with the changes made there.
+
+The following is a list of PMT dictionary functions. Click through to
+get more information on what each does.
+
+- bool pmt::pmt_is_dict(const pmt_t &obj)
+- pmt_t pmt::pmt_make_dict()
+- pmt_t pmt::pmt_dict_add(const pmt_t &dict, const pmt_t &key, const pmt_t &value)
+- pmt_t pmt::pmt_dict_delete(const pmt_t &dict, const pmt_t &key)
+- bool pmt::pmt_dict_has_key(const pmt_t &dict, const pmt_t &key)
+- pmt_t pmt::pmt_dict_ref(const pmt_t &dict, const pmt_t &key, const pmt_t &not_found)
+- pmt_t pmt::pmt_dict_items(pmt_t dict)
+- pmt_t pmt::pmt_dict_keys(pmt_t dict)
+- pmt_t pmt::pmt_dict_values(pmt_t dict)
+
+This example does some basic manipulations of PMT dictionaries in
+Python. Notice that we pass the dictionary \a a and return the results
+to \a a. This still creates a new dictionary and removes the local
+reference to the old dictionary. This just keeps our number of
+variables small.
+
+\code
+from gruel import pmt
+
+key0 = pmt.pmt_intern("int")
+val0 = pmt.pmt_from_long(123)
+val1 = pmt.pmt_from_long(234)
+
+key1 = pmt.pmt_intern("double")
+val2 = pmt.pmt_from_double(5.4321)
+
+# Make an empty dictionary
+a = pmt.pmt_make_dict()
+
+# Add a key:value pair to the dictionary
+a = pmt.pmt_dict_add(a, key0, val0)
+pmt.pmt_print(a)
+
+# Add a new value to the same key;
+# new dict will still have one item with new value
+a = pmt.pmt_dict_add(a, key0, val1)
+pmt.pmt_print(a)
+
+# Add a new key:value pair
+a = pmt.pmt_dict_add(a, key1, val2)
+pmt.pmt_print(a)
+
+# Test if we have a key, then delete it
+print pmt.pmt_dict_has_key(a, key1)
+a = pmt.pmt_dict_delete(a, key1)
+print pmt.pmt_dict_has_key(a, key1)
+
+ref = pmt.pmt_dict_ref(a, key0, pmt.PMT_NIL)
+pmt.pmt_print(ref)
+
+# The following should never print
+if(pmt.pmt_dict_has_key(a, key0) and pmt.pmt_eq(ref, pmt.PMT_NIL)):
+    print "Trouble! We have key0, but it returned PMT_NIL"
+\endcode
+
+\section vectors Vectors
+
+PMT vectors come in two forms: vectors of PMTs and vectors of uniform
+data. The standard PMT vector is a vector of PMTs, and each PMT can be
+of any internal type. On the other hand, uniform PMTs are of a
+specific data type which come in the form:
+
+- (u)int8
+- (u)int16
+- (u)int32
+- (u)int64
+- float32
+- float64
+- complex 32 (std::complex<float>)
+- complex 64 (std::complex<double>)
+
+That is, the standard sizes of integers, floats, and complex types of
+both signed and unsigned.
+
+Vectors have a well-defined interface that allows us to make, set,
+get, and fill them. We can also get the length of a vector with
+pmt::pmt_length.
+
+For standard vectors, these functions look like:
+
+- bool pmt::pmt_is_vector(pmt_t x)
+- pmt_t pmt::pmt_make_vector(size_t k, pmt_t fill)
+- pmt_t pmt::pmt_vector_ref(pmt_t vector, size_t k)
+- void pmt::pmt_vector_set(pmt_t vector, size_t k, pmt_t obj)
+- void pmt::pmt_vector_fill(pmt_t vector, pmt_t fill)
+
+Uniform vectors have the same types of functions, but they are data
+type-dependent. The following list tries to explain them where you
+substitute the specific data type prefix for \a dtype (prefixes being:
+u8, u16, u32, u64, s8, s16, s32, s64, f32, f64, c32, c64).
+
+- bool pmt::pmt_is_(dtype)vector(pmt_t x)
+- pmt_t pmt::pmt_make_(dtype)vector(size_t k, (dtype) fill)
+- pmt_t pmt::pmt_init_(dtype)vector(size_t k, const (dtype*) data)
+- pmt_t pmt::pmt_init_(dtype)vector(size_t k, const std::vector<dtype> data)
+- pmt_t pmt::pmt_(dtype)vector_ref(pmt_t vector, size_t k)
+- void pmt::pmt_(dtype)vector_set(pmt_t vector, size_t k, (dtype) x)
+- const dtype* pmt::pmt_(dtype)vector_elements(pmt_t vector, size_t &len)
+- dtype* pmt::pmt_(dtype)vector_writable_elements(pmt_t vector, size_t &len)
+
+\b Note: We break the contract with vectors. The 'set' functions
+actually change the data underneath. It is important to keep track of
+the implications of setting a new value as well as accessing the
+'vector_writable_elements' data. Since these are mostly standard data
+types, sets and gets are atomic, so it is unlikely to cause a great
+deal of harm. But it's only unlikely, not impossible. Best to use
+mutexes whenever manipulating data in a vector.
+
+
+\subsection blob BLOB
+
+A BLOB is a 'binary large object' type. In PMT's, this is actually
+just a thin wrapper around a u8vector.
+
+\section pairs Pairs
+
+Pairs are inspired by LISP 'cons' data types, so you will find the
+language here comes from LISP. A pair is just a pair of PMT
+objects. They are manipulated using the following functions:
+
+- bool pmt::pmt_is_pair (const pmt_t &obj): Return true if obj is a pair, else false
+- pmt_t pmt::pmt_cons(const pmt_t &x, const pmt_t &y): construct new pair
+- pmt_t pmt::pmt_car(const pmt_t &pair): get the car of the pair (first object)
+- pmt_t pmt::pmt_cdr(const pmt_t &pair): get the cdr of the pair (second object)
+- void pmt::pmt_set_car(pmt_t pair, pmt_t value): Stores value in the car field
+- void pmt::pmt_set_cdr(pmt_t pair, pmt_t value): Stores value in the cdr field
+
+
+\section serdes Serializing and Deserializing
+
+It is often important to hide the fact that we are working with PMTs
+to make them easier to transmit, store, write to file, etc. The PMT
+library has methods to serialize data into a string buffer or a
+string and then methods to deserialize the string buffer or string
+back into a PMT. We use this extensively in the metadata files (see
+\ref page_metadata).
+
+- bool pmt::pmt_serialize(pmt_t obj, std::streambuf &sink)
+- std::string pmt::pmt_serialize_str(pmt_t obj)
+- pmt_t pmt::pmt_deserialize(std::streambuf &source)
+- pmt_t pmt::pmt_deserialize_str(std::string str)
+
+For example, we will serialize the data above to make it into a string
+ready to be written to a file and then deserialize it back to its
+original PMT.
+
+\code
+from gruel import pmt
+
+key0 = pmt.pmt_intern("int")
+val0 = pmt.pmt_from_long(123)
+
+key1 = pmt.pmt_intern("double")
+val1 = pmt.pmt_from_double(5.4321)
+
+# Make an empty dictionary
+a = pmt.pmt_make_dict()
+
+# Add a key:value pair to the dictionary
+a = pmt.pmt_dict_add(a, key0, val0)
+a = pmt.pmt_dict_add(a, key1, val1)
+
+pmt.pmt_print(a)
+
+ser_str = pmt.pmt_serialize_str(a)
+print ser_str
+
+b = pmt.pmt_deserialize_str(ser_str)
+pmt.pmt_print(b)
+
+\endcode
+
+The line where we 'print ser_str' will print and parts will be
+readable, but the point of serializing is not to make a human-readable
+string. This is only done here as a test.
+
+
+\section printing Printing
+
+We have used the pmt::pmt_print function in these examples to nicely
+print the contents of a PMT. Another way to print the contents is
+using the overloaded "<<" operator with a stream buffer object. In
+C++, we can inline print the contents of a PMT like:
+
+\code
+pmt::pmt_t a pmt::pmt_from_double(1.0);
+std::cout << "The PMT a contains " << a << std::endl;
+\endcode
+
+*/
-- 
cgit v1.2.3


From 6d8161a0b0c88f2faf090a80c74eb03422278289 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Tue, 18 Dec 2012 15:31:20 -0500
Subject: docs: Restructuring main page to point to new pages describing
 features in GR.

---
 docs/doxygen/other/main_page.dox   | 6 ++++++
 docs/doxygen/other/msg_passing.dox | 3 +++
 2 files changed, 9 insertions(+)

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox
index 2826824647..abdc21b0c9 100644
--- a/docs/doxygen/other/main_page.dox
+++ b/docs/doxygen/other/main_page.dox
@@ -37,6 +37,12 @@ More details on packages in GNU Radio:
 \li \ref page_qtgui
 \li \ref page_uhd
 \li \ref page_vocoder
+
+More details on GNU Radio concepts:
+\li \ref page_pmt
+\li \ref page_msg_passing
+\li \ref page_metadata
+\li \ref volk_guide
 \li \ref page_pfb
 
 
diff --git a/docs/doxygen/other/msg_passing.dox b/docs/doxygen/other/msg_passing.dox
index 564a71c4ae..aea0ac94ae 100644
--- a/docs/doxygen/other/msg_passing.dox
+++ b/docs/doxygen/other/msg_passing.dox
@@ -26,6 +26,9 @@ communicate back and forth between external applications and GNU
 Radio. The new message passing interface handles these cases, although
 it does so on an asynchronous basis.
 
+The message passing interface heavily relies on Polymorphic Types
+(PMTs) in GNU Radio. For further information about these data
+structures, see the page \ref page_pmt.
 
 \section api Message Passing API
 
-- 
cgit v1.2.3


From 5faae9df3ad16bceb24b65fed63a8a8766b48ee9 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Wed, 2 Jan 2013 12:13:44 -0500
Subject: docs: fixing typo.

---
 docs/doxygen/other/metadata.dox | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/metadata.dox b/docs/doxygen/other/metadata.dox
index f867a06f28..b527b21008 100644
--- a/docs/doxygen/other/metadata.dox
+++ b/docs/doxygen/other/metadata.dox
@@ -298,7 +298,7 @@ The file sink example can be switched to use a signal source instead
 of a UHD source, but no extra tagged data is used in this mode.
 
 The file source example pushes the data stream to a new raw file while
-a tag debugger block prints out any tags observed in the metedata
+a tag debugger block prints out any tags observed in the metadata
 file. A QT GUI time sink is used to look at the signal as well.
 
 The versions with 'vector' in the name are similar except they use
-- 
cgit v1.2.3


From 01eab0c7e283db9c1cfff0a26296a49128062cca Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Wed, 19 Dec 2012 13:38:24 -0500
Subject: core: working thread affinity concept into gr_blocks.

Example in gnuradio-core/src/examples/mp-sched/affinity_set.py

Documentation describing API in docs/doxygen/other/thread_affinity.dox
---
 docs/doxygen/other/thread_affinity.dox             | 65 +++++++++++++++++++
 gnuradio-core/src/examples/mp-sched/CMakeLists.txt |  1 +
 .../src/examples/mp-sched/affinity_set.py          | 73 ++++++++++++++++++++++
 gnuradio-core/src/lib/runtime/gr_block.cc          | 18 ++++++
 gnuradio-core/src/lib/runtime/gr_block.h           | 21 +++++++
 gnuradio-core/src/lib/runtime/gr_block.i           |  5 ++
 gnuradio-core/src/lib/runtime/gr_block_detail.cc   | 21 +++++++
 gnuradio-core/src/lib/runtime/gr_block_detail.h    | 14 +++++
 .../src/lib/runtime/gr_tpb_thread_body.cc          |  7 +++
 gruel/src/lib/thread.cc                            |  5 +-
 10 files changed, 229 insertions(+), 1 deletion(-)
 create mode 100644 docs/doxygen/other/thread_affinity.dox
 create mode 100755 gnuradio-core/src/examples/mp-sched/affinity_set.py

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/thread_affinity.dox b/docs/doxygen/other/thread_affinity.dox
new file mode 100644
index 0000000000..fbbc449a4a
--- /dev/null
+++ b/docs/doxygen/other/thread_affinity.dox
@@ -0,0 +1,65 @@
+/*! \page page_affinity Block Thread Affinity
+
+\section intro Introduction
+
+In the thread-per-block scheduler, you can set the block's core
+affinity. Each block can be pinned to a group cores or be set back
+to use the standard kernel scheduler.
+
+The implementation is done by adding new functions to the GRUEL
+library:
+
+\code
+  gr_thread_t get_current_thread_id();
+  void thread_bind_to_processor(unsigned int n);
+  void thread_bind_to_processor(const std::vector<unsigned int> &mask);
+  void thread_bind_to_processor(gr_thread_t thread, unsigned int n);
+  void thread_bind_to_processor(gr_thread_t thread, const std::vector<unsigned int> &mask);
+  void thread_unbind();
+  void thread_unbind(gr_thread_t thread);
+\endcode
+
+The ability to set a thread's affinity to a core or groups of cores is
+not implemented in the Boost thread library, and so we have made our
+own portability library. In particular, the gruel::gr_thread_t type is
+defined as the thread type for the given system. The other functions
+are designed to be portable as well by calling the specific
+implementation for the thread affinity for a particular platform.
+
+There are functions to set a thread to a group of cores. If the thread
+is not given, the current thread is used. If a single number is
+passed, only that core is set (this is equivalent to a core mask with
+just a single value).
+
+Similarly, there are functions to unset the affinity. This practically
+implements the setting of the thread's affinity to all possible
+cores. Again, the function that does not take a thread argument unsets
+the affinity for the current thread.
+
+
+\section api GNU Radio Block API
+
+Each block has two new data members:
+
+- threaded: a boolean value that is true if the block is attached to a
+  thread.
+- thread: a gruel::gr_thread_t handle to the block's thread.
+
+A block can set and unset it's affinity at any time using the
+following member functions:
+
+- gr_block::set_processor_affinity(const std::vector<unsigned int> &mask)
+- gr_block::unset_processor_affinity()
+
+Where \p mask is a vector of core numbers to set the thread's affinity
+to.
+
+The current core affinity can be retrieved using the member function:
+ 
+- gr_block::processor_affinity()
+
+When set before the flowgraph is started, the scheduler will set the
+thread's affinity when it is started. When already running, the
+block's affinity will be immediately set.
+
+*/
diff --git a/gnuradio-core/src/examples/mp-sched/CMakeLists.txt b/gnuradio-core/src/examples/mp-sched/CMakeLists.txt
index dc47d17f9e..d2d910ecf2 100644
--- a/gnuradio-core/src/examples/mp-sched/CMakeLists.txt
+++ b/gnuradio-core/src/examples/mp-sched/CMakeLists.txt
@@ -20,6 +20,7 @@
 include(GrPython)
 
 GR_PYTHON_INSTALL(PROGRAMS
+  affinity_set.py
   plot_flops.py
   run_synthetic.py
   synthetic.py
diff --git a/gnuradio-core/src/examples/mp-sched/affinity_set.py b/gnuradio-core/src/examples/mp-sched/affinity_set.py
new file mode 100755
index 0000000000..b34477d14f
--- /dev/null
+++ b/gnuradio-core/src/examples/mp-sched/affinity_set.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: Affinity Set Test
+##################################################
+
+from gnuradio import eng_notation
+from gnuradio import gr
+from gnuradio.eng_option import eng_option
+from gnuradio.gr import firdes
+from optparse import OptionParser
+import sys
+
+class affinity_set(gr.top_block):
+
+    def __init__(self):
+        gr.top_block.__init__(self, "Affinity Set Test")
+
+        ##################################################
+	# Variables
+	##################################################
+	self.samp_rate = samp_rate = 32000
+
+	##################################################
+	# Blocks
+	##################################################
+        vec_len = 1
+	self.gr_throttle_0 = gr.throttle(gr.sizeof_gr_complex*vec_len, samp_rate)
+	self.gr_null_source_0 = gr.null_source(gr.sizeof_gr_complex*vec_len)
+	self.gr_null_sink_0 = gr.null_sink(gr.sizeof_gr_complex*vec_len)
+	self.gr_filt_0 = gr.fir_filter_ccc(1, 40000*[0.2+0.3j,])
+	self.gr_filt_1 = gr.fir_filter_ccc(1, 40000*[0.2+0.3j,])
+
+	self.gr_filt_0.set_processor_affinity([0,])
+	self.gr_filt_1.set_processor_affinity([1,2])
+		
+	##################################################
+	# Connections
+	##################################################
+	self.connect((self.gr_null_source_0, 0), (self.gr_throttle_0, 0))
+	self.connect((self.gr_throttle_0, 0), (self.gr_filt_0, 0))
+	self.connect((self.gr_filt_0, 0), (self.gr_filt_1, 0))
+	self.connect((self.gr_filt_1, 0), (self.gr_null_sink_0, 0))
+
+
+	# QT sink close method reimplementation
+
+    def get_samp_rate(self):
+        return self.samp_rate
+
+    def set_samp_rate(self, samp_rate):
+        self.samp_rate = samp_rate
+
+if __name__ == '__main__':
+    parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
+    (options, args) = parser.parse_args()
+    tb = affinity_set()
+    tb.start()
+	
+    while(1):
+        ret = raw_input('Press Enter to quit: ')
+	if(len(ret) == 0):
+            tb.stop()
+	    sys.exit(0)
+        elif(ret.lower() == "none"):
+            tb.gr_filt_0.unset_processor_affinity()
+	else:
+            try:
+                n = int(ret)
+	    except ValueError:
+                print "Invalid number"
+	    else:
+                tb.gr_filt_0.set_processor_affinity([n,])
diff --git a/gnuradio-core/src/lib/runtime/gr_block.cc b/gnuradio-core/src/lib/runtime/gr_block.cc
index 5ba30955f9..dca1fcf838 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.cc
+++ b/gnuradio-core/src/lib/runtime/gr_block.cc
@@ -251,6 +251,24 @@ gr_block::is_set_max_noutput_items()
   return d_max_noutput_items_set;
 }
 
+void
+gr_block::set_processor_affinity(const std::vector<unsigned int> &mask)
+{
+  d_affinity = mask;
+  if(d_detail) {
+    d_detail->set_processor_affinity(d_affinity);
+  }
+}
+
+void
+gr_block::unset_processor_affinity()
+{
+  d_affinity.clear();
+  if(d_detail) {
+    d_detail->unset_processor_affinity();
+  }
+}
+
 std::ostream&
 operator << (std::ostream& os, const gr_block *m)
 {
diff --git a/gnuradio-core/src/lib/runtime/gr_block.h b/gnuradio-core/src/lib/runtime/gr_block.h
index 7a70bdaf09..9906d36323 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.h
+++ b/gnuradio-core/src/lib/runtime/gr_block.h
@@ -359,6 +359,26 @@ class GR_CORE_API gr_block : public gr_basic_block {
   }
 
   // ----------------------------------------------------------------------------
+  // Functions to handle thread affinity
+
+  /*!
+   * \brief Set the thread's affinity to processor core \p n.
+   *
+   * \param mask a vector of unsigned ints of the core numbers available to this block.
+   */
+  void set_processor_affinity(const std::vector<unsigned int> &mask);
+
+  /*!
+   * \brief Remove processor affinity to a specific core.
+   */
+  void unset_processor_affinity();
+
+  /*!
+   * \brief Get the current processor affinity.
+   */
+  std::vector<unsigned int> processor_affinity() { return d_affinity; }
+
+  // ----------------------------------------------------------------------------
 
  private:
 
@@ -373,6 +393,7 @@ class GR_CORE_API gr_block : public gr_basic_block {
   bool                  d_max_noutput_items_set;     // if d_max_noutput_items is valid
   int                   d_max_noutput_items;         // value of max_noutput_items for this block
   tag_propagation_policy_t d_tag_propagation_policy; // policy for moving tags downstream
+  std::vector<unsigned int> d_affinity;              // thread affinity proc. mask
 
  protected:
   gr_block (void){} //allows pure virtual interface sub-classes
diff --git a/gnuradio-core/src/lib/runtime/gr_block.i b/gnuradio-core/src/lib/runtime/gr_block.i
index db6c1d04a7..89685d41f0 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.i
+++ b/gnuradio-core/src/lib/runtime/gr_block.i
@@ -66,6 +66,11 @@ class gr_block : public gr_basic_block {
   void set_min_output_buffer(long min_output_buffer);
   void set_min_output_buffer(int port, long min_output_buffer);
 
+  // Methods to manage processor affinity.
+  void set_processor_affinity(const std::vector<unsigned int> &mask);
+  void unset_processor_affinity();
+  std::vector<unsigned int> processor_affinity();
+
   // internal use
   gr_block_detail_sptr detail () const { return d_detail; }
   void set_detail (gr_block_detail_sptr detail) { d_detail = detail; }
diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.cc b/gnuradio-core/src/lib/runtime/gr_block_detail.cc
index c65493473c..e6199be374 100644
--- a/gnuradio-core/src/lib/runtime/gr_block_detail.cc
+++ b/gnuradio-core/src/lib/runtime/gr_block_detail.cc
@@ -201,3 +201,24 @@ gr_block_detail::get_tags_in_range(std::vector<gr_tag_t> &v,
     }
   }
 }
+
+void
+gr_block_detail::set_processor_affinity(const std::vector<unsigned int> &mask)
+{
+  if(threaded) {
+    try {
+      gruel::thread_bind_to_processor(thread, mask);
+    }
+    catch (std::runtime_error e) {
+      std::cerr << "set_processor_affinity: invalid mask."  << std::endl;;
+    }
+  }
+}
+
+void
+gr_block_detail::unset_processor_affinity()
+{
+  if(threaded) {
+    gruel::thread_unbind(thread);
+  }
+}
diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.h b/gnuradio-core/src/lib/runtime/gr_block_detail.h
index af00ea7c79..bcc42c7a0d 100644
--- a/gnuradio-core/src/lib/runtime/gr_block_detail.h
+++ b/gnuradio-core/src/lib/runtime/gr_block_detail.h
@@ -155,6 +155,20 @@ class GR_CORE_API gr_block_detail {
 			 uint64_t abs_end,
 			 const pmt::pmt_t &key);
 
+  /*!
+   * \brief Set core affinity of block to the cores in the vector mask.
+   *
+   * \param mask a vector of unsigned ints of the core numbers available to this block.
+   */
+  void set_processor_affinity(const std::vector<unsigned int> &mask);
+
+  /*!
+   * \brief Unset core affinity.
+   */
+  void unset_processor_affinity();
+
+  bool                               threaded;  // set if thread is currently running.
+  gruel::gr_thread_t                 thread;    // portable thread handle
   gr_tpb_detail			     d_tpb;	// used by thread-per-block scheduler
   int				     d_produce_or;
 
diff --git a/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.cc b/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.cc
index 9f17a48a80..cea374fac7 100644
--- a/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.cc
+++ b/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.cc
@@ -38,6 +38,13 @@ gr_tpb_thread_body::gr_tpb_thread_body(gr_block_sptr block, int max_noutput_item
   gr_block_executor::state s;
   pmt_t msg;
 
+  d->threaded = true;
+  d->thread = gruel::get_current_thread_id();
+
+  // Set thread affinity if it was set before fg was started.
+  if(block->processor_affinity().size() > 0) {
+    gruel::thread_bind_to_processor(d->thread, block->processor_affinity());
+  }
 
   while (1){
     boost::this_thread::interruption_point();
diff --git a/gruel/src/lib/thread.cc b/gruel/src/lib/thread.cc
index 46ba1745a0..ab022c0bd5 100644
--- a/gruel/src/lib/thread.cc
+++ b/gruel/src/lib/thread.cc
@@ -118,13 +118,16 @@ namespace gruel {
   }
 
   void
-  thread_bind_to_processor(gr_thread_t thread, const std::vector<unsigned int> &mask)
+  thread_bind_to_processor(const std::vector<unsigned int> &mask)
   {
     // Not implemented on OSX
   }
 
   void
   thread_bind_to_processor(gr_thread_t thread, const std::vector<unsigned int> &mask)
+  {
+    // Not implemented on OSX
+  }
 
   void
   thread_unbind()
-- 
cgit v1.2.3


From 3643a858e3f4e52fc9c9a3310f779a9f77ed308e Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Sat, 16 Feb 2013 16:23:12 -0500
Subject: docs: adding section to main page explaining config files.

---
 docs/doxygen/other/main_page.dox | 73 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox
index abdc21b0c9..e7d4685f75 100644
--- a/docs/doxygen/other/main_page.dox
+++ b/docs/doxygen/other/main_page.dox
@@ -329,4 +329,77 @@ they can also serve as examples. See the gr_complex_to_xxx.h file for
 examples of various blocks that make use of Volk.
 
 
+\section prefs Configuration / Preference Files
+
+GNU Radio defines some of its basic behavior through a set of
+configuration files located in
+${prefix}/etc/gnuradio/conf.d. Different components have different
+files listed in here for the various properties. These will be read
+once when starting a GNU Radio application, so updates during runtime
+will not affect them.
+
+The configuration files use the following format:
+
+\code
+# Stuff from section 1
+[section1]
+var1 = value1 
+var2 = value2 # value of 2
+
+# Stuff from section 2
+[section2]
+var3 = value3
+\endcode
+
+In this file, the hash mark ('#') indicates a comment and blank lines
+are ignored. Section labels are defined inside square brackets as a
+group distinguisher. All options must be associated with a section
+name. The options are listed one per line with the option name is
+given followed by an equals ('=') sign and then the value. All section
+and option names must not have white spaces (actually, all white
+spaces are ignored).
+
+The value of an option can be a string or number and retrieved through
+a few different interfaces. There is a single preference object
+created when GNU Radio is launched. In Python, you can get this by
+making a new variable:
+
+\code
+p = gr.prefs()
+\endcode
+
+Similarly, in C++, we get a reference to the object by explicitly
+calling for the singleton of the object:
+
+\code
+  gr_prefs *p = gr_prefs::singleton();
+\endcode
+
+The methods associated with this preferences object are (from class gr_prefs):
+
+\code
+  bool has_section(string section)
+  bool has_option(string section, string option)
+  string get_string(string section, string option, string default_val)
+  bool get_bool(string section, string option, bool default_val)
+  long get_long(string section, string option, long default_val)
+  double get_double(string section, string option, double default_val)
+\endcode
+
+When setting a Boolean value, we can use 0, 1, "True", "true",
+"False", "false", "On", "on", "Off", and "off".
+
+All configuration preferences in these files can also be overloaded by
+an environmental variable. The environmental variable is named based
+on the section and option name from the configuration file as:
+
+\code
+  GR_CONF_<SECTION>_<OPTION> = <value>
+\endcode
+
+The "GR_CONF_" is a prefix to identify this as a GNU Radio
+configuration variable and the section and option names are in
+uppercase. The value is the same format that would be used in the
+config file itself.
+
 */
-- 
cgit v1.2.3


From c6ef84436f6be534375d1b6ecfa08f565ff73cab Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Tue, 19 Feb 2013 10:24:20 -0500
Subject: docs: adding an exclude rule for gr-modtool to avoid conflicts.

---
 docs/doxygen/Doxyfile.in | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/Doxyfile.in b/docs/doxygen/Doxyfile.in
index 78a7a5d166..86cf2fc96f 100644
--- a/docs/doxygen/Doxyfile.in
+++ b/docs/doxygen/Doxyfile.in
@@ -633,7 +633,8 @@ EXCLUDE                = @abs_top_builddir@/docs/doxygen/html \
 			 @abs_top_builddir@/_CPack_Packages \
                          @abs_top_srcdir@/cmake \
 			 @abs_top_srcdir@/gr-qtgui/lib \
-                         @abs_top_srcdir@/gr-howto-write-a-block
+                         @abs_top_srcdir@/gr-howto-write-a-block \
+                         @abs_top_srcdir@/gr-utils/python/modtool/gr-newmod
 
 # The EXCLUDE_SYMLINKS tag can be used select whether or not files or
 # directories that are symbolic links (a Unix filesystem feature) are excluded
-- 
cgit v1.2.3


From b5bc1a3359e13a24e3329d92f32092e599e52d40 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Tue, 19 Feb 2013 10:52:14 -0500
Subject: docs: correcting gr-modtool exclude path for master dir format.

---
 docs/doxygen/Doxyfile.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'docs/doxygen')

diff --git a/docs/doxygen/Doxyfile.in b/docs/doxygen/Doxyfile.in
index 86cf2fc96f..536661996b 100644
--- a/docs/doxygen/Doxyfile.in
+++ b/docs/doxygen/Doxyfile.in
@@ -634,7 +634,7 @@ EXCLUDE                = @abs_top_builddir@/docs/doxygen/html \
                          @abs_top_srcdir@/cmake \
 			 @abs_top_srcdir@/gr-qtgui/lib \
                          @abs_top_srcdir@/gr-howto-write-a-block \
-                         @abs_top_srcdir@/gr-utils/python/modtool/gr-newmod
+                         @abs_top_srcdir@/gr-utils/src/python/modtool/gr-newmod
 
 # The EXCLUDE_SYMLINKS tag can be used select whether or not files or
 # directories that are symbolic links (a Unix filesystem feature) are excluded
-- 
cgit v1.2.3