]> git.gag.com Git - debian/gnuradio/blob - usrp/host/lib/inband/usrp_usb_interface.cc
Merged features/inband-usb -r6431:8293 into trunk.
[debian/gnuradio] / usrp / host / lib / inband / usrp_usb_interface.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 <usrp_usb_interface.h>
27
28 #include <iostream>
29 #include <vector>
30 #include <usb.h>
31 #include <mb_class_registry.h>
32 #include <usrp_inband_usb_packet.h>
33 #include <fpga_regs_common.h>
34 #include "usrp_rx.h"
35 #include <usrp_rx_stub.h>
36 #include "usrp_tx.h"
37 #include "usrp_standard.h"
38 #include <stdio.h>
39
40 typedef usrp_inband_usb_packet transport_pkt;
41
42 #include <symbols_usrp_interface_cs.h>
43 #include <symbols_usrp_tx_cs.h>
44 #include <symbols_usrp_rx_cs.h>
45 static pmt_t s_shutdown = pmt_intern("%shutdown");
46
47 static const bool verbose = false;
48
49
50 /*!
51  * \brief Initializes the USB interface m-block.
52  *
53  * The \p user_arg should be a PMT dictionary which can contain optional
54  * arguments for the block, such as the decimatoin and interpolation rate.
55  */
56 usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
57   : mb_mblock(rt, instance_name, user_arg),
58   d_fake_usrp(false),
59   d_rx_reading(false),
60   d_interp_tx(128),
61   d_decim_rx(128),
62   d_rf_freq(10e6),
63   d_rbf("inband_tx_rx.rbf")
64 {
65   // Dictionary for arguments to all of the components
66   pmt_t usrp_dict = user_arg;
67   
68   // Default TX/RX interface
69   std::string tx_interface = "usrp_tx";
70   std::string rx_interface = "usrp_rx";
71   
72   if (pmt_is_dict(usrp_dict)) {
73
74     // The 'fake-usrp' key enables the TX and RX stubs if PMT_T
75     if(pmt_t fake_usrp = pmt_dict_ref(usrp_dict, 
76                                       pmt_intern("fake-usrp"), 
77                                       PMT_NIL)) {
78       if(pmt_eqv(fake_usrp, PMT_T)) {
79         tx_interface = "usrp_tx_stub";
80         rx_interface = "usrp_rx_stub";
81         d_fake_usrp=true;
82       }
83     }
84
85     // Read the TX interpolations
86     if(pmt_t interp_tx = pmt_dict_ref(usrp_dict, 
87                                       pmt_intern("interp-tx"), 
88                                       PMT_NIL)) {
89       if(!pmt_eqv(interp_tx, PMT_NIL)) 
90         d_interp_tx = pmt_to_long(interp_tx);
91     }
92     
93     // Read the RX decimation rate
94     if(pmt_t decim_rx = pmt_dict_ref(usrp_dict, 
95                                       pmt_intern("decim-rx"), 
96                                       PMT_NIL)) {
97       if(!pmt_eqv(decim_rx, PMT_NIL)) 
98         d_decim_rx = pmt_to_long(decim_rx);
99     }
100
101     // Read the RBF
102     if(pmt_t rbf = pmt_dict_ref(usrp_dict, 
103                                 pmt_intern("rbf"), 
104                                 PMT_NIL)) {
105       if(!pmt_eqv(rbf, PMT_NIL)) 
106         d_rbf = pmt_symbol_to_string(rbf);
107     }
108
109     // The RF center frequency
110     if(pmt_t rf_freq = pmt_dict_ref(usrp_dict, 
111                                 pmt_intern("rf-freq"), 
112                                 PMT_NIL)) {
113       if(!pmt_eqv(rf_freq, PMT_NIL)) 
114         d_rf_freq = pmt_to_long(rf_freq);
115     }
116   }
117   
118   if (verbose) {
119     std::cout << "[USRP_USB_INTERFACE] Setting USRP RBF to " 
120               << d_rbf << std::endl;
121     
122     std::cout << "[USRP_USB_INTERFACE] Setting TX interpolation to " 
123               << d_interp_tx << std::endl;
124           
125     std::cout << "[USRP_USB_INTERFACE] Setting RX interpolation to " 
126               << d_decim_rx << std::endl;
127
128     std::cout << "[USRP_USB_INTERFACE] Using TX interface: " 
129               << tx_interface << "\n";
130
131     std::cout << "[USRP_USB_INTERFACE] Using RX interface: " 
132               << rx_interface << "\n";
133
134   }
135
136   d_cs = define_port("cs", "usrp-interface-cs", true, mb_port::EXTERNAL);       
137   d_rx_cs = define_port("rx_cs", "usrp-rx-cs", false, mb_port::INTERNAL);       
138   d_tx_cs = define_port("tx_cs", "usrp-tx-cs", false, mb_port::INTERNAL);       
139
140   // Connect to TX and RX
141   define_component("tx", tx_interface, usrp_dict);
142   define_component("rx", rx_interface, usrp_dict);
143   connect("self", "rx_cs", "rx", "cs");
144   connect("self", "tx_cs", "tx", "cs");
145   
146   // FIX ME: the code should query the FPGA to retrieve the number of channels and such
147   d_ntx_chan = 2;
148   d_nrx_chan = 2;
149
150   d_utx = NULL;
151   d_urx = NULL;
152   
153 }
154
155 usrp_usb_interface::~usrp_usb_interface() 
156
157
158 }
159
160 void 
161 usrp_usb_interface::initial_transition()
162 {
163
164 }
165
166 /*!
167  * \brief Handles all incoming signals to the block from the lowest m-blocks
168  * which read/write to the bus, or the higher m-block which is the USRP server.
169  */
170 void
171 usrp_usb_interface::handle_message(mb_message_sptr msg)
172 {
173   pmt_t event = msg->signal();          // the "name" of the message
174   pmt_t port_id = msg->port_id();       // which port it came in on
175   pmt_t data = msg->data();
176   pmt_t invocation_handle;
177
178   if (pmt_eq(event, s_shutdown))        // ignore (for now)
179     return;
180
181   //------------- CONTROL / STATUS -------------//
182   if (pmt_eq(port_id, d_cs->port_symbol())) {   
183
184     //------------ OPEN --------------//
185     if (pmt_eq(event, s_cmd_usrp_open)){
186       handle_cmd_open(data);
187       return;
188     }
189     //----------- CLOSE -------------//
190     else if (pmt_eq(event, s_cmd_usrp_close)) {
191       handle_cmd_close(data);
192       return;
193     }
194     //---------- NTX CHAN ----------//
195     else if (pmt_eq(event, s_cmd_usrp_ntx_chan)) {
196       invocation_handle = pmt_nth(0, data);
197       d_cs->send(s_response_usrp_ntx_chan, 
198                  pmt_list2(invocation_handle, 
199                            pmt_from_long(d_ntx_chan)));
200       return;
201     }
202     //---------- NRX CHAN ----------//
203     else if (pmt_eq(event, s_cmd_usrp_nrx_chan)) {
204       invocation_handle = pmt_nth(0, data);
205       d_cs->send(s_response_usrp_nrx_chan, 
206                  pmt_list2(invocation_handle, 
207                            pmt_from_long(d_nrx_chan)));
208       return;
209     }
210     //------------ WRITE -----------//
211     else if(pmt_eq(event, s_cmd_usrp_write)) {
212       handle_cmd_write(data);
213       return;
214     }
215     //-------- START READING --------//
216     else if(pmt_eq(event, s_cmd_usrp_start_reading)) {
217       handle_cmd_start_reading(data);
218       return;
219     }
220     //-------- STOP READING --------//
221     else if(pmt_eq(event, s_cmd_usrp_stop_reading)) {
222       handle_cmd_stop_reading(data);
223       return;
224     }
225
226     goto unhandled;
227   }
228
229   //---------------- RX ------------------//
230   if (pmt_eq(port_id, d_rx_cs->port_symbol())) {        
231
232     // Relay reads back up
233     if(pmt_eq(event, s_response_usrp_rx_read))  {
234       d_cs->send(s_response_usrp_read, data);
235       return;
236     }
237
238     goto unhandled;
239   }
240   
241   //---------------- TX ------------------//
242   if (pmt_eq(port_id, d_tx_cs->port_symbol())) {        
243
244     if(pmt_eq(event, s_response_usrp_tx_write))  {
245
246       pmt_t invocation_handle = pmt_nth(0, data);
247       pmt_t status = pmt_nth(1, data);
248       pmt_t channel = pmt_nth(2, data);
249
250       d_cs->send(s_response_usrp_write,
251                  pmt_list3(invocation_handle,
252                            status,
253                            channel));
254
255       return;
256     }
257
258     goto unhandled;
259   }
260
261  unhandled:
262   std::cout << "[USRP_USB_INTERFACE] unhandled msg: " << msg << std::endl;
263 }
264
265 /*!
266  * \brief Called by the handle_message() method when the incoming signal is to
267  * open a USB connection to the USRP (cmd-usrp-open).
268  *
269  * The \p data parameter is a PMT list, where the elements are an invocation
270  * handle and the USRP number.
271  */
272 void
273 usrp_usb_interface::handle_cmd_open(pmt_t data)
274 {
275   pmt_t invocation_handle = pmt_nth(0, data);
276   long which_usrp = pmt_to_long(pmt_nth(1, data));
277   pmt_t reply_data;
278  
279   if(d_fake_usrp) {
280     d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
281     return;
282   }
283
284   if (verbose)
285     std::cout << "[USRP_USB_INTERFACE] Handling open request for USRP " << which_usrp << "\n";
286
287   // Open up a standard RX and TX for communication with the USRP
288    
289   d_utx = usrp_standard_tx::make(which_usrp,
290                                  d_interp_tx,
291                                  1,                     // 1 channel
292                                  -1,          // mux
293                                  4096,        // USB block size
294                                  16,          // nblocks for async transfers
295                                  d_rbf
296                                  );
297   
298   if(d_utx==0) {
299     if (verbose)
300       std::cout << "[USRP_USB_INTERFACE] Failed to open TX\n";
301     reply_data = pmt_list2(invocation_handle, PMT_F);
302     d_cs->send(s_response_usrp_open, reply_data);
303     return;
304   }
305
306   if(!d_utx->set_tx_freq (0,d_rf_freq) || !d_utx->set_tx_freq(1,d_rf_freq)) {  // try setting center freq to 0
307     if (verbose)
308       std::cout << "[USRP_USB_INTERFACE] Failed to set center frequency on TX\n";
309     reply_data = pmt_list2(invocation_handle, PMT_F);
310     d_cs->send(s_response_usrp_open, reply_data);
311     return;
312   }
313
314   if(!d_utx->set_mux(0xBA98)) {
315     if (verbose)
316       std::cout << "[USRP_USB_INTERFACE] Failed to set TX mux\n";
317     reply_data = pmt_list2(invocation_handle, PMT_F);
318     d_cs->send(s_response_usrp_open, reply_data);
319     return;
320   }
321
322   d_utx->start();
323
324   if (verbose)
325     std::cout << "[USRP_USB_INTERFACE] Setup TX channel\n";
326
327   d_urx =
328     usrp_standard_rx::make (which_usrp,
329                             d_decim_rx,         
330                             1,                  // nchan
331                             -1,           // mux
332                             0,            // set blank mode to start
333                             4096,         // USB block size
334                             16,           // number of blocks for async transfers
335           d_rbf);
336
337   if(!d_urx) {
338     if (verbose)
339       std::cout << "[usrp_server] Failed to open RX\n";
340     reply_data = pmt_list2(invocation_handle, PMT_F);
341     d_cs->send(s_response_usrp_open, reply_data);
342     return;
343   }
344
345   if(!d_urx->set_rx_freq (0, -d_rf_freq) || !d_urx->set_rx_freq(1, -d_rf_freq)) {
346     if (verbose)
347       std::cout << "[usrp_server] Failed to set center frequency on RX\n";
348     reply_data = pmt_list2(invocation_handle, PMT_F);
349     d_cs->send(s_response_usrp_open, reply_data);
350     return;
351   }
352   
353   // Two channels ... this really needs to end up being set correctly by
354   // querying for what dboards are connected
355   if(!d_urx->set_mux(0x32103210)) {
356     if (verbose)
357       std::cout << "[USRP_USB_INTERFACE] Failed to set RX mux\n";
358     reply_data = pmt_list2(invocation_handle, PMT_F);
359     d_cs->send(s_response_usrp_open, reply_data);
360     return;
361   }
362
363   if (verbose)
364     std::cout << "[USRP_USB_INTERFACE] Setup RX channel\n";
365     
366 //  d_utx->_write_fpga_reg(FR_DEBUG_EN,0xf);
367 //  d_utx->_write_oe(0, 0xffff, 0xffff);
368 //  d_urx->_write_oe(0, 0xffff, 0xffff);
369 //  d_utx->_write_oe(1, 0xffff, 0xffff);
370 //  d_urx->_write_oe(1, 0xffff, 0xffff);
371
372   d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
373 }
374
375 /*!
376  * \brief Called by the handle_message() method when the incoming signal is to
377  * write data to the USB bus (cmd-usrp-write). 
378  *
379  * The \p data parameter is a PMT list containing 3 mandatory elements in the
380  * following order: an invocation handle, channel, and a uniform vector
381  * representation of the packets.
382  */
383 void
384 usrp_usb_interface::handle_cmd_write(pmt_t data)
385 {
386   pmt_t invocation_handle = pmt_nth(0, data);
387   pmt_t channel = pmt_nth(1, data);
388   pmt_t pkts = pmt_nth(2, data);
389
390   pmt_t tx_handle = pmt_make_any(d_utx);
391
392   d_tx_cs->send(s_cmd_usrp_tx_write, 
393                 pmt_list4(invocation_handle, 
394                           channel,
395                           pkts,
396                           tx_handle));
397
398   return;
399 }
400
401 /*!
402  * \brief Called by the handle_message() method when the incoming signal is to
403  * start reading data from the USB bus (cmd-usrp-start-reading).
404  *
405  * The \p data parameter is a PMT list with a single element: an invocation
406  * handle which can be returned with the response.
407  */
408 void
409 usrp_usb_interface::handle_cmd_start_reading(pmt_t data)
410 {
411   pmt_t invocation_handle = pmt_nth(0, data);
412   
413   if(verbose)
414     std::cout << "[USRP_USB_INTERFACE] Starting RX...\n";
415
416   if(!d_fake_usrp)
417     d_urx->start();
418
419   pmt_t rx_handle = pmt_make_any(d_urx);
420
421   d_rx_cs->send(s_cmd_usrp_rx_start_reading, pmt_list2(PMT_NIL, rx_handle));
422
423   d_rx_reading = true;
424
425   return;
426 }
427
428 /*!
429  * \brief Called by the handle_message() method when the incoming signal is to
430  * stop reading data from the USB bus (cmd-usrp-stop-reading).
431  *
432  * The \p data parameter is a PMT list with a single element: an invocation
433  * handle which can be returned with the response.
434  */
435 void
436 usrp_usb_interface::handle_cmd_stop_reading(pmt_t data)
437 {
438   pmt_t invocation_handle = pmt_nth(0, data);
439   
440   if(!d_fake_usrp) {
441     if(verbose)
442       std::cout << "[USRP_USB_INTERFACE] Stopping RX...\n";
443     usrp_rx_stop = true;
444
445     // Used to allow a read() being called by a lower layer to complete before
446     // stopping, else there can be partial data left on the bus and can generate
447     // errors.
448     while(usrp_rx_stop) {usleep(1);}
449     d_urx->stop();
450   }
451   else {
452     if(verbose)
453       std::cout << "[USRP_USB_INTERFACE] Stopping fake RX...\n";
454     usrp_rx_stop_stub = true;  // extern to communicate with stub to wait
455   }
456
457   d_rx_reading = false;
458
459   return;
460 }
461
462 /*!
463  * \brief Called by the handle_message() method when the incoming signal is to
464  * close the USB connection to the USRP.
465  *
466  * The \p data parameter is a PMT list with a single element: an invocation
467  * handle which can be returned with the response.
468  */
469 void
470 usrp_usb_interface::handle_cmd_close(pmt_t data)
471 {
472   pmt_t invocation_handle = pmt_nth(0, data);
473
474   if(d_rx_reading)
475     handle_cmd_stop_reading(PMT_NIL);
476
477   if(d_fake_usrp) {
478     d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
479     return;
480   }
481   
482   if (verbose)
483     std::cout << "[USRP_USB_INTERFACE] Handling close request for USRP\n";
484
485   delete d_utx;
486   d_utx = 0;
487
488   delete d_urx;
489   d_urx = 0;
490
491   d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
492
493   shutdown_all(PMT_T);
494 }
495
496
497 REGISTER_MBLOCK_CLASS(usrp_usb_interface);