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