Merged r11377:11390 from jcorgan/usrp-headers in to trunk.
[debian/gnuradio] / usrp / limbo / apps-inband / test_usrp_inband_overrun.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007,2008 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 <mblock/mblock.h>
27 #include <mblock/runtime.h>
28 #include <mblock/protocol_class.h>
29 #include <mblock/exception.h>
30 #include <mblock/msg_queue.h>
31 #include <mblock/message.h>
32 #include <mblock/msg_accepter.h>
33 #include <mblock/class_registry.h>
34 #include <pmt.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <iostream>
38 #include <fstream>
39
40 // Include the symbols needed for communication with USRP server
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_rx.h>
45
46 static bool verbose = true;
47
48 class test_usrp_rx : public mb_mblock
49 {
50   mb_port_sptr  d_rx;
51   mb_port_sptr  d_cs;
52   pmt_t         d_rx_chan;      // returned tx channel handle
53
54   enum state_t {
55     INIT,
56     OPENING_USRP,
57     ALLOCATING_CHANNEL,
58     RECEIVING,
59     CLOSING_CHANNEL,
60     CLOSING_USRP,
61   };
62
63   state_t       d_state;
64
65   std::ofstream d_ofile;
66
67   long d_n_overruns;
68
69   long d_samples_recvd;
70   long d_samples_to_recv;
71
72  public:
73   test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
74   ~test_usrp_rx();
75   void initial_transition();
76   void handle_message(mb_message_sptr msg);
77
78  protected:
79   void open_usrp();
80   void close_usrp();
81   void allocate_channel();
82   void send_packets();
83   void enter_receiving();
84   void build_and_send_next_frame();
85   void handle_response_recv_raw_samples(pmt_t invocation_handle);
86   void enter_closing_channel();
87 };
88
89 test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
90   : mb_mblock(runtime, instance_name, user_arg),
91     d_n_overruns(0),
92     d_samples_recvd(0),
93     d_samples_to_recv(10e6)
94
95   
96   d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
97   d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
98   
99   // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP
100   pmt_t usrp_dict = pmt_make_dict();
101
102   // Specify the RBF to use
103   pmt_dict_set(usrp_dict,
104                pmt_intern("rbf"),
105                pmt_intern("inband_1rxhb_1tx.rbf"));
106
107   pmt_dict_set(usrp_dict,
108                pmt_intern("decim-rx"),
109                pmt_from_long(128));
110
111   define_component("server", "usrp_server", usrp_dict);
112
113   connect("self", "rx0", "server", "rx0");
114   connect("self", "cs", "server", "cs");
115
116 }
117
118 test_usrp_rx::~test_usrp_rx()
119 {
120 }
121
122 void
123 test_usrp_rx::initial_transition()
124 {
125   open_usrp();
126 }
127
128 void
129 test_usrp_rx::handle_message(mb_message_sptr msg)
130 {
131   pmt_t event = msg->signal();
132   pmt_t data = msg->data();
133
134   pmt_t handle = PMT_F;
135   pmt_t status = PMT_F;
136   std::string error_msg;
137   
138   switch(d_state){
139     
140     //----------------------------- OPENING_USRP ----------------------------//
141     // We only expect a response from opening the USRP which should be succesful
142     // or failed.
143     case OPENING_USRP:
144       if (pmt_eq(event, s_response_open)){
145         status = pmt_nth(1, data);
146         if (pmt_eq(status, PMT_T)){
147           allocate_channel();
148           return;
149         }
150         else {
151           error_msg = "failed to open usrp:";
152           goto bail;
153         }
154       }
155       goto unhandled;
156       
157     //----------------------- ALLOCATING CHANNELS --------------------//
158     // Allocate an RX channel to perform the overrun test.
159     case ALLOCATING_CHANNEL:
160       if (pmt_eq(event, s_response_allocate_channel)){
161         status = pmt_nth(1, data);
162         d_rx_chan = pmt_nth(2, data);
163
164         if (pmt_eq(status, PMT_T)){
165           enter_receiving();
166           return;
167         }
168         else {
169           error_msg = "failed to allocate channel:";
170           goto bail;
171         }
172       }
173       goto unhandled;
174
175     //--------------------------- RECEIVING ------------------------------//
176     // In the receiving state, we receive samples until the specified amount
177     // while counting the number of overruns.
178     case RECEIVING:
179       if (pmt_eq(event, s_response_recv_raw_samples)){
180         status = pmt_nth(1, data);
181
182         if (pmt_eq(status, PMT_T)){
183           handle_response_recv_raw_samples(data);
184           return;
185         }
186         else {
187           error_msg = "bad response-xmit-raw-frame:";
188           goto bail;
189         }
190       }
191       goto unhandled;
192     
193     //------------------------- CLOSING CHANNEL ----------------------------//
194     // Check deallocation response for the RX channel 
195     case CLOSING_CHANNEL:
196       if (pmt_eq(event, s_response_deallocate_channel)){
197         status = pmt_nth(1, data);
198
199         if (pmt_eq(status, PMT_T)){
200           close_usrp();
201           return;
202         }
203         else {
204           error_msg = "failed to deallocate channel:";
205           goto bail;
206         }
207       }
208
209       // Alternately, we ignore all response recv samples while waiting for the
210       // channel to actually close
211       if (pmt_eq(event, s_response_recv_raw_samples))
212         return;
213
214       goto unhandled;
215
216     //--------------------------- CLOSING USRP ------------------------------//
217     // Once we have received a successful USRP close response, we shutdown all
218     // mblocks and exit.
219     case CLOSING_USRP:
220       if (pmt_eq(event, s_response_close)){
221         status = pmt_nth(1, data);
222
223         if (pmt_eq(status, PMT_T)){
224           std::cout << "\nOverruns: " << d_n_overruns << std::endl;
225           fflush(stdout);
226           shutdown_all(PMT_T);
227           return;
228         }
229         else {
230           error_msg = "failed to close USRP:";
231           goto bail;
232         }
233       }
234       goto unhandled;
235
236     default:
237       goto unhandled;
238   }
239   return;
240
241  // An error occured, print it, and shutdown all m-blocks
242  bail:
243   std::cerr << error_msg << data
244             << "status = " << status << std::endl;
245   shutdown_all(PMT_F);
246   return;
247
248  // Received an unhandled message for a specific state
249  unhandled:
250   if(verbose && !pmt_eq(event, pmt_intern("%shutdown")))
251     std::cout << "test_usrp_inband_tx: unhandled msg: " << msg
252               << "in state "<< d_state << std::endl;
253 }
254
255
256 void
257 test_usrp_rx::open_usrp()
258 {
259   pmt_t which_usrp = pmt_from_long(0);
260
261   d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp));
262   d_state = OPENING_USRP;
263   
264   if(verbose)
265     std::cout << "[TEST_USRP_INBAND_OVERRUN] Opening the USRP\n";
266 }
267
268 void
269 test_usrp_rx::close_usrp()
270 {
271   d_cs->send(s_cmd_close, pmt_list1(PMT_NIL));
272   d_state = CLOSING_USRP;
273   
274   if(verbose)
275     std::cout << "[TEST_USRP_INBAND_OVERRUN] Closing the USRP\n";
276 }
277
278 void
279 test_usrp_rx::allocate_channel()
280 {
281   long capacity = (long) 16e6;
282   d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity)));
283   d_state = ALLOCATING_CHANNEL;
284   
285   if(verbose)
286     std::cout << "[TEST_USRP_INBAND_OVERRUN] Requesting RX channel allocation\n";
287 }
288
289 void
290 test_usrp_rx::enter_receiving()
291 {
292   d_state = RECEIVING;
293
294   d_rx->send(s_cmd_start_recv_raw_samples,
295              pmt_list2(PMT_F,
296                        d_rx_chan));
297
298   if(verbose)
299     std::cout << "[TEST_USRP_INBAND_OVERRUN] Receiving...\n";
300 }
301
302 void
303 test_usrp_rx::handle_response_recv_raw_samples(pmt_t data)
304 {
305   pmt_t invocation_handle = pmt_nth(0, data);
306   pmt_t status = pmt_nth(1, data);
307   pmt_t v_samples = pmt_nth(2, data);
308   pmt_t timestamp = pmt_nth(3, data);
309   pmt_t channel = pmt_nth(4, data);
310   pmt_t properties = pmt_nth(5, data);
311
312   d_samples_recvd += pmt_length(v_samples) / 4;
313
314   // Check for overrun
315   if(!pmt_is_dict(properties)) {
316     std::cout << "[TEST_USRP_INBAND_OVERRUN] Recv samples dictionary is improper\n";
317     return;
318   }
319
320   if(pmt_t overrun = pmt_dict_ref(properties, 
321                                   pmt_intern("overrun"), 
322                                   PMT_NIL)) {
323     if(pmt_eqv(overrun, PMT_T)) {
324       d_n_overruns++;
325
326       if(verbose && 0)
327         std::cout << "[TEST_USRP_INBAND_OVERRUN] Underrun\n";
328     }
329     else {
330     if(verbose && 0)
331       std::cout << "[TEST_USRP_INBAND_OVERRUN] No overrun\n" << overrun <<std::endl;
332     }
333   } else {
334
335     if(verbose && 0)
336       std::cout << "[TEST_USRP_INBAND_OVERRUN] No overrun\n";
337   }
338
339   // Check if the number samples we have received meets the test
340   if(d_samples_recvd >= d_samples_to_recv) {
341     d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan));
342     enter_closing_channel();
343     return;
344   }
345
346 }
347
348 void
349 test_usrp_rx::enter_closing_channel()
350 {
351   d_state = CLOSING_CHANNEL;
352   
353   sleep(2);
354   
355   d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan));
356   
357   if(verbose)
358     std::cout << "[TEST_USRP_INBAND_OVERRUN] Deallocating RX channel\n";
359 }
360
361 REGISTER_MBLOCK_CLASS(test_usrp_rx);
362
363
364 // ----------------------------------------------------------------
365
366 int
367 main (int argc, char **argv)
368 {
369   // handle any command line args here
370
371   mb_runtime_sptr rt = mb_make_runtime();
372   pmt_t result = PMT_NIL;
373
374   rt->run("top", "test_usrp_rx", PMT_F, &result);
375 }