diff options
-rw-r--r-- | gr-blocks/grc/blocks_file_source.xml | 14 | ||||
-rw-r--r-- | gr-blocks/include/gnuradio/blocks/file_source.h | 31 | ||||
-rw-r--r-- | gr-blocks/lib/file_source_impl.cc | 200 | ||||
-rw-r--r-- | gr-blocks/lib/file_source_impl.h | 14 | ||||
-rw-r--r-- | gr-blocks/python/blocks/qa_file_descriptor_source_sink.py | 70 | ||||
-rw-r--r-- | gr-blocks/python/blocks/qa_file_sink.py | 60 | ||||
-rw-r--r-- | gr-blocks/python/blocks/qa_file_source.py | 153 | ||||
-rw-r--r-- | gr-blocks/python/blocks/qa_file_source_sink.py | 167 |
8 files changed, 453 insertions, 256 deletions
diff --git a/gr-blocks/grc/blocks_file_source.xml b/gr-blocks/grc/blocks_file_source.xml index 1f09e95168..e8ebd98706 100644 --- a/gr-blocks/grc/blocks_file_source.xml +++ b/gr-blocks/grc/blocks_file_source.xml @@ -9,7 +9,7 @@ <key>blocks_file_source</key> <import>from gnuradio import blocks</import> <import>import pmt</import> - <make>blocks.file_source($type.size*$vlen, $file, $repeat) + <make>blocks.file_source($type.size*$vlen, $file, $repeat, $offset, $length) self.$(id).set_begin_tag($begin_tag)</make> <callback>open($file, $repeat)</callback> <callback>self.$(id).set_begin_tag($begin_tag)</callback> @@ -76,6 +76,18 @@ self.$(id).set_begin_tag($begin_tag)</make> <value>pmt.PMT_NIL</value> <type>raw</type> </param> + <param> + <name>Offset</name> + <key>offset</key> + <value>0</value> + <type>int</type> + </param> + <param> + <name>Length</name> + <key>length</key> + <value>0</value> + <type>int</type> + </param> <check>$vlen > 0</check> <source> <name>out</name> diff --git a/gr-blocks/include/gnuradio/blocks/file_source.h b/gr-blocks/include/gnuradio/blocks/file_source.h index c8138339fd..cd73c97d02 100644 --- a/gr-blocks/include/gnuradio/blocks/file_source.h +++ b/gr-blocks/include/gnuradio/blocks/file_source.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2012 Free Software Foundation, Inc. + * Copyright 2012, 2018 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -46,32 +46,41 @@ namespace gr { * Opens \p filename as a source of items into a flowgraph. The * data is expected to be in binary format, item after item. The * \p itemsize of the block determines the conversion from bits - * to items. + * to items. The first \p offset items (default 0) will be + * skipped. * * If \p repeat is turned on, the file will repeat the file after * it's reached the end. * - * \param itemsize the size of each item in the file, in bytes - * \param filename name of the file to source from - * \param repeat repeat file from start + * If \p len is non-zero, only items [offset, offset+len) will + * be produced. + * + * \param itemsize the size of each item in the file, in bytes + * \param filename name of the file to source from + * \param repeat repeat file from start + * \param offset begin this many items into file + * \param len produce only items [offset, offset+len) */ - static sptr make(size_t itemsize, const char *filename, bool repeat = false); + static sptr make(size_t itemsize, const char *filename, bool repeat = false, + size_t offset = 0, size_t len = 0); /*! * \brief seek file to \p seek_point relative to \p whence * - * \param seek_point sample offset in file - * \param whence one of SEEK_SET, SEEK_CUR, SEEK_END (man fseek) + * \param seek_point sample offset in file + * \param whence one of SEEK_SET, SEEK_CUR, SEEK_END (man fseek) */ virtual bool seek(long seek_point, int whence) = 0; /*! * \brief Opens a new file. * - * \param filename name of the file to source from - * \param repeat repeat file from start + * \param filename name of the file to source from + * \param repeat repeat file from start + * \param offset begin this many items into file + * \param len produce only items [offset, offset+len) */ - virtual void open(const char *filename, bool repeat) = 0; + virtual void open(const char *filename, bool repeat, size_t offset = 0, size_t len = 0) = 0; /*! * \brief Close the file handle. diff --git a/gr-blocks/lib/file_source_impl.cc b/gr-blocks/lib/file_source_impl.cc index c077c74fd9..6f4f8fde26 100644 --- a/gr-blocks/lib/file_source_impl.cc +++ b/gr-blocks/lib/file_source_impl.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2012 Free Software Foundation, Inc. + * Copyright 2012, 2018 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -39,35 +39,38 @@ #include <io.h> #endif #ifdef O_BINARY -#define OUR_O_BINARY O_BINARY +#define OUR_O_BINARY O_BINARY #else -#define OUR_O_BINARY 0 +#define OUR_O_BINARY 0 #endif // should be handled via configure #ifdef O_LARGEFILE -#define OUR_O_LARGEFILE O_LARGEFILE +#define OUR_O_LARGEFILE O_LARGEFILE #else -#define OUR_O_LARGEFILE 0 +#define OUR_O_LARGEFILE 0 #endif namespace gr { namespace blocks { - file_source::sptr file_source::make(size_t itemsize, const char *filename, bool repeat) + file_source::sptr file_source::make(size_t itemsize, const char *filename, bool repeat, + size_t start_offset_items, size_t length_items) { return gnuradio::get_initial_sptr - (new file_source_impl(itemsize, filename, repeat)); + (new file_source_impl(itemsize, filename, repeat, start_offset_items, length_items)); } - file_source_impl::file_source_impl(size_t itemsize, const char *filename, bool repeat) + file_source_impl::file_source_impl(size_t itemsize, const char *filename, bool repeat, + size_t start_offset_items, size_t length_items) : sync_block("file_source", - io_signature::make(0, 0, 0), - io_signature::make(1, 1, itemsize)), - d_itemsize(itemsize), d_fp(0), d_new_fp(0), d_repeat(repeat), - d_updated(false), d_file_begin(true), d_repeat_cnt(0), - d_add_begin_tag(pmt::PMT_NIL) + io_signature::make(0, 0, 0), + io_signature::make(1, 1, itemsize)), + d_itemsize(itemsize), + d_start_offset_items(start_offset_items), d_length_items(length_items), + d_fp(0), d_new_fp(0), d_repeat(repeat), d_updated(false), + d_file_begin(true), d_repeat_cnt(0), d_add_begin_tag(pmt::PMT_NIL) { - open(filename, repeat); + open(filename, repeat, start_offset_items, length_items); do_update(); std::stringstream str; @@ -86,12 +89,35 @@ namespace gr { bool file_source_impl::seek(long seek_point, int whence) { - return fseek((FILE*)d_fp, seek_point *d_itemsize, whence) == 0; + seek_point += d_start_offset_items; + + switch(whence) { + case SEEK_SET: + break; + case SEEK_CUR: + seek_point += (d_length_items - d_items_remaining); + break; + case SEEK_END: + seek_point = d_length_items - seek_point; + break; + default: + GR_LOG_WARN(d_logger, "bad seek mode"); + return 0; + } + + if ((seek_point < (long)d_start_offset_items) + || (seek_point > (long)(d_start_offset_items+d_length_items-1))) { + GR_LOG_WARN(d_logger, "bad seek point"); + return 0; + } + + return fseek((FILE*)d_fp, seek_point * d_itemsize, SEEK_SET) == 0; } void - file_source_impl::open(const char *filename, bool repeat) + file_source_impl::open(const char *filename, bool repeat, + size_t start_offset_items, size_t length_items) { // obtain exclusive access for duration of this function gr::thread::scoped_lock lock(fp_mutex); @@ -100,33 +126,61 @@ namespace gr { // we use "open" to use to the O_LARGEFILE flag if((fd = ::open(filename, O_RDONLY | OUR_O_LARGEFILE | OUR_O_BINARY)) < 0) { - perror(filename); - throw std::runtime_error("can't open file"); + GR_LOG_ERROR(d_logger, boost::format("%s: %s") % filename % strerror(errno)); + throw std::runtime_error("can't open file"); } if(d_new_fp) { - fclose(d_new_fp); - d_new_fp = 0; + fclose(d_new_fp); + d_new_fp = 0; } if((d_new_fp = fdopen (fd, "rb")) == NULL) { - perror(filename); - ::close(fd); // don't leak file descriptor if fdopen fails - throw std::runtime_error("can't open file"); + GR_LOG_ERROR(d_logger, boost::format("%s: %s") % filename % strerror(errno)); + ::close(fd); // don't leak file descriptor if fdopen fails + throw std::runtime_error("can't open file"); } //Check to ensure the file will be consumed according to item size fseek(d_new_fp, 0, SEEK_END); int file_size = ftell(d_new_fp); - rewind (d_new_fp); - //Warn the user if part of the file will not be consumed. - if(file_size % d_itemsize){ - GR_LOG_WARN(d_logger, "WARNING: File will not be fully consumed with the current output type"); + // Make sure there will be at least one item available + if ((file_size / d_itemsize) < (start_offset_items+1)) { + if (start_offset_items) { + GR_LOG_WARN(d_logger, "file is too small for start offset"); + } + else { + GR_LOG_WARN(d_logger, "file is too small"); + } + fclose(d_new_fp); + throw std::runtime_error("file is too small"); + } + + size_t items_available = (file_size / d_itemsize - start_offset_items); + + // If length is not specified, use the remainder of the file. Check alignment at end. + if (length_items == 0) { + length_items = items_available; + if (file_size % d_itemsize){ + GR_LOG_WARN(d_logger, "file size is not a multiple of item size"); + } + } + + // Check specified length. Warn and use available items instead of throwing an exception. + if (length_items > items_available) { + length_items = items_available; + GR_LOG_WARN(d_logger, "file too short, will read fewer than requested items"); } + // Rewind to start offset + fseek(d_new_fp, start_offset_items * d_itemsize, SEEK_SET); + d_updated = true; d_repeat = repeat; + d_start_offset_items = start_offset_items; + d_length_items = length_items; + d_items_remaining = length_items; } void @@ -136,8 +190,8 @@ namespace gr { gr::thread::scoped_lock lock(fp_mutex); if(d_new_fp != NULL) { - fclose(d_new_fp); - d_new_fp = NULL; + fclose(d_new_fp); + d_new_fp = NULL; } d_updated = true; } @@ -146,15 +200,15 @@ namespace gr { file_source_impl::do_update() { if(d_updated) { - gr::thread::scoped_lock lock(fp_mutex); // hold while in scope + gr::thread::scoped_lock lock(fp_mutex); // hold while in scope - if(d_fp) - fclose(d_fp); + if(d_fp) + fclose(d_fp); - d_fp = d_new_fp; // install new file pointer - d_new_fp = 0; - d_updated = false; - d_file_begin = true; + d_fp = d_new_fp; // install new file pointer + d_new_fp = 0; + d_updated = false; + d_file_begin = true; } } @@ -166,60 +220,62 @@ namespace gr { int file_source_impl::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { char *o = (char*)output_items[0]; - int i; int size = noutput_items; do_update(); // update d_fp is reqd if(d_fp == NULL) - throw std::runtime_error("work with file not open"); + throw std::runtime_error("work with file not open"); gr::thread::scoped_lock lock(fp_mutex); // hold for the rest of this function + // No items remaining - all done + if (d_items_remaining == 0) + return WORK_DONE; + while(size) { + // Add stream tag whenever the file starts again if (d_file_begin && d_add_begin_tag != pmt::PMT_NIL) { - add_item_tag(0, nitems_written(0) + noutput_items - size, d_add_begin_tag, pmt::from_long(d_repeat_cnt), _id); + add_item_tag(0, nitems_written(0) + noutput_items - size, + d_add_begin_tag, pmt::from_long(d_repeat_cnt), _id); d_file_begin = false; } - i = fread(o, d_itemsize, size, (FILE*)d_fp); - - size -= i; - o += 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 ((FILE *) d_fp, 0, SEEK_SET) == -1) { - fprintf(stderr, "[%s] fseek failed\n", __FILE__); - exit(-1); - } - if (d_add_begin_tag != pmt::PMT_NIL) { - d_file_begin = true; - d_repeat_cnt++; + size_t nitems_to_read = std::min((size_t)size, d_items_remaining); + + // Since the bounds of the file are known, unexpected nitems is an error + if (nitems_to_read != fread(o, d_itemsize, nitems_to_read, (FILE*)d_fp)) + throw std::runtime_error("fread error"); + + size -= nitems_to_read; + d_items_remaining -= nitems_to_read; + o += nitems_to_read * d_itemsize; + + // Ran out of items ("EOF") + if (d_items_remaining == 0) { + + // Repeat: rewind and request tag + if (d_repeat) { + fseek(d_fp, d_start_offset_items * d_itemsize, SEEK_SET); + d_items_remaining = d_length_items; + if (d_add_begin_tag != pmt::PMT_NIL) { + d_file_begin = true; + d_repeat_cnt++; + } + } + + // No repeat: return + else { + break; + } } } - if(size > 0) { // EOF or error - if(size == noutput_items) // we didn't read anything; say we're done - return -1; - return noutput_items - size; // else return partial result - } - - return noutput_items; + return (noutput_items - size); } } /* namespace blocks */ diff --git a/gr-blocks/lib/file_source_impl.h b/gr-blocks/lib/file_source_impl.h index 19f393fc1d..6de3fc0d16 100644 --- a/gr-blocks/lib/file_source_impl.h +++ b/gr-blocks/lib/file_source_impl.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2012 Free Software Foundation, Inc. + * Copyright 2012, 2018 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -33,6 +33,9 @@ namespace gr { { private: size_t d_itemsize; + size_t d_start_offset_items; + size_t d_length_items; + size_t d_items_remaining; FILE *d_fp; FILE *d_new_fp; bool d_repeat; @@ -47,16 +50,17 @@ namespace gr { void do_update(); public: - file_source_impl(size_t itemsize, const char *filename, bool repeat); + file_source_impl(size_t itemsize, const char *filename, bool repeat, + size_t offset, size_t len); ~file_source_impl(); bool seek(long seek_point, int whence); - void open(const char *filename, bool repeat); + void open(const char *filename, bool repeat, size_t offset, size_t len); void close(); int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); void set_begin_tag(pmt::pmt_t val); }; diff --git a/gr-blocks/python/blocks/qa_file_descriptor_source_sink.py b/gr-blocks/python/blocks/qa_file_descriptor_source_sink.py new file mode 100644 index 0000000000..c84a82d59f --- /dev/null +++ b/gr-blocks/python/blocks/qa_file_descriptor_source_sink.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# +# Copyright 2018 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, blocks +import os +import tempfile +import pmt + +class test_file_descriptor_source_sink(gr_unittest.TestCase): + + def setUp (self): + os.environ['GR_CONF_CONTROLPORT_ON'] = 'False' + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def test_file_descriptor(self): + src_data = range(1000) + expected_result = range(1000) + + snk2 = blocks.vector_sink_f() + + with tempfile.NamedTemporaryFile() as temp: + fhandle0 = open(temp.name, "wb") + fd0 = fhandle0.fileno() + + src = blocks.vector_source_f(src_data) + snk = blocks.file_descriptor_sink(gr.sizeof_float, fd0) + + self.tb.connect(src, snk) + self.tb.run() + os.fsync(fd0) + fhandle0.close() + + fhandle1 = open(temp.name, "rb") + fd1 = fhandle1.fileno() + src2 = blocks.file_descriptor_source(gr.sizeof_float, fd1, False) + + self.tb.disconnect(src, snk) + self.tb.connect(src2, snk2) + self.tb.run() + os.fsync(fd1) + fhandle1.close() + + result_data = snk2.data() + self.assertFloatTuplesAlmostEqual(expected_result, result_data) + self.assertEqual(len(snk2.tags()), 0) + +if __name__ == '__main__': + gr_unittest.run(test_file_descriptor_source_sink, "test_file_descriptor_source_sink.xml") diff --git a/gr-blocks/python/blocks/qa_file_sink.py b/gr-blocks/python/blocks/qa_file_sink.py new file mode 100644 index 0000000000..a7296183ef --- /dev/null +++ b/gr-blocks/python/blocks/qa_file_sink.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# +# Copyright 2018 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, blocks +import os +import tempfile +import pmt +import array + +class test_file_sink(gr_unittest.TestCase): + + def setUp (self): + os.environ['GR_CONF_CONTROLPORT_ON'] = 'False' + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def test_file_sink(self): + data = range(1000) + expected_result = data + + with tempfile.NamedTemporaryFile() as temp: + src = blocks.vector_source_f(data) + snk = blocks.file_sink(gr.sizeof_float, temp.name) + snk.set_unbuffered(True) + self.tb.connect(src, snk) + self.tb.run() + + # Check file length (float: 4 * nsamples) + st = os.stat(temp.name) + self.assertEqual(st.st_size, 4 * len(data)) + + # Check file contents + datafile = open(temp.name, 'r') + result_data = array.array('f') + result_data.fromfile(datafile, len(data)) + self.assertFloatTuplesAlmostEqual(expected_result, result_data) + +if __name__ == '__main__': + gr_unittest.run(test_file_sink, "test_file_sink.xml") diff --git a/gr-blocks/python/blocks/qa_file_source.py b/gr-blocks/python/blocks/qa_file_source.py new file mode 100644 index 0000000000..f8ca75d79c --- /dev/null +++ b/gr-blocks/python/blocks/qa_file_source.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python +# +# Copyright 2018 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, blocks +import os +import tempfile +import pmt +import array + +class test_file_source(gr_unittest.TestCase): + + @classmethod + def setUpClass(cls): + os.environ['GR_CONF_CONTROLPORT_ON'] = 'False' + cls._datafile = tempfile.NamedTemporaryFile() + cls._datafilename = cls._datafile.name + cls._vector = range(1000) + with open(cls._datafilename, 'w') as f: + array.array('f', cls._vector).tofile(f) + + @classmethod + def tearDownClass(cls): + del cls._vector + del cls._datafilename + del cls._datafile + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def test_file_source(self): + expected_result = self._vector + + src = blocks.file_source(gr.sizeof_float, self._datafilename) + snk = blocks.vector_sink_f() + self.tb.connect(src, snk) + self.tb.run() + + result_data = snk.data() + self.assertFloatTuplesAlmostEqual(self._vector, result_data) + self.assertEqual(len(snk.tags()), 0) + + def test_file_source_no_such_file(self): + + try: + src = blocks.file_source(gr.sizeof_float, "___no_such_file___") + self.assertTrue(False) + except RuntimeError, e: + self.assertTrue(True) + + def test_file_source_with_offset(self): + expected_result = self._vector[100:] + + src = blocks.file_source(gr.sizeof_float, self._datafilename, offset=100) + snk = blocks.vector_sink_f() + + self.tb.connect(src, snk) + self.tb.run() + + result_data = snk.data() + self.assertFloatTuplesAlmostEqual(expected_result, result_data) + self.assertEqual(len(snk.tags()), 0) + + def test_source_with_offset_and_len(self): + expected_result = self._vector[100:100+600] + + src = blocks.file_source(gr.sizeof_float, self._datafilename, offset=100, len=600) + snk = blocks.vector_sink_f() + self.tb.connect(src, snk) + self.tb.run() + + result_data = snk.data() + self.assertFloatTuplesAlmostEqual(expected_result, result_data) + self.assertEqual(len(snk.tags()), 0) + + def test_file_source_can_seek_after_open(self): + + src = blocks.file_source(gr.sizeof_float, self._datafilename) + self.assertTrue(src.seek(0, os.SEEK_SET)) + self.assertTrue(src.seek(len(self._vector)-1, os.SEEK_SET)) + # Seek past end of file - this will also log a warning + self.assertFalse(src.seek(len(self._vector), os.SEEK_SET)) + # Negative seek - this will also log a warning + self.assertFalse(src.seek(-1, os.SEEK_SET)) + + self.assertTrue(src.seek(1, os.SEEK_END)) + self.assertTrue(src.seek(len(self._vector), os.SEEK_END)) + # Seek past end of file - this will also log a warning + self.assertFalse(src.seek(0, os.SEEK_END)) + + self.assertTrue(src.seek(0, os.SEEK_SET)) + self.assertTrue(src.seek(1, os.SEEK_CUR)) + # Seek past end of file - this will also log a warning + self.assertFalse(src.seek(len(self._vector), os.SEEK_CUR)); + + + def test_begin_tag(self): + expected_result = self._vector + + src = blocks.file_source(gr.sizeof_float, self._datafilename) + src.set_begin_tag(pmt.string_to_symbol("file_begin")) + snk = blocks.vector_sink_f() + self.tb.connect(src, snk) + self.tb.run() + + result_data = snk.data() + self.assertFloatTuplesAlmostEqual(expected_result, result_data) + self.assertEqual(len(snk.tags()), 1) + + def test_begin_tag_repeat(self): + expected_result = self._vector + self._vector + + src = blocks.file_source(gr.sizeof_float, self._datafilename, True) + src.set_begin_tag(pmt.string_to_symbol("file_begin")) + hd = blocks.head(gr.sizeof_float, 2 * len(self._vector)) + snk = blocks.vector_sink_f() + self.tb.connect(src, hd, snk) + self.tb.run() + + result_data = snk.data() + self.assertFloatTuplesAlmostEqual(expected_result, result_data) + tags = snk.tags() + self.assertEqual(len(tags), 2) + self.assertEqual(str(tags[0].key), "file_begin") + self.assertEqual(str(tags[0].value), "0") + self.assertEqual(tags[0].offset, 0) + self.assertEqual(str(tags[1].key), "file_begin") + self.assertEqual(str(tags[1].value), "1") + self.assertEqual(tags[1].offset, 1000) + +if __name__ == '__main__': + gr_unittest.run(test_file_source, "test_file_source.xml") diff --git a/gr-blocks/python/blocks/qa_file_source_sink.py b/gr-blocks/python/blocks/qa_file_source_sink.py deleted file mode 100644 index 86d36c0cca..0000000000 --- a/gr-blocks/python/blocks/qa_file_source_sink.py +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 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, blocks -import os -import tempfile -import pmt - -class test_file_source_sink(gr_unittest.TestCase): - - def setUp (self): - os.environ['GR_CONF_CONTROLPORT_ON'] = 'False' - self.tb = gr.top_block () - - def tearDown (self): - self.tb = None - - def test_001(self): - src_data = range(1000) - expected_result = range(1000) - - snk2 = blocks.vector_sink_f() - - with tempfile.NamedTemporaryFile() as temp: - src = blocks.vector_source_f(src_data) - snk = blocks.file_sink(gr.sizeof_float, temp.name) - snk.set_unbuffered(True) - - self.tb.connect(src, snk) - self.tb.run() - - src2 = blocks.file_source(gr.sizeof_float, temp.name) - - self.tb.disconnect(src, snk) - self.tb.connect(src2, snk2) - self.tb.run() - - result_data = snk2.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - self.assertEqual(len(snk2.tags()), 0) - - def test_descriptor_001(self): - src_data = range(1000) - expected_result = range(1000) - - snk2 = blocks.vector_sink_f() - - with tempfile.NamedTemporaryFile() as temp: - fhandle0 = open(temp.name, "wb") - fd0 = fhandle0.fileno() - - src = blocks.vector_source_f(src_data) - snk = blocks.file_descriptor_sink(gr.sizeof_float, fd0) - - self.tb.connect(src, snk) - self.tb.run() - os.fsync(fd0) - fhandle0.close() - - fhandle1 = open(temp.name, "rb") - fd1 = fhandle1.fileno() - src2 = blocks.file_descriptor_source(gr.sizeof_float, fd1, False) - - self.tb.disconnect(src, snk) - self.tb.connect(src2, snk2) - self.tb.run() - os.fsync(fd1) - fhandle1.close() - - result_data = snk2.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - self.assertEqual(len(snk2.tags()), 0) - - def test_file_source_can_seek_after_open(self): - src_data = range(1000) - - with tempfile.NamedTemporaryFile() as temp: - src = blocks.vector_source_f(src_data) - snk = blocks.file_sink(gr.sizeof_float, temp.name) - snk.set_unbuffered(True) - - self.tb.connect(src, snk) - self.tb.run() - - source = blocks.file_source(gr.sizeof_float, temp.name) - self.assertTrue(source.seek(0, os.SEEK_SET)) - - def test_begin_tag(self): - src_data = range(1000) - expected_result = range(1000) - - snk2 = blocks.vector_sink_f() - - with tempfile.NamedTemporaryFile() as temp: - src = blocks.vector_source_f(src_data) - snk = blocks.file_sink(gr.sizeof_float, temp.name) - snk.set_unbuffered(True) - - self.tb.connect(src, snk) - self.tb.run() - - src2 = blocks.file_source(gr.sizeof_float, temp.name) - src2.set_begin_tag(pmt.string_to_symbol("file_begin")) - - self.tb.disconnect(src, snk) - self.tb.connect(src2, snk2) - self.tb.run() - - result_data = snk2.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - self.assertEqual(len(snk2.tags()), 1) - - def test_begin_tag_repeat(self): - src_data = range(1000) - expected_result = range(1000) - expected_result.extend(range(1000)) - - snk2 = blocks.vector_sink_f() - - with tempfile.NamedTemporaryFile() as temp: - src = blocks.vector_source_f(src_data) - snk = blocks.file_sink(gr.sizeof_float, temp.name) - snk.set_unbuffered(True) - - self.tb.connect(src, snk) - self.tb.run() - - src2 = blocks.file_source(gr.sizeof_float, temp.name, True) - src2.set_begin_tag(pmt.string_to_symbol("file_begin")) - hd = blocks.head(gr.sizeof_float, 2000) - - self.tb.disconnect(src, snk) - self.tb.connect(src2, hd, snk2) - self.tb.run() - - result_data = snk2.data() - self.assertFloatTuplesAlmostEqual(expected_result, result_data) - tags = snk2.tags() - self.assertEqual(len(tags), 2) - self.assertEqual(str(tags[0].key), "file_begin") - self.assertEqual(str(tags[0].value), "0") - self.assertEqual(tags[0].offset, 0) - self.assertEqual(str(tags[1].key), "file_begin") - self.assertEqual(str(tags[1].value), "1") - self.assertEqual(tags[1].offset, 1000) - -if __name__ == '__main__': - gr_unittest.run(test_file_source_sink, "test_file_source_sink.xml") |