Merged r7478:7608 from michaelld/t186 into trunk. Adds ability to compile GNU Radio...
[debian/gnuradio] / usrp / host / apps-inband / test_usrp_inband_timestamps.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007 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 along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <mb_mblock.h>
27 #include <mb_runtime.h>
28 #include <mb_protocol_class.h>
29 #include <mb_exception.h>
30 #include <mb_msg_queue.h>
31 #include <mb_message.h>
32 #include <mb_msg_accepter.h>
33 #include <mb_class_registry.h>
34 #include <pmt.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <sys/time.h>
38 #include <iostream>
39
40 #include <ui_nco.h>
41 #include <symbols_usrp_server_cs.h>
42 #include <symbols_usrp_channel.h>
43 #include <symbols_usrp_low_level_cs.h>
44 #include <symbols_usrp_tx.h>
45 #include <symbols_usrp_rx.h>
46
47 #define NBPING  10
48
49 static bool verbose = true;
50 bool bskip = false;
51 long bstep = 10000;
52 long bcurr = 0;
53 long incr = 0x500;
54 long ptime = 0x000;
55
56 class test_usrp_inband_timestamps : public mb_mblock
57 {
58   mb_port_sptr  d_tx;
59   mb_port_sptr  d_rx;
60   mb_port_sptr  d_cs;
61   pmt_t         d_tx_chan;      // returned tx channel handle
62   pmt_t         d_rx_chan;      // returned tx channel handle
63
64   struct timeval times[NBPING];
65
66   enum state_t {
67     INIT,
68     OPENING_USRP,
69     ALLOCATING_CHANNEL,
70     TRANSMITTING,
71     CLOSING_CHANNEL,
72     CLOSING_USRP,
73   };
74
75   state_t       d_state;
76   long          d_nsamples_to_send;
77   long          d_nsamples_xmitted;
78   long          d_nframes_xmitted;
79   long          d_samples_per_frame;
80   bool          d_done_sending;
81
82   // for generating sine wave output
83   ui_nco<float,float>   d_nco;
84   double                d_amplitude;
85
86  public:
87   test_usrp_inband_timestamps(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
88   ~test_usrp_inband_timestamps();
89   void initial_transition();
90   void handle_message(mb_message_sptr msg);
91
92  protected:
93   void open_usrp();
94   void close_usrp();
95   void allocate_channel();
96   void send_packets();
97   void enter_receiving();
98   void enter_transmitting();
99   void build_and_send_ping();
100   void build_and_send_next_frame();
101   void handle_xmit_response(pmt_t invocation_handle);
102   void enter_closing_channel();
103 };
104
105 test_usrp_inband_timestamps::test_usrp_inband_timestamps(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
106   : mb_mblock(runtime, instance_name, user_arg),
107     d_tx_chan(PMT_NIL),
108     d_rx_chan(PMT_NIL),
109     d_state(INIT), d_nsamples_to_send((long) 40e6),
110     d_nsamples_xmitted(0),
111     d_nframes_xmitted(0),
112     //d_samples_per_frame((long)(126)),
113     d_samples_per_frame((long)(126 * 2)),       // non-full packet
114     //d_samples_per_frame((long)(126 * 3.5)),   // non-full packet
115     //d_samples_per_frame((long)(126 * 4)),     // full packet
116     d_done_sending(false),
117     d_amplitude(16384)
118
119   if(verbose)
120     std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Initializing...\n";
121   
122   d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
123   d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
124   d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
125   
126   bool fake_usrp_p = false;
127
128   // Test the TX side
129
130   pmt_t usrp_dict = pmt_make_dict();
131
132   if(fake_usrp_p) {
133     pmt_dict_set(usrp_dict, 
134                  pmt_intern("fake-usrp"),
135                              PMT_T);
136   }
137
138   // Set TX and RX interpolations
139   pmt_dict_set(usrp_dict,
140                pmt_intern("interp-tx"),
141                pmt_from_long(128));
142
143   pmt_dict_set(usrp_dict,
144                pmt_intern("decim-rx"),
145                pmt_from_long(16));
146
147   // Specify the RBF to use
148   pmt_dict_set(usrp_dict,
149                pmt_intern("rbf"),
150                pmt_intern("tmac5.rbf"));
151
152   define_component("server", "usrp_server", usrp_dict);
153
154   connect("self", "tx0", "server", "tx0");
155   connect("self", "rx0", "server", "rx0");
156   connect("self", "cs", "server", "cs");
157
158   // initialize NCO
159   double freq = 100e3;
160   int interp = 32;                          // 32 -> 4MS/s
161   double sample_rate = 128e6 / interp;  
162   d_nco.set_freq(2*M_PI * freq/sample_rate);
163
164 }
165
166 test_usrp_inband_timestamps::~test_usrp_inband_timestamps()
167 {
168 }
169
170 void
171 test_usrp_inband_timestamps::initial_transition()
172 {
173   open_usrp();
174 }
175
176 void
177 test_usrp_inband_timestamps::handle_message(mb_message_sptr msg)
178 {
179   pmt_t event = msg->signal();
180   pmt_t data = msg->data();
181   pmt_t port_id = msg->port_id();
182
183   pmt_t handle = PMT_F;
184   pmt_t status = PMT_F;
185   std::string error_msg;
186   
187   //std::cout << msg << std::endl;
188
189   switch(d_state){
190   case OPENING_USRP:
191     if (pmt_eq(event, s_response_open)){
192       status = pmt_nth(1, data);
193       if (pmt_eq(status, PMT_T)){
194         allocate_channel();
195         return;
196       }
197       else {
198         error_msg = "failed to open usrp:";
199         goto bail;
200       }
201     }
202     goto unhandled;
203     
204   case ALLOCATING_CHANNEL:
205     if (pmt_eq(event, s_response_allocate_channel)){
206
207       if(pmt_eq(d_tx->port_symbol(), port_id)) {
208         status = pmt_nth(1, data);
209         d_tx_chan = pmt_nth(2, data);
210
211         if (pmt_eq(status, PMT_T)){
212
213           if(verbose)
214             std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Received allocation for TX\n";
215
216           if(!pmt_eqv(d_rx_chan, PMT_NIL)) {
217             enter_receiving();
218             enter_transmitting();
219           }
220           return;
221         }
222         else {
223           error_msg = "failed to allocate channel:";
224           goto bail;
225         }
226       }
227       
228       if(pmt_eq(d_rx->port_symbol(), port_id)) {
229         status = pmt_nth(1, data);
230         d_rx_chan = pmt_nth(2, data);
231
232         if (pmt_eq(status, PMT_T)){
233
234           if(verbose)
235             std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Received allocation for TX\n";
236           
237           if(!pmt_eqv(d_tx_chan, PMT_NIL)) {
238             enter_receiving();
239             enter_transmitting();
240           }
241           return;
242         }
243         else {
244           error_msg = "failed to allocate channel:";
245           goto bail;
246         }
247       }
248     }
249     goto unhandled;
250
251   case TRANSMITTING:
252     if (pmt_eq(event, s_response_xmit_raw_frame)){
253       handle = pmt_nth(0, data);
254       status = pmt_nth(1, data);
255
256       if (pmt_eq(status, PMT_T)){
257         handle_xmit_response(handle);
258         return;
259       }
260       else {
261         error_msg = "bad response-xmit-raw-frame:";
262         goto bail;
263       }
264     }
265
266     if (pmt_eq(event, s_response_from_control_channel)) {
267       std::cout << "ping response!\n";
268     }
269     goto unhandled;
270
271   case CLOSING_CHANNEL:
272     if (pmt_eq(event, s_response_deallocate_channel)){
273       status = pmt_nth(1, data);
274
275       if (pmt_eq(status, PMT_T)){
276         close_usrp();
277         return;
278       }
279       else {
280         error_msg = "failed to deallocate channel:";
281         goto bail;
282       }
283     }
284     goto unhandled;
285
286   case CLOSING_USRP:
287     if (pmt_eq(event, s_response_close)){
288       status = pmt_nth(1, data);
289
290       if (pmt_eq(status, PMT_T)){
291         shutdown_all(PMT_T);
292         return;
293       }
294       else {
295         error_msg = "failed to close USRP:";
296         goto bail;
297       }
298     }
299     goto unhandled;
300
301   default:
302     goto unhandled;
303   }
304   return;
305
306  bail:
307   std::cerr << error_msg << data
308             << "status = " << status << std::endl;
309   shutdown_all(PMT_F);
310   return;
311
312  unhandled:
313   if(verbose && 0)
314     std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
315               << "in state "<< d_state << std::endl;
316 }
317
318
319 void
320 test_usrp_inband_timestamps::open_usrp()
321 {
322   pmt_t which_usrp = pmt_from_long(0);
323
324   d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
325   d_state = OPENING_USRP;
326 }
327
328 void
329 test_usrp_inband_timestamps::close_usrp()
330 {
331   d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
332   d_state = CLOSING_USRP;
333
334   if(verbose)
335     std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Closing USRP\n";
336 }
337
338 void
339 test_usrp_inband_timestamps::allocate_channel()
340 {
341   long capacity = (long) 16e6;
342   d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
343   d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
344   d_state = ALLOCATING_CHANNEL;
345 }
346
347 void
348 test_usrp_inband_timestamps::enter_receiving()
349 {
350   d_rx->send(s_cmd_start_recv_raw_samples,
351              pmt_list2(PMT_F,
352                        d_rx_chan));
353 }
354
355 void
356 test_usrp_inband_timestamps::enter_transmitting()
357 {
358   d_state = TRANSMITTING;
359   d_nsamples_xmitted = 0;
360
361   if(verbose)
362     std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Beginning transmission\n";
363
364   sleep(1);
365
366   build_and_send_next_frame();
367   build_and_send_next_frame();
368   build_and_send_next_frame();
369   build_and_send_next_frame();
370
371 }
372
373 void
374 test_usrp_inband_timestamps::build_and_send_ping()
375 {
376   
377   d_tx->send(s_cmd_to_control_channel,
378              pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed,
379                                                     pmt_list2(pmt_from_long(0),
380                                                               pmt_from_long(0))))));
381   if(verbose && 0)
382     std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Ping sent" << std::endl;
383 }
384
385 void
386 test_usrp_inband_timestamps::build_and_send_next_frame()
387 {
388   // allocate the uniform vector for the samples
389   // FIXME perhaps hold on to this between calls
390
391 #if 0
392   long nsamples_this_frame =
393     std::min(d_nsamples_to_send - d_nsamples_xmitted,
394              d_samples_per_frame);
395 #else
396   long nsamples_this_frame = d_samples_per_frame;
397 #endif
398
399   if (nsamples_this_frame == 0){
400     d_done_sending = true;
401     return;
402   }
403     
404
405   size_t nshorts = 2 * nsamples_this_frame;     // 16-bit I & Q
406   pmt_t uvec = pmt_make_s16vector(nshorts, 0);
407   size_t ignore;
408   int16_t *samples = pmt_s16vector_writeable_elements(uvec, ignore);
409
410   // fill in the complex sinusoid
411
412   for (int i = 0; i < nsamples_this_frame; i++){
413
414     if (1){
415       gr_complex s;
416       d_nco.sincos(&s, 1, d_amplitude);
417       // write 16-bit i & q
418       samples[2*i] =   (int16_t) s.real();
419       samples[2*i+1] = (int16_t) s.imag();
420     }
421     else {
422       gr_complex s(d_amplitude, d_amplitude);
423
424       // write 16-bit i & q
425       samples[2*i] =   (int16_t) s.real();
426       samples[2*i+1] = (int16_t) s.imag();
427     }
428   }
429
430   pmt_t timestamp;
431
432   if(bskip) {
433     timestamp = pmt_from_long(0x0);     // throw away  
434     bcurr++;
435     if(bcurr == bstep) {
436       bskip = false;
437       bcurr = 0;
438     }
439   } else {
440     timestamp = pmt_from_long(0xffffffff);      // NOW
441     timestamp = pmt_from_long(ptime);
442     ptime += incr;
443     bcurr++;
444     if(bcurr == bstep) {
445       //bskip = true;
446       bcurr = 0;
447     }
448   }
449
450   std::cout << bskip << " -- " << bcurr << std::endl;
451
452   d_tx->send(s_cmd_xmit_raw_frame,
453              pmt_list4(pmt_from_long(d_nframes_xmitted),  // invocation-handle
454                        d_tx_chan,                         // channel
455                        uvec,                              // the samples
456                        timestamp));
457
458   d_nsamples_xmitted += nsamples_this_frame;
459   d_nframes_xmitted++;
460
461   if(verbose && 0)
462     std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Transmitted frame\n";
463   
464   //build_and_send_next_frame();
465 }
466
467
468 void
469 test_usrp_inband_timestamps::handle_xmit_response(pmt_t handle)
470 {
471   if (d_done_sending &&
472       pmt_to_long(handle) == (d_nframes_xmitted - 1)){
473     // We're done sending and have received all responses
474     enter_closing_channel();
475   }
476
477   build_and_send_next_frame();
478   //build_and_send_ping();
479 }
480
481 void
482 test_usrp_inband_timestamps::enter_closing_channel()
483 {
484   d_state = CLOSING_CHANNEL;
485   
486   d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan));
487
488   if(verbose)
489     std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Closing channel\n";
490 }
491
492 REGISTER_MBLOCK_CLASS(test_usrp_inband_timestamps);
493
494
495 // ----------------------------------------------------------------
496
497 int
498 main (int argc, char **argv)
499 {
500   // handle any command line args here
501
502   mb_runtime_sptr rt = mb_make_runtime();
503   pmt_t result = PMT_NIL;
504
505   rt->run("top", "test_usrp_inband_timestamps", PMT_F, &result);
506 }