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