3e41bbf8d0ad454627f225ecd83fb39f4b8c3e19
[debian/gnuradio] / usrp2 / host / apps / tx_samples.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007,2008 Free Software Foundation, Inc.
4  *
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.
9  *
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.
14  *
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/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 #include <usrp2/usrp2.h>
23 #include <usrp2/strtod_si.h>
24 #include <iostream>
25 #include <cstdio>
26 #include <complex>
27 #include <getopt.h>
28 #include <gruel/realtime.h>
29 #include <signal.h>
30 #include <string.h>
31 #include <stdexcept>
32
33
34 typedef std::complex<float> fcomplex;
35
36 static volatile bool signaled = false;
37
38 static void 
39 sig_handler(int sig)
40 {
41   signaled = true;
42 }
43
44 static void
45 install_sig_handler(int signum,
46                     void (*new_handler)(int))
47 {
48   struct sigaction new_action;
49   memset (&new_action, 0, sizeof (new_action));
50
51   new_action.sa_handler = new_handler;
52   sigemptyset (&new_action.sa_mask);
53   new_action.sa_flags = 0;
54
55   if (sigaction (signum, &new_action, 0) < 0){
56     perror ("sigaction (install new)");
57     throw std::runtime_error ("sigaction");
58   }
59 }
60
61
62 static const char *
63 prettify_progname(const char *progname)         // that's probably almost a word ;)
64 {
65   const char *p = strrchr(progname, '/');       // drop leading directory path
66   if (p)
67     p++;
68
69   if (strncmp(p, "lt-", 3) == 0)                // drop lt- libtool prefix
70     p += 3;
71
72   return p;
73 }
74
75 static void
76 usage(const char *progname)
77 {
78   fprintf(stderr, "Usage: %s [options]\n\n", prettify_progname(progname));
79   fprintf(stderr, "Options:\n");
80   fprintf(stderr, "  -h                   show this message and exit\n");
81   fprintf(stderr, "  -e ETH_INTERFACE     specify ethernet interface [default=eth0]\n");
82   fprintf(stderr, "  -m MAC_ADDR          mac address of USRP2 HH:HH [default=first one found]\n");
83   fprintf(stderr, "  -I INPUT_FILE        set input filename [default=stdin]\n");
84   fprintf(stderr, "  -r                   repeat.  When EOF of input file is reached, seek to beginning\n");
85   fprintf(stderr, "  -f FREQ              set frequency to FREQ [default=0]\n");
86   fprintf(stderr, "  -i INTERP            set interpolation rate to INTERP [default=32]\n");
87   fprintf(stderr, "  -g gain              set tx gain\n");
88   fprintf(stderr, "  -S SCALE             fpga scaling factor for I & Q [default=256]\n");
89 }
90
91 #define GAIN_NOT_SET (-1000)
92 #define MAX_SAMPLES (371)
93
94 int
95 main(int argc, char **argv)
96 {
97   const char *interface = "eth0";
98   const char *input_filename = 0;
99   bool repeat = false;
100   const char *mac_addr_str = "";
101   double freq = 0;
102   int32_t interp = 32;
103   int32_t samples_per_frame = MAX_SAMPLES;
104   int32_t scale = -1;
105   double gain = GAIN_NOT_SET;
106   
107   int    ch;
108   double tmp;
109
110
111   while ((ch = getopt(argc, argv, "he:m:I:rf:i:S:F:g:")) != EOF){
112     switch (ch){
113
114     case 'e':
115       interface = optarg;
116       break;
117       
118     case 'm':
119       mac_addr_str = optarg;
120 #if 0
121       if (!usrp2_basic::parse_mac_addr(optarg, &mac_addr)){
122         std::cerr << "invalid mac addr: " << optarg << std::endl;
123         usage(argv[0]);
124         return 1;
125       }
126 #endif
127       break;
128
129     case 'I':
130       input_filename = optarg;
131       break;
132       
133     case 'r':
134       repeat = true;
135       break;
136       
137     case 'f':
138       if (!strtod_si(optarg, &freq)){
139         std::cerr << "invalid number: " << optarg << std::endl;
140         usage(argv[0]);
141         return 1;
142       }
143       break;
144
145     case 'F':
146       samples_per_frame = strtol(optarg, 0, 0);
147       break;
148
149     case 'i':
150       interp = strtol(optarg, 0, 0);
151       break;
152
153     case 'g':
154       gain = strtod(optarg, 0);
155       break;
156
157     case 'S':
158       if (!strtod_si(optarg, &tmp)){
159         std::cerr << "invalid number: " << optarg << std::endl;
160         usage(argv[0]);
161         return 1;
162       }
163       scale = static_cast<int32_t>(tmp);
164       break;
165       
166     case 'h':
167     default:
168       usage(argv[0]);
169       return 1;
170     }
171   }
172
173   
174   if (argc - optind != 0){
175     usage(argv[0]);
176     return 1;
177   }
178   
179   if (samples_per_frame < 9 || samples_per_frame > MAX_SAMPLES){
180     std::cerr << prettify_progname(argv[0])
181               << ": samples_per_frame is out of range.  "
182               << "Must be in [9, " << MAX_SAMPLES << "].\n";
183     usage(argv[0]);
184     return 1;
185   }
186
187
188   FILE *fp = 0;
189   if (input_filename == 0)
190     fp = stdin;
191   else {
192     fp = fopen(input_filename, "rb");
193     if (fp == 0){
194       perror(input_filename);
195       return 1;
196     }
197   }
198
199   install_sig_handler(SIGINT, sig_handler);
200
201
202   gruel::rt_status_t rt = gruel::enable_realtime_scheduling();
203   if (rt != gruel::RT_OK)
204     std::cerr << "Failed to enable realtime scheduling" << std::endl;
205
206
207   usrp2::usrp2::sptr u2 = usrp2::usrp2::make(interface, mac_addr_str);
208   
209   if (gain != GAIN_NOT_SET){
210     if (!u2->set_tx_gain(gain)){
211       std::cerr << "set_tx_gain failed\n";
212       return 1;
213     }
214   }
215
216   usrp2::tune_result tr;
217   if (!u2->set_tx_center_freq(freq, &tr)){
218     fprintf(stderr, "set_tx_center_freq(%g) failed\n", freq);
219     return 1;
220   }
221
222   printf("Daughterboard configuration:\n");
223   printf("  baseband_freq=%f\n", tr.baseband_freq);
224   printf("       duc_freq=%f\n", tr.dxc_freq);
225   printf("  residual_freq=%f\n", tr.residual_freq);
226   printf("       inverted=%s\n\n", tr.spectrum_inverted ? "yes" : "no");
227
228   if (!u2->set_tx_interp(interp)){
229     fprintf(stderr, "set_tx_interp(%d) failed\n", interp);
230     return 1;
231   }
232
233   if (scale != -1){
234     if (!u2->set_tx_scale_iq(scale, scale)){
235       std::cerr << "set_tx_scale_iq failed\n";
236       return 1;
237     }
238   }
239
240   usrp2::tx_metadata    md;
241   md.timestamp = -1;
242   md.start_of_burst = 1;
243   md.send_now = 1;
244
245   while (!signaled){
246
247     std::complex<int16_t> samples[MAX_SAMPLES];
248
249     int r = fread(samples, sizeof(uint32_t), samples_per_frame, fp);
250
251     // fprintf(stderr, "fread -> %d\n", r);
252     
253     if (r == 0){
254       if (!repeat)
255         break;
256       if (fseek(fp, 0, SEEK_SET) == -1)
257         break;
258     }
259
260     // FIXME if r < 9, pad to 9 for minimum packet size constraint
261
262     if (!u2->tx_16sc(0, samples, r, &md)){
263       fprintf(stderr, "tx_complex_int16 failed\n");
264       break;
265     }
266   }
267
268   return 0;
269 }