269ed2706d24548870f57d06abdbe85ae9da7bd3
[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 // need to take number of TX and RX channels as parameter
52 usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
53   : mb_mblock(rt, instance_name, user_arg),
54   d_fpga_debug(false),
55   d_fake_usrp(false),
56   d_interp_tx(128),
57   d_decim_rx(128),
58   d_rf_freq(10e6),
59   d_rbf("inband_tx_rx.rbf")
60 {
61   // Dictionary for arguments to all of the components
62   pmt_t usrp_dict = user_arg;
63   
64   // Default TX/RX interface
65   std::string tx_interface = "usrp_tx";
66   std::string rx_interface = "usrp_rx";
67   
68   if (pmt_is_dict(usrp_dict)) {
69
70     // The 'fake-usrp' key enables the TX and RX stubs if PMT_T
71     if(pmt_t fake_usrp = pmt_dict_ref(usrp_dict, 
72                                       pmt_intern("fake-usrp"), 
73                                       PMT_NIL)) {
74       if(pmt_eqv(fake_usrp, PMT_T)) {
75         tx_interface = "usrp_tx_stub";
76         rx_interface = "usrp_rx_stub";
77         d_fake_usrp=true;
78       }
79     }
80
81     // Read the TX interpolations
82     if(pmt_t interp_tx = pmt_dict_ref(usrp_dict, 
83                                       pmt_intern("interp-tx"), 
84                                       PMT_NIL)) {
85       if(!pmt_eqv(interp_tx, PMT_NIL)) 
86         d_interp_tx = pmt_to_long(interp_tx);
87     }
88     
89     // Read the RX interpolations
90     if(pmt_t decim_rx = pmt_dict_ref(usrp_dict, 
91                                       pmt_intern("decim-rx"), 
92                                       PMT_NIL)) {
93       if(!pmt_eqv(decim_rx, PMT_NIL)) 
94         d_decim_rx = pmt_to_long(decim_rx);
95     }
96
97     // Read the RBF
98     if(pmt_t rbf = pmt_dict_ref(usrp_dict, 
99                                 pmt_intern("rbf"), 
100                                 PMT_NIL)) {
101       if(!pmt_eqv(rbf, PMT_NIL)) 
102         d_rbf = pmt_symbol_to_string(rbf);
103     }
104
105     // The RF center frequency
106     if(pmt_t rf_freq = pmt_dict_ref(usrp_dict, 
107                                 pmt_intern("rf-freq"), 
108                                 PMT_NIL)) {
109       if(!pmt_eqv(rf_freq, PMT_NIL)) 
110         d_rf_freq = pmt_to_long(rf_freq);
111     }
112   }
113   
114   if (verbose) {
115     std::cout << "[USRP_USB_INTERFACE] Setting USRP RBF to " 
116               << d_rbf << std::endl;
117     
118     std::cout << "[USRP_USB_INTERFACE] Setting TX interpolation to " 
119               << d_interp_tx << std::endl;
120           
121     std::cout << "[USRP_USB_INTERFACE] Setting RX interpolation to " 
122               << d_decim_rx << std::endl;
123
124     std::cout << "[USRP_USB_INTERFACE] Using TX interface: " 
125               << tx_interface << "\n";
126
127     std::cout << "[USRP_USB_INTERFACE] Using RX interface: " 
128               << rx_interface << "\n";
129
130   }
131
132   d_cs = define_port("cs", "usrp-interface-cs", true, mb_port::EXTERNAL);       
133   d_rx_cs = define_port("rx_cs", "usrp-rx-cs", false, mb_port::INTERNAL);       
134   d_tx_cs = define_port("tx_cs", "usrp-tx-cs", false, mb_port::INTERNAL);       
135
136   // Connect to TX and RX
137   define_component("tx", tx_interface, PMT_F);
138   define_component("rx", rx_interface, PMT_F);
139   connect("self", "rx_cs", "rx", "cs");
140   connect("self", "tx_cs", "tx", "cs");
141   
142   // FIX ME: the code should query the FPGA to retrieve the number of channels and such
143   d_ntx_chan = 2;
144   d_nrx_chan = 2;
145
146   d_utx = NULL;
147   d_urx = NULL;
148   
149   d_fpga_debug=true;   // WARNING: DO NOT ENABLE WITH D'BOARDS OTHER THAN BASIC TX/RX
150
151 }
152
153 usrp_usb_interface::~usrp_usb_interface() 
154
155
156 }
157
158 void 
159 usrp_usb_interface::initial_transition()
160 {
161
162 }
163
164 void
165 usrp_usb_interface::handle_message(mb_message_sptr msg)
166 {
167   pmt_t event = msg->signal();          // the "name" of the message
168   pmt_t port_id = msg->port_id();       // which port it came in on
169   pmt_t data = msg->data();
170   pmt_t invocation_handle;
171
172   if (pmt_eq(event, s_shutdown))        // ignore (for now)
173     return;
174
175   //------------- CONTROL / STATUS -------------//
176   if (pmt_eq(port_id, d_cs->port_symbol())) {   
177
178     //------------ OPEN --------------//
179     if (pmt_eq(event, s_cmd_usrp_open)){
180       handle_cmd_open(data);
181       return;
182     }
183     //----------- CLOSE -------------//
184     else if (pmt_eq(event, s_cmd_usrp_close)) {
185       handle_cmd_close(data);
186       return;
187     }
188     //---------- NTX CHAN ----------//
189     else if (pmt_eq(event, s_cmd_usrp_ntx_chan)) {
190       invocation_handle = pmt_nth(0, data);
191       d_cs->send(s_response_usrp_ntx_chan, 
192                  pmt_list2(invocation_handle, 
193                            pmt_from_long(d_ntx_chan)));
194       return;
195     }
196     //---------- NRX CHAN ----------//
197     else if (pmt_eq(event, s_cmd_usrp_nrx_chan)) {
198       invocation_handle = pmt_nth(0, data);
199       d_cs->send(s_response_usrp_nrx_chan, 
200                  pmt_list2(invocation_handle, 
201                            pmt_from_long(d_nrx_chan)));
202       return;
203     }
204     //------------ WRITE -----------//
205     else if(pmt_eq(event, s_cmd_usrp_write)) {
206       handle_cmd_write(data);
207       return;
208     }
209     //-------- START READING --------//
210     else if(pmt_eq(event, s_cmd_usrp_start_reading)) {
211       handle_cmd_start_reading(data);
212       return;
213     }
214     //-------- STOP READING --------//
215     else if(pmt_eq(event, s_cmd_usrp_stop_reading)) {
216       handle_cmd_stop_reading(data);
217       return;
218     }
219
220     goto unhandled;
221   }
222
223   //---------------- RX ------------------//
224   if (pmt_eq(port_id, d_rx_cs->port_symbol())) {        
225
226     // Relay reads back up
227     if(pmt_eq(event, s_response_usrp_rx_read))  {
228       d_cs->send(s_response_usrp_read, data);
229       return;
230     }
231
232     goto unhandled;
233   }
234   
235   //---------------- TX ------------------//
236   if (pmt_eq(port_id, d_tx_cs->port_symbol())) {        
237
238     if(pmt_eq(event, s_response_usrp_tx_write))  {
239
240       pmt_t invocation_handle = pmt_nth(0, data);
241       pmt_t status = pmt_nth(1, data);
242       pmt_t channel = pmt_nth(2, data);
243
244       d_cs->send(s_response_usrp_write,
245                  pmt_list3(invocation_handle,
246                            status,
247                            channel));
248
249       return;
250     }
251
252     goto unhandled;
253   }
254
255  unhandled:
256   std::cout << "[USRP_USB_INTERFACE] unhandled msg: " << msg << std::endl;
257 }
258
259 void
260 usrp_usb_interface::handle_cmd_open(pmt_t data)
261 {
262   pmt_t invocation_handle = pmt_nth(0, data);
263   long which_usrp = pmt_to_long(pmt_nth(1, data));
264   pmt_t reply_data;
265  
266   if(d_fake_usrp) {
267     d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
268     return;
269   }
270
271   if (verbose)
272     std::cout << "[USRP_USB_INTERFACE] Handling open request for USRP " << which_usrp << "\n";
273
274   // Open up a standard RX and TX for communication with the USRP
275    
276   d_utx = usrp_standard_tx::make(which_usrp,
277                                  d_interp_tx,
278                                  1,                     // 1 channel
279                                  -1,          // mux
280                                  4096,        // USB block size
281                                  16,          // nblocks for async transfers
282                                  d_rbf
283                                  );
284   
285   if(d_utx==0) {
286     if (verbose)
287       std::cout << "[USRP_USB_INTERFACE] Failed to open TX\n";
288     reply_data = pmt_list2(invocation_handle, PMT_F);
289     d_cs->send(s_response_usrp_open, reply_data);
290     return;
291   }
292
293   if(!d_utx->set_tx_freq (0,d_rf_freq)) {  // try setting center freq to 0
294     if (verbose)
295       std::cout << "[USRP_USB_INTERFACE] Failed to set center frequency on TX\n";
296     reply_data = pmt_list2(invocation_handle, PMT_F);
297     d_cs->send(s_response_usrp_open, reply_data);
298     return;
299   }
300
301   d_utx->start();
302
303   if (verbose)
304     std::cout << "[USRP_USB_INTERFACE] Setup TX channel\n";
305
306   d_urx =
307     usrp_standard_rx::make (which_usrp,
308                             d_decim_rx,         
309                             1,                  // nchan
310                             -1,           // mux
311                             0,            // set blank mode to start
312                             4096,         // USB block size
313                             16,           // number of blocks for async transfers
314           d_rbf);
315
316   if(!d_urx) {
317     if (verbose)
318       std::cout << "[usrp_server] Failed to open RX\n";
319     reply_data = pmt_list2(invocation_handle, PMT_F);
320     d_cs->send(s_response_usrp_open, reply_data);
321     return;
322   }
323
324   if(!d_urx->set_rx_freq (0, d_rf_freq)) {
325     if (verbose)
326       std::cout << "[usrp_server] Failed to set center frequency on RX\n";
327     reply_data = pmt_list2(invocation_handle, PMT_F);
328     d_cs->send(s_response_usrp_open, reply_data);
329     return;
330   }
331
332   if(d_fpga_debug) {
333     d_utx->_write_fpga_reg(FR_DEBUG_EN,0xf);
334     d_utx->_write_oe(0, 0xffff, 0xffff);
335     d_urx->_write_oe(0, 0xffff, 0xffff);
336     d_utx->_write_oe(1, 0xffff, 0xffff);
337     d_urx->_write_oe(1, 0xffff, 0xffff);
338
339 //    while(1){
340 //      for(int i=0; i<0xffff; i++) 
341 //        d_urx->write_io(0, i, 0xffff);
342 //    }
343   }
344   
345   if (verbose)
346     std::cout << "[USRP_USB_INTERFACE] Setup RX channel\n";
347
348   d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
349 }
350
351 void
352 usrp_usb_interface::handle_cmd_write(pmt_t data)
353 {
354   pmt_t invocation_handle = pmt_nth(0, data);
355   pmt_t channel = pmt_nth(1, data);
356   pmt_t pkts = pmt_nth(2, data);
357
358   pmt_t tx_handle = pmt_make_any(d_utx);
359
360   d_tx_cs->send(s_cmd_usrp_tx_write, 
361                 pmt_list4(invocation_handle, 
362                           channel,
363                           pkts,
364                           tx_handle));
365
366   return;
367 }
368
369 void
370 usrp_usb_interface::handle_cmd_start_reading(pmt_t data)
371 {
372   pmt_t invocation_handle = pmt_nth(0, data);
373   
374   if(verbose)
375     std::cout << "[USRP_USB_INTERFACE] Starting RX...\n";
376
377   if(!d_fake_usrp)
378     d_urx->start();
379
380   pmt_t rx_handle = pmt_make_any(d_urx);
381
382   d_rx_cs->send(s_cmd_usrp_rx_start_reading, pmt_list2(PMT_NIL, rx_handle));
383
384   return;
385 }
386
387 void
388 usrp_usb_interface::handle_cmd_stop_reading(pmt_t data)
389 {
390   pmt_t invocation_handle = pmt_nth(0, data);
391   
392   if(!d_fake_usrp) {
393     if(verbose)
394       std::cout << "[USRP_USB_INTERFACE] Stopping RX...\n";
395     d_urx->stop();
396   }
397   else {
398     if(verbose)
399       std::cout << "[USRP_USB_INTERFACE] Stopping fake RX...\n";
400     usrp_rx_stop = true;  // extern to communicate with stub to wait
401   }
402
403   return;
404 }
405
406 void
407 usrp_usb_interface::handle_cmd_close(pmt_t data)
408 {
409   pmt_t invocation_handle = pmt_nth(0, data);
410
411   if(d_fake_usrp) {
412     d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
413     return;
414   }
415   
416   if (verbose)
417     std::cout << "[USRP_USB_INTERFACE] Handling close request for USRP\n";
418
419   delete d_utx;
420   d_utx = 0;
421
422   delete d_urx;
423   d_urx = 0;
424
425   d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
426
427   shutdown_all(PMT_T);
428 }
429
430
431 REGISTER_MBLOCK_CLASS(usrp_usb_interface);