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