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