1 /* -*- c++ -*- */
2 /*
3 * Copyright 2010,2013 Free Software Foundation, Inc.
4 *
5 * This file is part of GNU Radio
6 *
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
11 *
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "tagged_file_sink_impl.h"
28 #include <gnuradio/io_signature.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <iostream>
34 #include <stdexcept>
35
36 #ifdef HAVE_IO_H
37 #include <io.h>
38 #endif
39
40 #ifdef O_BINARY
41 #define OUR_O_BINARY O_BINARY
42 #else
43 #define OUR_O_BINARY 0
44 #endif
45
46 // should be handled via configure
47 #ifdef O_LARGEFILE
48 #define OUR_O_LARGEFILE O_LARGEFILE
49 #else
50 #define OUR_O_LARGEFILE 0
51 #endif
52
53 namespace gr {
54 namespace blocks {
55
make(size_t itemsize,double samp_rate)56 tagged_file_sink::sptr tagged_file_sink::make(size_t itemsize, double samp_rate)
57 {
58 return gnuradio::get_initial_sptr(new tagged_file_sink_impl(itemsize, samp_rate));
59 }
60
tagged_file_sink_impl(size_t itemsize,double samp_rate)61 tagged_file_sink_impl::tagged_file_sink_impl(size_t itemsize, double samp_rate)
62 : sync_block("tagged_file_sink",
63 io_signature::make(1, 1, itemsize),
64 io_signature::make(0, 0, 0)),
65 d_itemsize(itemsize),
66 d_n(0),
67 d_sample_rate(samp_rate)
68 {
69 d_state = NOT_IN_BURST;
70 d_last_N = 0;
71 d_timeval = 0;
72 }
73
~tagged_file_sink_impl()74 tagged_file_sink_impl::~tagged_file_sink_impl() {}
75
work(int noutput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)76 int tagged_file_sink_impl::work(int noutput_items,
77 gr_vector_const_void_star& input_items,
78 gr_vector_void_star& output_items)
79 {
80 char* inbuf = (char*)input_items[0];
81
82 uint64_t start_N = nitems_read(0);
83 uint64_t end_N = start_N + (uint64_t)(noutput_items);
84 pmt::pmt_t bkey = pmt::string_to_symbol("burst");
85 pmt::pmt_t tkey = pmt::string_to_symbol("rx_time"); // use gr_tags::key_time
86
87 std::vector<tag_t> all_tags;
88 get_tags_in_range(all_tags, 0, start_N, end_N);
89
90 std::sort(all_tags.begin(), all_tags.end(), tag_t::offset_compare);
91
92 std::vector<tag_t>::iterator vitr = all_tags.begin();
93
94 // Look for a time tag and initialize d_timeval.
95 std::vector<tag_t> time_tags_outer;
96 get_tags_in_range(time_tags_outer, 0, start_N, end_N, tkey);
97 if (!time_tags_outer.empty()) {
98 const tag_t tag = time_tags_outer[0];
99 uint64_t offset = tag.offset;
100 pmt::pmt_t time = tag.value;
101 uint64_t tsecs = pmt::to_uint64(pmt::tuple_ref(time, 0));
102 double tfrac = pmt::to_double(pmt::tuple_ref(time, 1));
103 double delta = (double)offset / d_sample_rate;
104 d_timeval = (double)tsecs + tfrac + delta;
105 d_last_N = offset;
106 }
107
108 int idx = 0, idx_stop = 0;
109 while (idx < noutput_items) {
110 if (d_state == NOT_IN_BURST) {
111 while (vitr != all_tags.end()) {
112 if ((pmt::eqv((*vitr).key, bkey)) && pmt::is_true((*vitr).value)) {
113
114 uint64_t N = (*vitr).offset;
115 idx = (int)(N - start_N);
116
117 // std::cout << std::endl << "Found start of burst: "
118 // << idx << ", " << N << std::endl;
119
120 // Find time burst occurred by getting latest time tag and
121 // extrapolating to new time based on sample rate of this block.
122 std::vector<tag_t> time_tags;
123 // get_tags_in_range(time_tags, 0, d_last_N, N, gr_tags::key_time);
124 get_tags_in_range(time_tags, 0, d_last_N, N, tkey);
125 if (!time_tags.empty()) {
126 const tag_t tag = time_tags[time_tags.size() - 1];
127
128 uint64_t time_nitems = tag.offset;
129
130 // Get time based on last time tag from USRP
131 pmt::pmt_t time = tag.value;
132 uint64_t tsecs = pmt::to_uint64(pmt::tuple_ref(time, 0));
133 double tfrac = pmt::to_double(pmt::tuple_ref(time, 1));
134
135 // Get new time from last time tag + difference in time to when
136 // burst tag occurred based on the sample rate
137 double delta = (double)(N - time_nitems) / d_sample_rate;
138 d_timeval = (double)tsecs + tfrac + delta;
139
140 // std::cout.setf(std::ios::fixed, std::ios::floatfield);
141 // std::cout.precision(8);
142 // std::cout << "Time found: " << (double)tsecs + tfrac <<
143 // std::endl; std::cout << " time: " << d_timeval << std::endl;
144 // std::cout << " time at N = " << time_nitems << " burst N = "
145 // << N << std::endl;
146 } else {
147 // if no time tag, use last seen tag and update time based on
148 // sample rate of the block
149 d_timeval += (double)(N - d_last_N) / d_sample_rate;
150 // std::cout << "Time not found" << std::endl;
151 // std::cout << " time: " << d_timeval << std::endl;
152 }
153 d_last_N = N;
154
155 std::stringstream filename;
156 filename.setf(std::ios::fixed, std::ios::floatfield);
157 filename.precision(8);
158 filename << "file" << unique_id() << "_" << d_n << "_" << d_timeval
159 << ".dat";
160 d_n++;
161
162 int fd;
163 if ((fd = ::open(filename.str().c_str(),
164 O_WRONLY | O_CREAT | O_TRUNC | OUR_O_LARGEFILE |
165 OUR_O_BINARY,
166 0664)) < 0) {
167 perror(filename.str().c_str());
168 return -1;
169 }
170
171 // FIXME:
172 // if((d_handle = fdopen (fd, d_is_binary ? "wb" : "w")) == NULL) {
173 if ((d_handle = fdopen(fd, "wb")) == NULL) {
174 perror(filename.str().c_str());
175 ::close(fd); // don't leak file descriptor if fdopen fails.
176 }
177
178 // std::cout << "Created new file: " << filename.str() << std::endl;
179
180 d_state = IN_BURST;
181 break;
182 }
183
184 vitr++;
185 }
186 if (d_state == NOT_IN_BURST)
187 return noutput_items;
188 } else { // In burst
189 while (vitr != all_tags.end()) {
190 if ((pmt::eqv((*vitr).key, bkey)) && pmt::is_false((*vitr).value)) {
191 uint64_t N = (*vitr).offset;
192 idx_stop = (int)N - start_N;
193
194 // std::cout << "Found end of burst: "
195 // << idx_stop << ", " << N << std::endl;
196
197 int count = fwrite(
198 &inbuf[d_itemsize * idx], d_itemsize, idx_stop - idx, d_handle);
199 if (count == 0) {
200 if (ferror(d_handle)) {
201 perror("tagged_file_sink: error writing file");
202 }
203 }
204 idx = idx_stop;
205 d_state = NOT_IN_BURST;
206 vitr++;
207 fclose(d_handle);
208 break;
209 } else {
210 vitr++;
211 }
212 }
213 if (d_state == IN_BURST) {
214 int count = fwrite(
215 &inbuf[d_itemsize * idx], d_itemsize, noutput_items - idx, d_handle);
216 if (count == 0) {
217 if (ferror(d_handle)) {
218 perror("tagged_file_sink: error writing file");
219 }
220 }
221 idx = noutput_items;
222 }
223 }
224 }
225
226 return noutput_items;
227 }
228
229 } /* namespace blocks */
230 } /* namespace gr */
231