diff options
Diffstat (limited to 'gnuradio-core')
-rw-r--r-- | gnuradio-core/src/lib/io/gr_file_meta_sink.cc | 119 | ||||
-rw-r--r-- | gnuradio-core/src/lib/io/gr_file_meta_sink.h | 15 | ||||
-rw-r--r-- | gnuradio-core/src/lib/io/gr_file_meta_sink.i | 5 | ||||
-rw-r--r-- | gnuradio-core/src/python/gnuradio/parse_file_metadata.py | 13 |
4 files changed, 96 insertions, 56 deletions
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 401d8299d..ebfeb4e4a 100644 --- a/gnuradio-core/src/lib/io/gr_file_meta_sink.cc +++ b/gnuradio-core/src/lib/io/gr_file_meta_sink.cc @@ -28,31 +28,32 @@ #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, double relative_rate, gr_file_types type, bool complex, + size_t max_segment_size, const std::string &extra_dict) { return gnuradio::get_initial_sptr (new gr_file_meta_sink(itemsize, filename, samp_rate, relative_rate, type, complex, + max_segment_size, extra_dict)); } gr_file_meta_sink::gr_file_meta_sink(size_t itemsize, const char *filename, double samp_rate, double relative_rate, gr_file_types type, bool complex, + size_t max_segment_size, 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_relative_rate(relative_rate), - d_total_seg_size(0) + d_max_seg_size(max_segment_size), d_total_seg_size(0) { if(!open(filename)) throw std::runtime_error("file_meta_sink: can't open file\n"); @@ -77,11 +78,12 @@ gr_file_meta_sink::gr_file_meta_sink(size_t itemsize, const char *filename, 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("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_extra_size)); + d_header = pmt_dict_add(d_header, mp("strt"), pmt_from_uint64(METADATA_HEADER_SIZE+d_extra_size)); d_header = pmt_dict_add(d_header, mp("size"), pmt_from_uint64(0)); write_header(d_header, d_extra); @@ -95,7 +97,7 @@ gr_file_meta_sink::write_header(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() != HEADER_SIZE) && (extra_str.size() != d_extra_size)) + 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; @@ -144,31 +146,63 @@ gr_file_meta_sink::update_header(pmt_t key, pmt_t value) } } +void +gr_file_meta_sink::update_last_header() +{ + // Update the last header info with the number of samples this + // block represents. + 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); + write_header(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); + 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); + 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) - (HEADER_SIZE+d_extra_size); + loc = pmt_to_uint64(v) - (METADATA_HEADER_SIZE+d_extra_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, d_extra); - } + update_last_header(); } int @@ -188,7 +222,7 @@ gr_file_meta_sink::work(int noutput_items, 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 @@ -200,50 +234,27 @@ gr_file_meta_sink::work(int noutput_items, } } 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, d_extra); - } - + update_last_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 + 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, d_extra); - } - } + write_and_update(); } } } while(nwritten < noutput_items) { - int count = fwrite(inbuf, d_itemsize, noutput_items - nwritten, d_fp); + 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(); + write_and_update(); + } } if(d_unbuffered) 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 9ba4878d1..f02c2c4ad 100644 --- a/gnuradio-core/src/lib/io/gr_file_meta_sink.h +++ b/gnuradio-core/src/lib/io/gr_file_meta_sink.h @@ -30,6 +30,9 @@ using namespace pmt; +const char METADATA_VERSION = 0; +const size_t METADATA_HEADER_SIZE = 134; + enum gr_file_types { GR_FILE_BYTE=0, GR_FILE_CHAR=0, @@ -48,6 +51,7 @@ GR_CORE_API gr_file_meta_sink_sptr gr_make_file_meta_sink(size_t itemsize, const char *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=""); /*! @@ -86,6 +90,8 @@ class GR_CORE_API gr_file_meta_sink : public gr_sync_block, public gr_file_sink_ * 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. */ @@ -93,12 +99,14 @@ class GR_CORE_API gr_file_meta_sink : public gr_sync_block, public gr_file_sink_ gr_make_file_meta_sink(size_t itemsize, const char *filename, double samp_rate, double relative_rate, gr_file_types type, bool complex, + size_t max_segment_size, const std::string &extra_dict); private: size_t d_itemsize; double d_relative_rate; - uint64_t d_total_seg_size; + 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; @@ -107,15 +115,20 @@ class GR_CORE_API gr_file_meta_sink : public gr_sync_block, public gr_file_sink_ gr_file_meta_sink(size_t itemsize, const char *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=""); void write_header(pmt_t header, pmt_t extra); bool update_header(pmt_t key, pmt_t value); + void update_last_header(); + void write_and_update(); uint64_t get_last_header_loc(); public: ~gr_file_meta_sink(); + //FIXME: add setters/getters for properties. + int work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); 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 b58a519ce..6cced3f38 100644 --- a/gnuradio-core/src/lib/io/gr_file_meta_sink.i +++ b/gnuradio-core/src/lib/io/gr_file_meta_sink.i @@ -22,6 +22,9 @@ GR_SWIG_BLOCK_MAGIC(gr,file_meta_sink) +const char METADATA_VERSION = 0; +const size_t METADATA_HEADER_SIZE = 134; + enum gr_file_types { GR_FILE_BYTE=0, GR_FILE_CHAR=0, @@ -37,6 +40,7 @@ gr_file_meta_sink_sptr gr_make_file_meta_sink(size_t itemsize, const char *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=""); class gr_file_meta_sink : public gr_sync_block, public gr_file_sink_base @@ -45,6 +49,7 @@ class gr_file_meta_sink : public gr_sync_block, public gr_file_sink_base gr_file_meta_sink(size_t itemsize, const char *filename, double samp_rate, double relative_rate, gr_file_types type, bool complex, + size_t max_segment_size, 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 c8a9fbde1..31ba5f7f0 100644 --- a/gnuradio-core/src/python/gnuradio/parse_file_metadata.py +++ b/gnuradio-core/src/python/gnuradio/parse_file_metadata.py @@ -32,7 +32,8 @@ strt Start of data (or size of header) in bytes size Size of data in bytes ''' -HEADER_LENGTH = 117 +HEADER_LENGTH = gr.METADATA_HEADER_SIZE + ftype_to_string = {gr.GR_FILE_BYTE: "bytes", gr.GR_FILE_SHORT: "short", gr.GR_FILE_INT: "int", @@ -58,6 +59,16 @@ def parse_header(p, hdr_start, VERBOSE=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(gr.pmt_dict_has_key(p, gr.pmt_string_to_symbol("version"))): + r = gr.pmt_dict_ref(p, gr.pmt_string_to_symbol("version"), dump) + version = gr.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(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) |