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