From 461ece56b36a44b2405282630157739c7f9a26ba Mon Sep 17 00:00:00 2001
From: Tom Rondeau
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
diff --git a/docs/doxygen/other/metadata.dox b/docs/doxygen/other/metadata.dox
index 1b3c891a8..9fad7c584 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 36333425c..01d9eb83e 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 182d9c543..000000000
--- 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 197ff5572..000000000
--- a/gnuradio-core/src/examples/metadata/file_metadata_sink.grc
+++ /dev/null
@@ -1,951 +0,0 @@
-
-
- Thu Dec 13 14:25:16 2012
-
- gr_sig_source_x
-
- id
- gr_sig_source_x_0
-
-
- _enabled
- False
-
-
- type
- complex
-
-
- samp_rate
- samp_rate
-
-
- waveform
- gr.GR_COS_WAVE
-
-
- freq
- 1000
-
-
- amp
- 1
-
-
- offset
- 0
-
-
- _coordinate
- (57, 140)
-
-
- _rotation
- 0
-
-
-
- variable_qtgui_range
-
- id
- qt_samp_rate
-
-
- _enabled
- True
-
-
- label
-
-
-
- value
- samp_rate
-
-
- start
- 200000
-
-
- stop
- 5000000
-
-
- step
- 200000
-
-
- widget
- counter_slider
-
-
- orient
- Qt.Horizontal
-
-
- min_len
- 200
-
-
- gui_hint
-
-
-
- _coordinate
- (330, 259)
-
-
- _rotation
- 0
-
-
-
- gr_head
-
- id
- gr_head_0
-
-
- _enabled
- True
-
-
- type
- complex
-
-
- num_items
- 20000000
-
-
- vlen
- 1
-
-
- _coordinate
- (309, 172)
-
-
- _rotation
- 0
-
-
-
- variable
-
- id
- samp_rate
-
-
- _enabled
- True
-
-
- value
- 200000
-
-
- _coordinate
- (208, 11)
-
-
- _rotation
- 0
-
-
-
- uhd_usrp_source
-
- id
- uhd_usrp_source_0
-
-
- _enabled
- True
-
-
- type
- fc32
-
-
- otw
-
-
-
- stream_args
-
-
-
- dev_addr
- addr=192.168.11.2
-
-
- sync
-
-
-
- clock_rate
- 0.0
-
-
- num_mboards
- 1
-
-
- clock_source0
-
-
-
- time_source0
-
-
-
- sd_spec0
-
-
-
- clock_source1
-
-
-
- time_source1
-
-
-
- sd_spec1
-
-
-
- clock_source2
-
-
-
- time_source2
-
-
-
- sd_spec2
-
-
-
- clock_source3
-
-
-
- time_source3
-
-
-
- sd_spec3
-
-
-
- clock_source4
-
-
-
- time_source4
-
-
-
- sd_spec4
-
-
-
- clock_source5
-
-
-
- time_source5
-
-
-
- sd_spec5
-
-
-
- clock_source6
-
-
-
- time_source6
-
-
-
- sd_spec6
-
-
-
- clock_source7
-
-
-
- time_source7
-
-
-
- sd_spec7
-
-
-
- nchan
- 1
-
-
- samp_rate
- qt_samp_rate
-
-
- center_freq0
- 98.9e6
-
-
- gain0
- 30
-
-
- ant0
-
-
-
- bw0
- 0
-
-
- center_freq1
- 0
-
-
- gain1
- 0
-
-
- ant1
-
-
-
- bw1
- 0
-
-
- center_freq2
- 0
-
-
- gain2
- 0
-
-
- ant2
-
-
-
- bw2
- 0
-
-
- center_freq3
- 0
-
-
- gain3
- 0
-
-
- ant3
-
-
-
- bw3
- 0
-
-
- center_freq4
- 0
-
-
- gain4
- 0
-
-
- ant4
-
-
-
- bw4
- 0
-
-
- center_freq5
- 0
-
-
- gain5
- 0
-
-
- ant5
-
-
-
- bw5
- 0
-
-
- center_freq6
- 0
-
-
- gain6
- 0
-
-
- ant6
-
-
-
- bw6
- 0
-
-
- center_freq7
- 0
-
-
- gain7
- 0
-
-
- ant7
-
-
-
- bw7
- 0
-
-
- center_freq8
- 0
-
-
- gain8
- 0
-
-
- ant8
-
-
-
- bw8
- 0
-
-
- center_freq9
- 0
-
-
- gain9
- 0
-
-
- ant9
-
-
-
- bw9
- 0
-
-
- center_freq10
- 0
-
-
- gain10
- 0
-
-
- ant10
-
-
-
- bw10
- 0
-
-
- center_freq11
- 0
-
-
- gain11
- 0
-
-
- ant11
-
-
-
- bw11
- 0
-
-
- center_freq12
- 0
-
-
- gain12
- 0
-
-
- ant12
-
-
-
- bw12
- 0
-
-
- center_freq13
- 0
-
-
- gain13
- 0
-
-
- ant13
-
-
-
- bw13
- 0
-
-
- center_freq14
- 0
-
-
- gain14
- 0
-
-
- ant14
-
-
-
- bw14
- 0
-
-
- center_freq15
- 0
-
-
- gain15
- 0
-
-
- ant15
-
-
-
- bw15
- 0
-
-
- center_freq16
- 0
-
-
- gain16
- 0
-
-
- ant16
-
-
-
- bw16
- 0
-
-
- center_freq17
- 0
-
-
- gain17
- 0
-
-
- ant17
-
-
-
- bw17
- 0
-
-
- center_freq18
- 0
-
-
- gain18
- 0
-
-
- ant18
-
-
-
- bw18
- 0
-
-
- center_freq19
- 0
-
-
- gain19
- 0
-
-
- ant19
-
-
-
- bw19
- 0
-
-
- center_freq20
- 0
-
-
- gain20
- 0
-
-
- ant20
-
-
-
- bw20
- 0
-
-
- center_freq21
- 0
-
-
- gain21
- 0
-
-
- ant21
-
-
-
- bw21
- 0
-
-
- center_freq22
- 0
-
-
- gain22
- 0
-
-
- ant22
-
-
-
- bw22
- 0
-
-
- center_freq23
- 0
-
-
- gain23
- 0
-
-
- ant23
-
-
-
- bw23
- 0
-
-
- center_freq24
- 0
-
-
- gain24
- 0
-
-
- ant24
-
-
-
- bw24
- 0
-
-
- center_freq25
- 0
-
-
- gain25
- 0
-
-
- ant25
-
-
-
- bw25
- 0
-
-
- center_freq26
- 0
-
-
- gain26
- 0
-
-
- ant26
-
-
-
- bw26
- 0
-
-
- center_freq27
- 0
-
-
- gain27
- 0
-
-
- ant27
-
-
-
- bw27
- 0
-
-
- center_freq28
- 0
-
-
- gain28
- 0
-
-
- ant28
-
-
-
- bw28
- 0
-
-
- center_freq29
- 0
-
-
- gain29
- 0
-
-
- ant29
-
-
-
- bw29
- 0
-
-
- center_freq30
- 0
-
-
- gain30
- 0
-
-
- ant30
-
-
-
- bw30
- 0
-
-
- center_freq31
- 0
-
-
- gain31
- 0
-
-
- ant31
-
-
-
- bw31
- 0
-
-
- _coordinate
- (53, 269)
-
-
- _rotation
- 0
-
-
-
- gr_file_meta_sink
-
- id
- gr_file_meta_sink_0
-
-
- _enabled
- True
-
-
- file
- /tmp/metadat_file.out
-
-
- type
- complex
-
-
- samp_rate
- samp_rate
-
-
- rel_rate
- 1
-
-
- vlen
- 1
-
-
- max_seg_size
- 1000000
-
-
- extra_dict
- ""
-
-
- detached
- False
-
-
- unbuffered
- False
-
-
- _coordinate
- (555, 148)
-
-
- _rotation
- 0
-
-
-
- options
-
- id
- file_metadata_sink
-
-
- _enabled
- True
-
-
- title
-
-
-
- author
-
-
-
- description
-
-
-
- window_size
- 1280, 1024
-
-
- generate_options
- qt_gui
-
-
- category
- Custom
-
-
- run_options
- prompt
-
-
- run
- True
-
-
- max_nouts
- 0
-
-
- realtime_scheduling
-
-
-
- _coordinate
- (10, 10)
-
-
- _rotation
- 0
-
-
-
- gr_head_0
- gr_file_meta_sink_0
- 0
- 0
-
-
- gr_sig_source_x_0
- gr_head_0
- 0
- 0
-
-
- uhd_usrp_source_0
- gr_head_0
- 0
- 0
-
-
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 cc1383ae1..000000000
--- a/gnuradio-core/src/examples/metadata/file_metadata_source.grc
+++ /dev/null
@@ -1,346 +0,0 @@
-
-
- Thu Dec 13 14:25:01 2012
-
- variable
-
- id
- samp_rate
-
-
- _enabled
- True
-
-
- value
- 200000
-
-
- _coordinate
- (208, 11)
-
-
- _rotation
- 0
-
-
-
- gr_tag_debug
-
- id
- gr_tag_debug_0
-
-
- _enabled
- True
-
-
- type
- complex
-
-
- name
- Test
-
-
- num_inputs
- 1
-
-
- vlen
- 1
-
-
- display
- True
-
-
- _coordinate
- (561, 290)
-
-
- _rotation
- 0
-
-
-
- gr_throttle
-
- id
- gr_throttle_0
-
-
- _enabled
- True
-
-
- type
- complex
-
-
- samples_per_second
- samp_rate
-
-
- vlen
- 1
-
-
- _coordinate
- (322, 223)
-
-
- _rotation
- 0
-
-
-
- gr_file_meta_source
-
- id
- gr_file_meta_source_0
-
-
- _enabled
- True
-
-
- type
- complex
-
-
- file
- /tmp/metadat_file.out
-
-
- repeat
- False
-
-
- detached
- False
-
-
- hdr_file
-
-
-
- _coordinate
- (56, 199)
-
-
- _rotation
- 0
-
-
-
- analog_agc2_xx
-
- id
- analog_agc2_xx_0
-
-
- _enabled
- True
-
-
- type
- complex
-
-
- attack_rate
- 1e-1
-
-
- decay_rate
- 1e-2
-
-
- reference
- 1.0
-
-
- gain
- 1.0
-
-
- max_gain
- 0.0
-
-
- _coordinate
- (561, 82)
-
-
- _rotation
- 0
-
-
-
- qtgui_time_sink_x
-
- id
- qtgui_time_sink_x_0
-
-
- _enabled
- True
-
-
- type
- complex
-
-
- name
- QT GUI Plot
-
-
- size
- 1024
-
-
- bw
- samp_rate
-
-
- nconnections
- 1
-
-
- gui_hint
-
-
-
- _coordinate
- (776, 98)
-
-
- _rotation
- 0
-
-
-
- gr_file_sink
-
- id
- gr_file_sink_1
-
-
- _enabled
- True
-
-
- file
- /tmp/received_data.out
-
-
- type
- complex
-
-
- vlen
- 1
-
-
- unbuffered
- False
-
-
- _coordinate
- (564, 215)
-
-
- _rotation
- 0
-
-
-
- options
-
- id
- file_metadata_source
-
-
- _enabled
- True
-
-
- title
-
-
-
- author
-
-
-
- description
-
-
-
- window_size
- 1280, 1024
-
-
- generate_options
- qt_gui
-
-
- category
- Custom
-
-
- run_options
- prompt
-
-
- run
- True
-
-
- max_nouts
- 0
-
-
- realtime_scheduling
-
-
-
- _coordinate
- (10, 10)
-
-
- _rotation
- 0
-
-
-
- gr_throttle_0
- gr_file_sink_1
- 0
- 0
-
-
- gr_throttle_0
- gr_tag_debug_0
- 0
- 0
-
-
- gr_file_meta_source_0
- gr_throttle_0
- 0
- 0
-
-
- gr_throttle_0
- analog_agc2_xx_0
- 0
- 0
-
-
- analog_agc2_xx_0
- qtgui_time_sink_x_0
- 0
- 0
-
-
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 d67af3a66..000000000
--- a/gnuradio-core/src/examples/metadata/file_metadata_vector_sink.grc
+++ /dev/null
@@ -1,219 +0,0 @@
-
-
- Fri Dec 14 13:52:31 2012
-
- variable
-
- id
- samp_rate
-
-
- _enabled
- True
-
-
- value
- 200000
-
-
- _coordinate
- (208, 11)
-
-
- _rotation
- 0
-
-
-
- gr_vector_source_x
-
- id
- gr_vector_source_x_0
-
-
- _enabled
- True
-
-
- type
- complex
-
-
- vector
- 10*[0,1,2,3,4,5,6,7,8,9]
-
-
- repeat
- True
-
-
- vlen
- 10
-
-
- _coordinate
- (67, 100)
-
-
- _rotation
- 0
-
-
-
- gr_file_meta_sink
-
- id
- gr_file_meta_sink_0
-
-
- _enabled
- True
-
-
- file
- /tmp/metadat_file.out
-
-
- type
- complex
-
-
- samp_rate
- samp_rate
-
-
- rel_rate
- 1
-
-
- vlen
- 10
-
-
- max_seg_size
- 1000000
-
-
- extra_dict
-
-
-
- detached
- False
-
-
- unbuffered
- False
-
-
- _coordinate
- (559, 60)
-
-
- _rotation
- 0
-
-
-
- options
-
- id
- file_metadata_vector_sink
-
-
- _enabled
- True
-
-
- title
-
-
-
- author
-
-
-
- description
-
-
-
- window_size
- 1280, 1024
-
-
- generate_options
- no_gui
-
-
- category
- Custom
-
-
- run_options
- run
-
-
- run
- True
-
-
- max_nouts
- 0
-
-
- realtime_scheduling
-
-
-
- _coordinate
- (10, 10)
-
-
- _rotation
- 0
-
-
-
- gr_head
-
- id
- gr_head_0
-
-
- _enabled
- True
-
-
- type
- complex
-
-
- num_items
- 10010000
-
-
- vlen
- 10
-
-
- _coordinate
- (325, 108)
-
-
- _rotation
- 0
-
-
-
- gr_vector_source_x_0
- gr_head_0
- 0
- 0
-
-
- gr_head_0
- gr_file_meta_sink_0
- 0
- 0
-
-
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 0662865f1..000000000
--- a/gnuradio-core/src/examples/metadata/file_metadata_vector_source.grc
+++ /dev/null
@@ -1,338 +0,0 @@
-
-
- Fri Dec 14 13:55:43 2012
-
- options
-
- id
- file_metadata_source
-
-
- _enabled
- True
-
-
- title
-
-
-
- author
-
-
-
- description
-
-
-
- window_size
- 1280, 1024
-
-
- generate_options
- qt_gui
-
-
- category
- Custom
-
-
- run_options
- prompt
-
-
- run
- True
-
-
- max_nouts
- 0
-
-
- realtime_scheduling
-
-
-
- _coordinate
- (10, 10)
-
-
- _rotation
- 0
-
-
-
- variable
-
- id
- samp_rate
-
-
- _enabled
- True
-
-
- value
- 200000
-
-
- _coordinate
- (208, 11)
-
-
- _rotation
- 0
-
-
-
- gr_file_sink
-
- id
- gr_file_sink_1
-
-
- _enabled
- True
-
-
- file
- /tmp/received_data.out
-
-
- type
- complex
-
-
- vlen
- 10
-
-
- unbuffered
- False
-
-
- _coordinate
- (564, 215)
-
-
- _rotation
- 0
-
-
-
- gr_tag_debug
-
- id
- gr_tag_debug_0
-
-
- _enabled
- True
-
-
- type
- complex
-
-
- name
- Test
-
-
- num_inputs
- 1
-
-
- vlen
- 10
-
-
- display
- True
-
-
- _coordinate
- (563, 298)
-
-
- _rotation
- 0
-
-
-
- gr_file_meta_source
-
- id
- gr_file_meta_source_0
-
-
- _enabled
- True
-
-
- type
- complex
-
-
- file
- /tmp/metadat_file.out
-
-
- repeat
- False
-
-
- detached
- False
-
-
- hdr_file
- /tmp/metadat_file.out.hdr
-
-
- vlen
- 10
-
-
- _coordinate
- (51, 199)
-
-
- _rotation
- 0
-
-
-
- qtgui_time_sink_x
-
- id
- qtgui_time_sink_x_0
-
-
- _enabled
- True
-
-
- type
- complex
-
-
- name
- QT GUI Plot
-
-
- size
- 1024
-
-
- bw
- samp_rate
-
-
- nconnections
- 1
-
-
- gui_hint
-
-
-
- _coordinate
- (746, 116)
-
-
- _rotation
- 0
-
-
-
- gr_throttle
-
- id
- gr_throttle_0
-
-
- _enabled
- True
-
-
- type
- complex
-
-
- samples_per_second
- samp_rate
-
-
- vlen
- 10
-
-
- _coordinate
- (322, 223)
-
-
- _rotation
- 0
-
-
-
- blocks_vector_to_stream
-
- id
- blocks_vector_to_stream_0
-
-
- _enabled
- True
-
-
- type
- complex
-
-
- num_items
- 10
-
-
- vlen
- 1
-
-
- _coordinate
- (526, 132)
-
-
- _rotation
- 0
-
-
-
- gr_throttle_0
- gr_file_sink_1
- 0
- 0
-
-
- gr_throttle_0
- gr_tag_debug_0
- 0
- 0
-
-
- gr_file_meta_source_0
- gr_throttle_0
- 0
- 0
-
-
- blocks_vector_to_stream_0
- qtgui_time_sink_x_0
- 0
- 0
-
-
- gr_throttle_0
- blocks_vector_to_stream_0
- 0
- 0
-
-
diff --git a/gnuradio-core/src/lib/io/CMakeLists.txt b/gnuradio-core/src/lib/io/CMakeLists.txt
index 1cbcd2daf..59ca06b5a 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 ab0acbdb4..000000000
--- 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
-#include
-#include
-#include
-#include
-#include
-#include
-
-// win32 (mingw/msvc) specific
-#ifdef HAVE_IO_H
-#include
-#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(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 all_tags;
- get_tags_in_range(all_tags, 0, abs_N, end_N);
-
- std::vector::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 9b67cc4c8..000000000
--- 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
-#include
-#include
-#include
-
-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_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 6fa34913b..000000000
--- 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 d940e5edc..000000000
--- 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
-#include
-#include
-#include
-#include
-#include
-#include
-
-// win32 (mingw/msvc) specific
-#ifdef HAVE_IO_H
-#include
-#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 &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 &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 95e466936..000000000
--- 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
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-class gr_file_meta_source;
-typedef boost::shared_ptr 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 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 &tags);
- void parse_extras(pmt_t extras, uint64_t offset,
- std::vector &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 cb1281036..000000000
--- 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 5885214d8..e2de4eb97 100644
--- a/gnuradio-core/src/lib/io/io.i
+++ b/gnuradio-core/src/lib/io/io.i
@@ -27,9 +27,7 @@
#endif
#include
-#include
#include
-#include
#include
#include
#include
@@ -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 31cde6921..bf696e0d3 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 849f32299..000000000
--- 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 0cee5a02c..000000000
--- 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 9c81ba6bf..7e2f43562 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 000000000..79535daa0
--- /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 000000000..53a54b9d5
--- /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 000000000..198b0725f
--- /dev/null
+++ b/gr-blocks/examples/metadata/file_metadata_sink.grc
@@ -0,0 +1,951 @@
+
+
+ Fri Dec 14 17:09:06 2012
+
+ options
+
+ id
+ file_metadata_sink
+
+
+ _enabled
+ True
+
+
+ title
+
+
+
+ author
+
+
+
+ description
+
+
+
+ window_size
+ 1280, 1024
+
+
+ generate_options
+ qt_gui
+
+
+ category
+ Custom
+
+
+ run_options
+ prompt
+
+
+ run
+ True
+
+
+ max_nouts
+ 0
+
+
+ realtime_scheduling
+
+
+
+ _coordinate
+ (10, 10)
+
+
+ _rotation
+ 0
+
+
+
+ gr_sig_source_x
+
+ id
+ gr_sig_source_x_0
+
+
+ _enabled
+ False
+
+
+ type
+ complex
+
+
+ samp_rate
+ samp_rate
+
+
+ waveform
+ gr.GR_COS_WAVE
+
+
+ freq
+ 1000
+
+
+ amp
+ 1
+
+
+ offset
+ 0
+
+
+ _coordinate
+ (57, 140)
+
+
+ _rotation
+ 0
+
+
+
+ variable_qtgui_range
+
+ id
+ qt_samp_rate
+
+
+ _enabled
+ True
+
+
+ label
+
+
+
+ value
+ samp_rate
+
+
+ start
+ 200000
+
+
+ stop
+ 5000000
+
+
+ step
+ 200000
+
+
+ widget
+ counter_slider
+
+
+ orient
+ Qt.Horizontal
+
+
+ min_len
+ 200
+
+
+ gui_hint
+
+
+
+ _coordinate
+ (330, 259)
+
+
+ _rotation
+ 0
+
+
+
+ variable
+
+ id
+ samp_rate
+
+
+ _enabled
+ True
+
+
+ value
+ 200000
+
+
+ _coordinate
+ (208, 11)
+
+
+ _rotation
+ 0
+
+
+
+ uhd_usrp_source
+
+ id
+ uhd_usrp_source_0
+
+
+ _enabled
+ True
+
+
+ type
+ fc32
+
+
+ otw
+
+
+
+ stream_args
+
+
+
+ dev_addr
+ addr=192.168.11.2
+
+
+ sync
+
+
+
+ clock_rate
+ 0.0
+
+
+ num_mboards
+ 1
+
+
+ clock_source0
+
+
+
+ time_source0
+
+
+
+ sd_spec0
+
+
+
+ clock_source1
+
+
+
+ time_source1
+
+
+
+ sd_spec1
+
+
+
+ clock_source2
+
+
+
+ time_source2
+
+
+
+ sd_spec2
+
+
+
+ clock_source3
+
+
+
+ time_source3
+
+
+
+ sd_spec3
+
+
+
+ clock_source4
+
+
+
+ time_source4
+
+
+
+ sd_spec4
+
+
+
+ clock_source5
+
+
+
+ time_source5
+
+
+
+ sd_spec5
+
+
+
+ clock_source6
+
+
+
+ time_source6
+
+
+
+ sd_spec6
+
+
+
+ clock_source7
+
+
+
+ time_source7
+
+
+
+ sd_spec7
+
+
+
+ nchan
+ 1
+
+
+ samp_rate
+ qt_samp_rate
+
+
+ center_freq0
+ 98.9e6
+
+
+ gain0
+ 30
+
+
+ ant0
+
+
+
+ bw0
+ 0
+
+
+ center_freq1
+ 0
+
+
+ gain1
+ 0
+
+
+ ant1
+
+
+
+ bw1
+ 0
+
+
+ center_freq2
+ 0
+
+
+ gain2
+ 0
+
+
+ ant2
+
+
+
+ bw2
+ 0
+
+
+ center_freq3
+ 0
+
+
+ gain3
+ 0
+
+
+ ant3
+
+
+
+ bw3
+ 0
+
+
+ center_freq4
+ 0
+
+
+ gain4
+ 0
+
+
+ ant4
+
+
+
+ bw4
+ 0
+
+
+ center_freq5
+ 0
+
+
+ gain5
+ 0
+
+
+ ant5
+
+
+
+ bw5
+ 0
+
+
+ center_freq6
+ 0
+
+
+ gain6
+ 0
+
+
+ ant6
+
+
+
+ bw6
+ 0
+
+
+ center_freq7
+ 0
+
+
+ gain7
+ 0
+
+
+ ant7
+
+
+
+ bw7
+ 0
+
+
+ center_freq8
+ 0
+
+
+ gain8
+ 0
+
+
+ ant8
+
+
+
+ bw8
+ 0
+
+
+ center_freq9
+ 0
+
+
+ gain9
+ 0
+
+
+ ant9
+
+
+
+ bw9
+ 0
+
+
+ center_freq10
+ 0
+
+
+ gain10
+ 0
+
+
+ ant10
+
+
+
+ bw10
+ 0
+
+
+ center_freq11
+ 0
+
+
+ gain11
+ 0
+
+
+ ant11
+
+
+
+ bw11
+ 0
+
+
+ center_freq12
+ 0
+
+
+ gain12
+ 0
+
+
+ ant12
+
+
+
+ bw12
+ 0
+
+
+ center_freq13
+ 0
+
+
+ gain13
+ 0
+
+
+ ant13
+
+
+
+ bw13
+ 0
+
+
+ center_freq14
+ 0
+
+
+ gain14
+ 0
+
+
+ ant14
+
+
+
+ bw14
+ 0
+
+
+ center_freq15
+ 0
+
+
+ gain15
+ 0
+
+
+ ant15
+
+
+
+ bw15
+ 0
+
+
+ center_freq16
+ 0
+
+
+ gain16
+ 0
+
+
+ ant16
+
+
+
+ bw16
+ 0
+
+
+ center_freq17
+ 0
+
+
+ gain17
+ 0
+
+
+ ant17
+
+
+
+ bw17
+ 0
+
+
+ center_freq18
+ 0
+
+
+ gain18
+ 0
+
+
+ ant18
+
+
+
+ bw18
+ 0
+
+
+ center_freq19
+ 0
+
+
+ gain19
+ 0
+
+
+ ant19
+
+
+
+ bw19
+ 0
+
+
+ center_freq20
+ 0
+
+
+ gain20
+ 0
+
+
+ ant20
+
+
+
+ bw20
+ 0
+
+
+ center_freq21
+ 0
+
+
+ gain21
+ 0
+
+
+ ant21
+
+
+
+ bw21
+ 0
+
+
+ center_freq22
+ 0
+
+
+ gain22
+ 0
+
+
+ ant22
+
+
+
+ bw22
+ 0
+
+
+ center_freq23
+ 0
+
+
+ gain23
+ 0
+
+
+ ant23
+
+
+
+ bw23
+ 0
+
+
+ center_freq24
+ 0
+
+
+ gain24
+ 0
+
+
+ ant24
+
+
+
+ bw24
+ 0
+
+
+ center_freq25
+ 0
+
+
+ gain25
+ 0
+
+
+ ant25
+
+
+
+ bw25
+ 0
+
+
+ center_freq26
+ 0
+
+
+ gain26
+ 0
+
+
+ ant26
+
+
+
+ bw26
+ 0
+
+
+ center_freq27
+ 0
+
+
+ gain27
+ 0
+
+
+ ant27
+
+
+
+ bw27
+ 0
+
+
+ center_freq28
+ 0
+
+
+ gain28
+ 0
+
+
+ ant28
+
+
+
+ bw28
+ 0
+
+
+ center_freq29
+ 0
+
+
+ gain29
+ 0
+
+
+ ant29
+
+
+
+ bw29
+ 0
+
+
+ center_freq30
+ 0
+
+
+ gain30
+ 0
+
+
+ ant30
+
+
+
+ bw30
+ 0
+
+
+ center_freq31
+ 0
+
+
+ gain31
+ 0
+
+
+ ant31
+
+
+
+ bw31
+ 0
+
+
+ _coordinate
+ (53, 269)
+
+
+ _rotation
+ 0
+
+
+
+ gr_head
+
+ id
+ gr_head_0
+
+
+ _enabled
+ True
+
+
+ type
+ complex
+
+
+ num_items
+ 20000000
+
+
+ vlen
+ 1
+
+
+ _coordinate
+ (309, 172)
+
+
+ _rotation
+ 0
+
+
+
+ blocks_file_meta_sink
+
+ id
+ blocks_file_meta_sink_0
+
+
+ _enabled
+ True
+
+
+ file
+ /tmp/metadat_file.out
+
+
+ type
+ complex
+
+
+ samp_rate
+ samp_rate
+
+
+ rel_rate
+ 1
+
+
+ vlen
+ 1
+
+
+ max_seg_size
+ 1000000
+
+
+ extra_dict
+ ""
+
+
+ detached
+ True
+
+
+ unbuffered
+ False
+
+
+ _coordinate
+ (569, 124)
+
+
+ _rotation
+ 0
+
+
+
+ gr_sig_source_x_0
+ gr_head_0
+ 0
+ 0
+
+
+ uhd_usrp_source_0
+ gr_head_0
+ 0
+ 0
+
+
+ gr_head_0
+ blocks_file_meta_sink_0
+ 0
+ 0
+
+
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 000000000..23757881b
--- /dev/null
+++ b/gr-blocks/examples/metadata/file_metadata_source.grc
@@ -0,0 +1,350 @@
+
+
+ Fri Dec 14 17:08:09 2012
+
+ options
+
+ id
+ file_metadata_source
+
+
+ _enabled
+ True
+
+
+ title
+
+
+
+ author
+
+
+
+ description
+
+
+
+ window_size
+ 1280, 1024
+
+
+ generate_options
+ qt_gui
+
+
+ category
+ Custom
+
+
+ run_options
+ prompt
+
+
+ run
+ True
+
+
+ max_nouts
+ 0
+
+
+ realtime_scheduling
+
+
+
+ _coordinate
+ (10, 10)
+
+
+ _rotation
+ 0
+
+
+
+ variable
+
+ id
+ samp_rate
+
+
+ _enabled
+ True
+
+
+ value
+ 200000
+
+
+ _coordinate
+ (208, 11)
+
+
+ _rotation
+ 0
+
+
+
+ gr_tag_debug
+
+ id
+ gr_tag_debug_0
+
+
+ _enabled
+ True
+
+
+ type
+ complex
+
+
+ name
+ Test
+
+
+ num_inputs
+ 1
+
+
+ vlen
+ 1
+
+
+ display
+ True
+
+
+ _coordinate
+ (561, 290)
+
+
+ _rotation
+ 0
+
+
+
+ analog_agc2_xx
+
+ id
+ analog_agc2_xx_0
+
+
+ _enabled
+ True
+
+
+ type
+ complex
+
+
+ attack_rate
+ 1e-1
+
+
+ decay_rate
+ 1e-2
+
+
+ reference
+ 1.0
+
+
+ gain
+ 1.0
+
+
+ max_gain
+ 0.0
+
+
+ _coordinate
+ (561, 82)
+
+
+ _rotation
+ 0
+
+
+
+ qtgui_time_sink_x
+
+ id
+ qtgui_time_sink_x_0
+
+
+ _enabled
+ True
+
+
+ type
+ complex
+
+
+ name
+ QT GUI Plot
+
+
+ size
+ 1024
+
+
+ bw
+ samp_rate
+
+
+ nconnections
+ 1
+
+
+ gui_hint
+
+
+
+ _coordinate
+ (776, 98)
+
+
+ _rotation
+ 0
+
+
+
+ gr_file_sink
+
+ id
+ gr_file_sink_1
+
+
+ _enabled
+ True
+
+
+ file
+ /tmp/received_data.out
+
+
+ type
+ complex
+
+
+ vlen
+ 1
+
+
+ unbuffered
+ False
+
+
+ _coordinate
+ (564, 215)
+
+
+ _rotation
+ 0
+
+
+
+ gr_throttle
+
+ id
+ gr_throttle_0
+
+
+ _enabled
+ True
+
+
+ type
+ complex
+
+
+ samples_per_second
+ samp_rate
+
+
+ vlen
+ 1
+
+
+ _coordinate
+ (322, 222)
+
+
+ _rotation
+ 0
+
+
+
+ blocks_file_meta_source
+
+ id
+ blocks_file_meta_source_0
+
+
+ _enabled
+ True
+
+
+ type
+ complex
+
+
+ file
+ /tmp/metadat_file.out
+
+
+ repeat
+ False
+
+
+ detached
+ True
+
+
+ hdr_file
+
+
+
+ vlen
+ 1
+
+
+ _coordinate
+ (50, 198)
+
+
+ _rotation
+ 0
+
+
+
+ gr_throttle_0
+ gr_file_sink_1
+ 0
+ 0
+
+
+ gr_throttle_0
+ gr_tag_debug_0
+ 0
+ 0
+
+
+ gr_throttle_0
+ analog_agc2_xx_0
+ 0
+ 0
+
+
+ analog_agc2_xx_0
+ qtgui_time_sink_x_0
+ 0
+ 0
+
+
+ blocks_file_meta_source_0
+ gr_throttle_0
+ 0
+ 0
+
+
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 000000000..05b7cbc92
--- /dev/null
+++ b/gr-blocks/examples/metadata/file_metadata_vector_sink.grc
@@ -0,0 +1,219 @@
+
+
+ Fri Dec 14 17:08:29 2012
+
+ options
+
+ id
+ file_metadata_vector_sink
+
+
+ _enabled
+ True
+
+
+ title
+
+
+
+ author
+
+
+
+ description
+
+
+
+ window_size
+ 1280, 1024
+
+
+ generate_options
+ no_gui
+
+
+ category
+ Custom
+
+
+ run_options
+ run
+
+
+ run
+ True
+
+
+ max_nouts
+ 0
+
+
+ realtime_scheduling
+
+
+
+ _coordinate
+ (10, 10)
+
+
+ _rotation
+ 0
+
+
+
+ variable
+
+ id
+ samp_rate
+
+
+ _enabled
+ True
+
+
+ value
+ 200000
+
+
+ _coordinate
+ (208, 11)
+
+
+ _rotation
+ 0
+
+
+
+ gr_vector_source_x
+
+ id
+ gr_vector_source_x_0
+
+
+ _enabled
+ True
+
+
+ type
+ complex
+
+
+ vector
+ 10*[0,1,2,3,4,5,6,7,8,9]
+
+
+ repeat
+ True
+
+
+ vlen
+ 10
+
+
+ _coordinate
+ (67, 100)
+
+
+ _rotation
+ 0
+
+
+
+ gr_head
+
+ id
+ gr_head_0
+
+
+ _enabled
+ True
+
+
+ type
+ complex
+
+
+ num_items
+ 10010000
+
+
+ vlen
+ 10
+
+
+ _coordinate
+ (325, 108)
+
+
+ _rotation
+ 0
+
+
+
+ blocks_file_meta_sink
+
+ id
+ blocks_file_meta_sink_0
+
+
+ _enabled
+ True
+
+
+ file
+ /tmp/metadat_vector.out
+
+
+ type
+ complex
+
+
+ samp_rate
+ samp_rate
+
+
+ rel_rate
+ 1
+
+
+ vlen
+ 10
+
+
+ max_seg_size
+ 1000000
+
+
+ extra_dict
+ ""
+
+
+ detached
+ True
+
+
+ unbuffered
+ False
+
+
+ _coordinate
+ (544, 60)
+
+
+ _rotation
+ 0
+
+
+
+ gr_vector_source_x_0
+ gr_head_0
+ 0
+ 0
+
+
+ gr_head_0
+ blocks_file_meta_sink_0
+ 0
+ 0
+
+
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 000000000..d52257e06
--- /dev/null
+++ b/gr-blocks/examples/metadata/file_metadata_vector_source.grc
@@ -0,0 +1,338 @@
+
+
+ Fri Dec 14 17:11:02 2012
+
+ options
+
+ id
+ file_metadata_vector_source
+
+
+ _enabled
+ True
+
+
+ title
+
+
+
+ author
+
+
+
+ description
+
+
+
+ window_size
+ 1280, 1024
+
+
+ generate_options
+ qt_gui
+
+
+ category
+ Custom
+
+
+ run_options
+ prompt
+
+
+ run
+ True
+
+
+ max_nouts
+ 0
+
+
+ realtime_scheduling
+
+
+
+ _coordinate
+ (10, 10)
+
+
+ _rotation
+ 0
+
+
+
+ variable
+
+ id
+ samp_rate
+
+
+ _enabled
+ True
+
+
+ value
+ 200000
+
+
+ _coordinate
+ (208, 11)
+
+
+ _rotation
+ 0
+
+
+
+ gr_file_sink
+
+ id
+ gr_file_sink_1
+
+
+ _enabled
+ True
+
+
+ file
+ /tmp/received_data.out
+
+
+ type
+ complex
+
+
+ vlen
+ 10
+
+
+ unbuffered
+ False
+
+
+ _coordinate
+ (564, 215)
+
+
+ _rotation
+ 0
+
+
+
+ gr_tag_debug
+
+ id
+ gr_tag_debug_0
+
+
+ _enabled
+ True
+
+
+ type
+ complex
+
+
+ name
+ Test
+
+
+ num_inputs
+ 1
+
+
+ vlen
+ 10
+
+
+ display
+ True
+
+
+ _coordinate
+ (563, 298)
+
+
+ _rotation
+ 0
+
+
+
+ qtgui_time_sink_x
+
+ id
+ qtgui_time_sink_x_0
+
+
+ _enabled
+ True
+
+
+ type
+ complex
+
+
+ name
+ QT GUI Plot
+
+
+ size
+ 1024
+
+
+ bw
+ samp_rate
+
+
+ nconnections
+ 1
+
+
+ gui_hint
+
+
+
+ _coordinate
+ (746, 116)
+
+
+ _rotation
+ 0
+
+
+
+ blocks_vector_to_stream
+
+ id
+ blocks_vector_to_stream_0
+
+
+ _enabled
+ True
+
+
+ type
+ complex
+
+
+ num_items
+ 10
+
+
+ vlen
+ 1
+
+
+ _coordinate
+ (526, 132)
+
+
+ _rotation
+ 0
+
+
+
+ gr_throttle
+
+ id
+ gr_throttle_0
+
+
+ _enabled
+ True
+
+
+ type
+ complex
+
+
+ samples_per_second
+ samp_rate
+
+
+ vlen
+ 10
+
+
+ _coordinate
+ (322, 223)
+
+
+ _rotation
+ 0
+
+
+
+ blocks_file_meta_source
+
+ id
+ blocks_file_meta_source_0
+
+
+ _enabled
+ True
+
+
+ type
+ complex
+
+
+ file
+ /tmp/metadat_vector.out
+
+
+ repeat
+ False
+
+
+ detached
+ True
+
+
+ hdr_file
+
+
+
+ vlen
+ 10
+
+
+ _coordinate
+ (42, 199)
+
+
+ _rotation
+ 0
+
+
+
+ gr_throttle_0
+ gr_file_sink_1
+ 0
+ 0
+
+
+ gr_throttle_0
+ gr_tag_debug_0
+ 0
+ 0
+
+
+ blocks_vector_to_stream_0
+ qtgui_time_sink_x_0
+ 0
+ 0
+
+
+ gr_throttle_0
+ blocks_vector_to_stream_0
+ 0
+ 0
+
+
+ blocks_file_meta_source_0
+ gr_throttle_0
+ 0
+ 0
+
+
diff --git a/gr-blocks/grc/blocks_block_tree.xml b/gr-blocks/grc/blocks_block_tree.xml
index ea5e552d1..797b3dbc5 100644
--- a/gr-blocks/grc/blocks_block_tree.xml
+++ b/gr-blocks/grc/blocks_block_tree.xml
@@ -31,6 +31,11 @@
Sources (New)
blocks_file_source
+ blocks_file_meta_source
+
+
+ Sinks (New)
+ blocks_file_meta_sink
Math Operations (New)
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 000000000..f6490d507
--- /dev/null
+++ b/gr-blocks/grc/blocks_file_meta_sink.xml
@@ -0,0 +1,124 @@
+
+
+
+ File Meta Sink
+ blocks_file_meta_sink
+ from gnuradio import gr, blocks
+ 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)
+ set_unbuffered($unbuffered)
+ open($file)
+
+ File
+ file
+
+ file_save
+
+
+ Input Type
+ type
+ enum
+
+
+
+
+
+
+
+ Sample Rate
+ samp_rate
+ samp_rate
+ real
+
+
+ Relative Rate Change
+ rel_rate
+ 1
+ real
+
+
+ Vec Length
+ vlen
+ 1
+ int
+
+
+ Max Seg. Size
+ max_seg_size
+ 1000000
+ int
+
+
+ Extra Dict.
+ extra_dict
+ ""
+ string
+
+
+ Detached
+ detached
+ False
+ bool
+
+
+
+ Unbuffered
+ unbuffered
+ False
+ bool
+
+
+
+ $vlen > 0
+
+ in
+ $type
+ $vlen
+
+
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 000000000..aa7e34955
--- /dev/null
+++ b/gr-blocks/grc/blocks_file_meta_source.xml
@@ -0,0 +1,94 @@
+
+
+
+ File Meta Source
+ blocks_file_meta_source
+ from gnuradio import gr, blocks
+ blocks.file_meta_source($file, $repeat, $detached, $hdr_file)
+ open($file, $repeat)
+
+ Output Type
+ type
+ enum
+
+
+
+
+
+
+
+ File
+ file
+
+ file_open
+
+
+ Repeat
+ repeat
+ True
+ enum
+
+
+
+
+ Detached Header
+ detached
+ False
+ enum
+
+
+
+
+ Header File
+ hdr_file
+
+ file_open
+
+
+ Vec Length
+ vlen
+ 1
+ int
+
+
+ out
+ $type
+ $vlen
+
+
diff --git a/gr-blocks/include/blocks/CMakeLists.txt b/gr-blocks/include/blocks/CMakeLists.txt
index 787fddba3..0459097b0 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 000000000..ef64887cf
--- /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
+#include
+
+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 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 000000000..a992d5243
--- /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
+#include
+
+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 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 3a8ffac75..ab989fc78 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 000000000..ad16e9fca
--- /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
+#include
+#include
+#include
+#include
+#include
+
+namespace gr {
+ namespace blocks {
+
+// win32 (mingw/msvc) specific
+#ifdef HAVE_IO_H
+#include
+#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(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 all_tags;
+ get_tags_in_range(all_tags, 0, abs_N, end_N);
+
+ std::vector::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 000000000..566c997b3
--- /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
+#include
+#include
+
+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 000000000..fb39b205b
--- /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
+#include
+#include
+#include
+#include
+#include
+
+namespace gr {
+ namespace blocks {
+
+// win32 (mingw/msvc) specific
+#ifdef HAVE_IO_H
+#include
+#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 &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 &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 000000000..ca7ddc6e1
--- /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
+#include
+#include
+#include
+
+#include
+
+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 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 &tags);
+ void parse_extras(pmt_t extras, uint64_t offset,
+ std::vector &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 710ab155c..cab0b956f 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 000000000..ec7bf6e80
--- /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 000000000..9f4a331d6
--- /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 7ec6bb423..53eea818f 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 efbf8d15d..cf0cd5b11 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 f1c68c7c9..183883959 100644
--- a/grc/blocks/block_tree.xml
+++ b/grc/blocks/block_tree.xml
@@ -29,8 +29,6 @@
gr_vector_sink_x
gr_null_sink
gr_file_sink
- gr_file_meta_source
- gr_file_meta_sink
blks2_tcp_sink
gr_udp_sink
gr_wavfile_sink
diff --git a/grc/blocks/gr_file_meta_sink.xml b/grc/blocks/gr_file_meta_sink.xml
deleted file mode 100644
index ba9bf4ee1..000000000
--- a/grc/blocks/gr_file_meta_sink.xml
+++ /dev/null
@@ -1,124 +0,0 @@
-
-
-
- File Meta Sink
- gr_file_meta_sink
- from gnuradio import gr
- 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)
- set_unbuffered($unbuffered)
- open($file)
-
- File
- file
-
- file_save
-
-
- Input Type
- type
- enum
-
-
-
-
-
-
-
- Sample Rate
- samp_rate
- samp_rate
- real
-
-
- Relative Rate Change
- rel_rate
- 1
- real
-
-
- Vec Length
- vlen
- 1
- int
-
-
- Max Seg. Size
- max_seg_size
- 1000000
- int
-
-
- Extra Dict.
- extra_dict
- ""
- string
-
-
- Detached
- detached
- False
- bool
-
-
-
- Unbuffered
- unbuffered
- False
- bool
-
-
-
- $vlen > 0
-
- in
- $type
- $vlen
-
-
diff --git a/grc/blocks/gr_file_meta_source.xml b/grc/blocks/gr_file_meta_source.xml
deleted file mode 100644
index 8f667961e..000000000
--- a/grc/blocks/gr_file_meta_source.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
-
- File Meta Source
- gr_file_meta_source
- from gnuradio import gr
- gr.file_meta_source($file, $repeat, $detached, $hdr_file)
- open($file, $repeat)
-
- Output Type
- type
- enum
-
-
-
-
-
-
-
- File
- file
-
- file_open
-
-
- Repeat
- repeat
- True
- enum
-
-
-
-
- Detached Header
- detached
- False
- enum
-
-
-
-
- Header File
- hdr_file
-
- file_open
-
-
- Vec Length
- vlen
- 1
- int
-
-
- out
- $type
- $vlen
-
-
--
cgit