3 * Copyright 2007,2008 Free Software Foundation, Inc.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <usrp2/usrp2.h>
24 #include <usrp2/strtod_si.h>
25 #include <usrp2/copiers.h>
26 #include <usrp2/rx_nop_handler.h>
27 #include <gruel/realtime.h>
32 #include <boost/scoped_ptr.hpp>
33 #include <boost/shared_ptr.hpp>
37 static volatile bool signaled = false;
46 install_sig_handler(int signum,
47 void (*new_handler)(int))
49 struct sigaction new_action;
50 memset (&new_action, 0, sizeof (new_action));
52 new_action.sa_handler = new_handler;
53 sigemptyset (&new_action.sa_mask);
54 new_action.sa_flags = 0;
56 if (sigaction (signum, &new_action, 0) < 0){
57 perror ("sigaction (install new)");
58 throw std::runtime_error ("sigaction");
62 // ------------------------------------------------------------------------
64 // FIXME make this a template
66 class file_writer_16sc : public usrp2::rx_nop_handler
69 std::string d_filename;
73 file_writer_16sc(const std::string &filename, uint64_t max_samples)
74 : usrp2::rx_nop_handler(max_samples), d_filename(filename)
76 d_fp = fopen(filename.c_str(), "wb");
78 perror(filename.c_str());
79 throw std::invalid_argument(filename);
86 operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata *metadata)
88 bool ok = rx_nop_handler::operator()(items, nitems, metadata);
90 size_t host_nitems = nitems;
91 std::complex<int16_t> host_items[host_nitems];
93 usrp2::copy_u2_16sc_to_host_16sc(nitems, items, host_items);
96 while (n < host_nitems){
97 size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp);
99 if (r == 0){ // out of space?
101 perror(d_filename.c_str());
111 file_writer_16sc::~file_writer_16sc()
116 // ------------------------------------------------------------------------
118 class file_writer_32fc : public usrp2::rx_nop_handler
121 std::string d_filename;
125 file_writer_32fc(const std::string &filename, uint64_t max_samples)
126 : usrp2::rx_nop_handler(max_samples), d_filename(filename)
128 d_fp = fopen(filename.c_str(), "wb");
130 perror(filename.c_str());
131 throw std::invalid_argument(filename);
138 operator()(const uint32_t *items, size_t nitems, const usrp2::rx_metadata *metadata)
140 bool ok = rx_nop_handler::operator()(items, nitems, metadata);
142 size_t host_nitems = nitems;
143 std::complex<float> host_items[host_nitems];
145 usrp2::copy_u2_16sc_to_host_32fc(nitems, items, host_items);
148 while (n < host_nitems){
149 size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp);
151 if (r == 0){ // out of space?
153 perror(d_filename.c_str());
163 file_writer_32fc::~file_writer_32fc()
168 // ------------------------------------------------------------------------
171 usage(const char *progname)
173 const char *p = strrchr(progname, '/'); // drop leading directory path
177 if (strncmp(p, "lt-", 3) == 0) // drop lt- libtool prefix
180 fprintf(stderr, "Usage: %s [options]\n\n", p);
181 fprintf(stderr, "Options:\n");
182 fprintf(stderr, " -h show this message and exit\n");
183 fprintf(stderr, " -e ETH_INTERFACE specify ethernet interface [default=eth0]\n");
184 fprintf(stderr, " -m MAC_ADDR mac address of USRP2 HH:HH [default=first one found]\n");
185 fprintf(stderr, " -f FREQUENCY specify receive center frequency in Hz [default=0.0]\n");
186 fprintf(stderr, " -d DECIM specify receive decimation rate [default=5]\n");
187 fprintf(stderr, " -g GAIN specify receive daughterboard gain [default=0]\n");
188 fprintf(stderr, " -N NSAMPLES specify number of samples to receive [default=infinite]\n");
189 fprintf(stderr, " -o OUTPUT_FILENAME specify file to receive samples [default=none]\n");
190 fprintf(stderr, " -s write complex<short> [default=complex<float>]\n");
191 fprintf(stderr, " -v verbose output\n");
195 main(int argc, char **argv)
197 // options and their defaults
198 const char *interface = "eth0";
199 const char *mac_addr_str = "";
200 double rx_freq = 0.0;
202 double rx_gain = 0.0;
203 uint64_t nsamples = 0;
204 bool output_shorts = false;
205 char *output_filename = 0;
206 bool verbose = false;
210 while ((ch = getopt(argc, argv, "he:m:f:d:g:N:o:sv")) != EOF){
219 mac_addr_str = optarg;
223 if (!strtod_si(optarg, &rx_freq)) {
224 std::cerr << "invalid number: " << optarg << std::endl;
231 if (!strtod_si(optarg, &rx_gain)) {
232 std::cerr << "invalid number: " << optarg << std::endl;
239 rx_decim = strtol(optarg, 0, 0);
240 if (rx_decim < 4 or rx_decim > 512) {
241 std::cerr << "invalid decimation rate: " << optarg << std::endl;
248 if (!strtod_si(optarg, &tmp)) {
249 std::cerr << "invalid number: " << optarg << std::endl;
253 nsamples = static_cast<uint64_t>(tmp);
257 output_shorts = true;
261 output_filename = optarg;
276 install_sig_handler(SIGINT, sig_handler);
278 usrp2::rx_nop_handler::sptr handler;
280 if (output_filename){
282 handler = usrp2::rx_nop_handler::sptr(new file_writer_16sc(output_filename, nsamples));
284 handler = usrp2::rx_nop_handler::sptr(new file_writer_32fc(output_filename, nsamples));
287 handler = usrp2::rx_nop_handler::sptr(new usrp2::rx_nop_handler(nsamples));
289 gruel::rt_status_t rt = gruel::enable_realtime_scheduling();
290 if (rt != gruel::RT_OK)
291 std::cerr << "Failed to enable realtime scheduling" << std::endl;
293 usrp2::usrp2::sptr u2 = usrp2::usrp2::make(interface, mac_addr_str);
295 // FIXME in case it was left running...
296 if (!u2->stop_rx_streaming()){
297 fprintf(stderr, "stop_rx_streaming failed\n");
300 if (!u2->set_rx_gain(rx_gain)){
301 fprintf(stderr, "set_rx_gain(%f) failed\n", rx_gain);
305 usrp2::tune_result tr;
306 if (!u2->set_rx_center_freq(rx_freq, &tr)){
307 fprintf(stderr, "set_rx_center_freq(%g) failed\n", rx_freq);
312 printf("USRP2 MAC address: %s\n\n", u2->mac_addr().c_str());
313 printf("Daughterboard configuration:\n");
314 printf(" baseband_freq=%f\n", tr.baseband_freq);
315 printf(" ddc_freq=%f\n", tr.dxc_freq);
316 printf(" residual_freq=%f\n", tr.residual_freq);
317 printf(" inverted=%s\n\n", tr.spectrum_inverted ? "yes" : "no");
320 if (!u2->set_rx_decim(rx_decim)) {
321 fprintf(stderr, "set_rx_decim(%d) failed\n", rx_decim);
326 printf("USRP2 using decimation rate of %d\n", rx_decim);
328 if (!u2->start_rx_streaming(0)){
329 fprintf(stderr, "start_rx_streaming failed\n");
335 printf("Receiving %zd samples\n\n", nsamples);
337 printf("Receiving infinite samples\n\n");
340 struct timeval start, end;
341 gettimeofday(&start, 0);
344 !handler->has_errored_p() &&
345 !handler->has_finished_p()) {
346 bool ok = u2->rx_samples(0, handler.get());
348 fprintf(stderr, "u2->rx_samples failed\n");
353 gettimeofday(&end, 0);
354 long n_usecs = end.tv_usec-start.tv_usec;
355 long n_secs = end.tv_sec-start.tv_sec;
356 double elapsed = (double)n_secs + (double)n_usecs*1e-6;
357 double mbs = handler->nsamples()*sizeof(uint32_t)/elapsed/1e6;
358 double pps = handler->nframes()/elapsed;
360 u2->stop_rx_streaming();
363 printf("\nCopy handler called %li times.\n", handler->nframes());
364 printf("Copy handler called with %li bytes.\n\n", handler->nsamples()*sizeof(uint32_t));
365 printf("Elapsed time was %5.3f seconds.\n", elapsed);
366 printf("Packet rate was %1.0f pkts/sec.\n", pps);
367 printf("Approximate throughput was %5.2f MB/sec.\n", mbs);
368 printf("Total instances of overruns was %d.\n", u2->rx_overruns());
369 printf("Total missing frames was %d.\n", u2->rx_missing());