3 * Copyright 2007,2008 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
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)
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.
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.
26 #include <usrp_usb_interface.h>
31 #include <mblock/class_registry.h>
32 #include <usrp_inband_usb_packet.h>
33 #include <fpga_regs_common.h>
35 #include <usrp_rx_stub.h>
37 #include "usrp_standard.h"
39 #include <usrp_dbid.h>
41 typedef usrp_inband_usb_packet transport_pkt;
43 #include <symbols_usrp_interface_cs.h>
44 #include <symbols_usrp_tx_cs.h>
45 #include <symbols_usrp_rx_cs.h>
46 static pmt_t s_shutdown = pmt_intern("%shutdown");
48 static const bool verbose = false;
52 * \brief Initializes the USB interface m-block.
54 * The \p user_arg should be a PMT dictionary which can contain optional
55 * arguments for the block, such as the decimatoin and interpolation rate.
57 usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
58 : mb_mblock(rt, instance_name, user_arg),
64 d_rbf("inband_tx_rx.rbf")
66 // Dictionary for arguments to all of the components
67 pmt_t usrp_dict = user_arg;
69 // Default TX/RX interface
70 std::string tx_interface = "usrp_tx";
71 std::string rx_interface = "usrp_rx";
73 if (pmt_is_dict(usrp_dict)) {
75 // The 'fake-usrp' key enables the TX and RX stubs if PMT_T
76 if(pmt_t fake_usrp = pmt_dict_ref(usrp_dict,
77 pmt_intern("fake-usrp"),
79 if(pmt_eqv(fake_usrp, PMT_T)) {
80 tx_interface = "usrp_tx_stub";
81 rx_interface = "usrp_rx_stub";
86 // Read the TX interpolations
87 if(pmt_t interp_tx = pmt_dict_ref(usrp_dict,
88 pmt_intern("interp-tx"),
90 if(!pmt_eqv(interp_tx, PMT_NIL))
91 d_interp_tx = pmt_to_long(interp_tx);
94 // Read the RX decimation rate
95 if(pmt_t decim_rx = pmt_dict_ref(usrp_dict,
96 pmt_intern("decim-rx"),
98 if(!pmt_eqv(decim_rx, PMT_NIL))
99 d_decim_rx = pmt_to_long(decim_rx);
103 if(pmt_t rbf = pmt_dict_ref(usrp_dict,
106 if(!pmt_eqv(rbf, PMT_NIL))
107 d_rbf = pmt_symbol_to_string(rbf);
110 // The RF center frequency
111 if(pmt_t rf_freq = pmt_dict_ref(usrp_dict,
112 pmt_intern("rf-freq"),
114 if(!pmt_eqv(rf_freq, PMT_NIL))
115 d_rf_freq = pmt_to_double(rf_freq);
120 std::cout << "[USRP_USB_INTERFACE] Setting USRP RBF to "
121 << d_rbf << std::endl;
123 std::cout << "[USRP_USB_INTERFACE] Setting TX interpolation to "
124 << d_interp_tx << std::endl;
126 std::cout << "[USRP_USB_INTERFACE] Setting RX interpolation to "
127 << d_decim_rx << std::endl;
129 std::cout << "[USRP_USB_INTERFACE] Using TX interface: "
130 << tx_interface << "\n";
132 std::cout << "[USRP_USB_INTERFACE] Using RX interface: "
133 << rx_interface << "\n";
137 d_cs = define_port("cs", "usrp-interface-cs", true, mb_port::EXTERNAL);
138 d_rx_cs = define_port("rx_cs", "usrp-rx-cs", false, mb_port::INTERNAL);
139 d_tx_cs = define_port("tx_cs", "usrp-tx-cs", false, mb_port::INTERNAL);
141 // Connect to TX and RX
142 define_component("tx", tx_interface, usrp_dict);
143 define_component("rx", rx_interface, usrp_dict);
144 connect("self", "rx_cs", "rx", "cs");
145 connect("self", "tx_cs", "tx", "cs");
147 // FIXME: the code should query the FPGA to retrieve the number of channels and such
152 usrp_usb_interface::~usrp_usb_interface()
158 usrp_usb_interface::initial_transition()
164 * \brief Handles all incoming signals to the block from the lowest m-blocks
165 * which read/write to the bus, or the higher m-block which is the USRP server.
168 usrp_usb_interface::handle_message(mb_message_sptr msg)
170 pmt_t event = msg->signal(); // the "name" of the message
171 pmt_t port_id = msg->port_id(); // which port it came in on
172 pmt_t data = msg->data();
173 pmt_t invocation_handle;
175 if (pmt_eq(event, s_shutdown)) // ignore (for now)
178 //------------- CONTROL / STATUS -------------//
179 if (pmt_eq(port_id, d_cs->port_symbol())) {
181 //------------ OPEN --------------//
182 if (pmt_eq(event, s_cmd_usrp_open)){
183 handle_cmd_open(data);
186 //----------- CLOSE -------------//
187 else if (pmt_eq(event, s_cmd_usrp_close)) {
188 handle_cmd_close(data);
191 //---------- NTX CHAN ----------//
192 else if (pmt_eq(event, s_cmd_usrp_ntx_chan)) {
193 invocation_handle = pmt_nth(0, data);
194 d_cs->send(s_response_usrp_ntx_chan,
195 pmt_list2(invocation_handle,
196 pmt_from_long(d_ntx_chan)));
199 //---------- NRX CHAN ----------//
200 else if (pmt_eq(event, s_cmd_usrp_nrx_chan)) {
201 invocation_handle = pmt_nth(0, data);
202 d_cs->send(s_response_usrp_nrx_chan,
203 pmt_list2(invocation_handle,
204 pmt_from_long(d_nrx_chan)));
207 //------------ WRITE -----------//
208 else if(pmt_eq(event, s_cmd_usrp_write)) {
209 handle_cmd_write(data);
212 //-------- START READING --------//
213 else if(pmt_eq(event, s_cmd_usrp_start_reading)) {
214 handle_cmd_start_reading(data);
217 //-------- STOP READING --------//
218 else if(pmt_eq(event, s_cmd_usrp_stop_reading)) {
219 handle_cmd_stop_reading(data);
226 //---------------- RX ------------------//
227 if (pmt_eq(port_id, d_rx_cs->port_symbol())) {
229 // Relay reads back up
230 if(pmt_eq(event, s_response_usrp_rx_read)) {
231 d_cs->send(s_response_usrp_read, data);
238 //---------------- TX ------------------//
239 if (pmt_eq(port_id, d_tx_cs->port_symbol())) {
241 if(pmt_eq(event, s_response_usrp_tx_write)) {
243 pmt_t invocation_handle = pmt_nth(0, data);
244 pmt_t status = pmt_nth(1, data);
245 pmt_t channel = pmt_nth(2, data);
247 d_cs->send(s_response_usrp_write,
248 pmt_list3(invocation_handle,
259 std::cout << "[USRP_USB_INTERFACE] unhandled msg: " << msg << std::endl;
263 * \brief Called by the handle_message() method when the incoming signal is to
264 * open a USB connection to the USRP (cmd-usrp-open).
266 * The \p data parameter is a PMT list, where the elements are an invocation
267 * handle and the USRP number.
270 usrp_usb_interface::handle_cmd_open(pmt_t data)
272 pmt_t invocation_handle = pmt_nth(0, data);
273 long which_usrp = pmt_to_long(pmt_nth(1, data));
277 d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
282 std::cout << "[USRP_USB_INTERFACE] Handling open request for USRP " << which_usrp << "\n";
284 // Open up a standard RX and TX for communication with the USRP
286 d_utx = usrp_standard_tx::make(which_usrp,
290 4096, // USB block size
291 16, // nblocks for async transfers
297 std::cout << "[USRP_USB_INTERFACE] Failed to open TX\n";
298 reply_data = pmt_list2(invocation_handle, PMT_F);
299 d_cs->send(s_response_usrp_open, reply_data);
303 // Perform TX daughterboard tuning
311 // Cast to usrp_basic and then detect daughterboards
313 usrp_subdev_spec tspec = pick_tx_subdevice();
314 db_base_sptr tsubdev = d_ub_tx->selected_subdev(tspec);
316 // Set the TX mux value
317 mux = d_utx->determine_tx_mux_value(tspec);
320 // Set the TX gain and determine rate
321 tgain = tsubdev->gain_max();
322 tsubdev->set_gain(tgain);
323 input_rate = d_ub_tx->converter_rate() / d_utx->interp_rate();
325 // Perform the actual tuning, if no frequency specified then pick
327 target_freq = tsubdev->freq_min()+((tsubdev->freq_max()-tsubdev->freq_min())/2.0);
329 target_freq = d_rf_freq;
330 ok = d_utx->tune(tsubdev->which(), tsubdev, target_freq, &r);
331 tsubdev->set_enable(true);
334 printf("TX Subdevice name is %s\n", tsubdev->name().c_str());
335 printf("TX Subdevice freq range: (%g, %g)\n",
336 tsubdev->freq_min(), tsubdev->freq_max());
337 printf("mux: %#08x\n", mux);
338 printf("target_freq: %f\n", target_freq);
339 printf("ok: %s\n", ok ? "true" : "false");
340 printf("r.baseband_freq: %f\n", r.baseband_freq);
341 printf("r.dxc_freq: %f\n", r.dxc_freq);
342 printf("r.residual_freq: %f\n", r.residual_freq);
343 printf("r.inverted: %d\n", r.inverted);
347 std::cerr << "[USRP_USB_INTERFACE] Failed to set center frequency on TX\n";
348 reply_data = pmt_list2(invocation_handle, PMT_F);
349 d_cs->send(s_response_usrp_open, reply_data);
356 std::cout << "[USRP_USB_INTERFACE] Setup TX channel\n";
359 usrp_standard_rx::make (which_usrp,
363 0, // set blank mode to start
364 4096, // USB block size
365 16, // number of blocks for async transfers
370 std::cout << "[usrp_server] Failed to open RX\n";
371 reply_data = pmt_list2(invocation_handle, PMT_F);
372 d_cs->send(s_response_usrp_open, reply_data);
376 // Cast to usrp_basic and then detect daughterboards
378 usrp_subdev_spec rspec = pick_rx_subdevice();
379 db_base_sptr rsubdev = d_ub_rx->selected_subdev(rspec);
381 // Set the RX mux value
382 mux = d_urx->determine_rx_mux_value(rspec);
385 // Set the TX gain and determine rate
386 rgain = rsubdev->gain_max();
387 rsubdev->set_gain(rgain);
388 input_rate = d_ub_rx->converter_rate() / d_urx->decim_rate();
390 ok = d_urx->tune(rsubdev->which(), rsubdev, target_freq, &r);
391 rsubdev->set_enable(true);
394 printf("RX Subdevice name is %s\n", rsubdev->name().c_str());
395 printf("RX Subdevice freq range: (%g, %g)\n",
396 rsubdev->freq_min(), rsubdev->freq_max());
397 printf("mux: %#08x\n", mux);
398 printf("target_freq: %f\n", target_freq);
399 printf("ok: %s\n", ok ? "true" : "false");
400 printf("r.baseband_freq: %f\n", r.baseband_freq);
401 printf("r.dxc_freq: %f\n", r.dxc_freq);
402 printf("r.residual_freq: %f\n", r.residual_freq);
403 printf("r.inverted: %d\n", r.inverted);
407 std::cerr << "[USRP_USB_INTERFACE] Failed to set center frequency on RX\n";
408 reply_data = pmt_list2(invocation_handle, PMT_F);
409 d_cs->send(s_response_usrp_open, reply_data);
414 std::cout << "[USRP_USB_INTERFACE] Setup RX channel\n";
416 // d_utx->_write_fpga_reg(FR_DEBUG_EN,0xf);
417 // d_utx->_write_oe(0, 0xffff, 0xffff);
418 // d_urx->_write_oe(0, 0xffff, 0xffff);
419 // d_utx->_write_oe(1, 0xffff, 0xffff);
420 // d_urx->_write_oe(1, 0xffff, 0xffff);
422 d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
426 * \brief Called by the handle_message() method when the incoming signal is to
427 * write data to the USB bus (cmd-usrp-write).
429 * The \p data parameter is a PMT list containing 3 mandatory elements in the
430 * following order: an invocation handle, channel, and a uniform vector
431 * representation of the packets.
434 usrp_usb_interface::handle_cmd_write(pmt_t data)
436 pmt_t invocation_handle = pmt_nth(0, data);
437 pmt_t channel = pmt_nth(1, data);
438 pmt_t pkts = pmt_nth(2, data);
440 pmt_t tx_handle = pmt_make_any(d_utx);
442 d_tx_cs->send(s_cmd_usrp_tx_write,
443 pmt_list4(invocation_handle,
450 * \brief Called by the handle_message() method when the incoming signal is to
451 * start reading data from the USB bus (cmd-usrp-start-reading).
453 * The \p data parameter is a PMT list with a single element: an invocation
454 * handle which can be returned with the response.
457 usrp_usb_interface::handle_cmd_start_reading(pmt_t data)
459 pmt_t invocation_handle = pmt_nth(0, data);
462 std::cout << "[USRP_USB_INTERFACE] Starting RX...\n";
467 pmt_t rx_handle = pmt_make_any(d_urx);
469 d_rx_cs->send(s_cmd_usrp_rx_start_reading, pmt_list2(PMT_NIL, rx_handle));
477 * \brief Called by the handle_message() method when the incoming signal is to
478 * stop reading data from the USB bus (cmd-usrp-stop-reading).
480 * The \p data parameter is a PMT list with a single element: an invocation
481 * handle which can be returned with the response.
484 usrp_usb_interface::handle_cmd_stop_reading(pmt_t data)
486 pmt_t invocation_handle = pmt_nth(0, data);
490 std::cout << "[USRP_USB_INTERFACE] Stopping RX...\n";
493 // Used to allow a read() being called by a lower layer to complete before
494 // stopping, else there can be partial data left on the bus and can generate
496 while(usrp_rx_stop) {usleep(1);}
501 std::cout << "[USRP_USB_INTERFACE] Stopping fake RX...\n";
502 usrp_rx_stop_stub = true; // extern to communicate with stub to wait
505 d_rx_reading = false;
511 * \brief Called by the handle_message() method when the incoming signal is to
512 * close the USB connection to the USRP.
514 * The \p data parameter is a PMT list with a single element: an invocation
515 * handle which can be returned with the response.
518 usrp_usb_interface::handle_cmd_close(pmt_t data)
520 pmt_t invocation_handle = pmt_nth(0, data);
523 handle_cmd_stop_reading(PMT_NIL);
526 d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
531 std::cout << "[USRP_USB_INTERFACE] Handling close request for USRP\n";
536 d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
538 // FIXME This seems like a _very_ strange place to be calling shutdown_all.
539 // That decision should be left to high-level code, not low-level code like this.
544 usrp_usb_interface::pick_rx_subdevice()
547 USRP_DBID_FLEX_400_RX,
548 USRP_DBID_FLEX_900_RX,
549 USRP_DBID_FLEX_1200_RX,
550 USRP_DBID_FLEX_2400_RX,
552 USRP_DBID_TV_RX_REV_2,
554 USRP_DBID_DBS_RX_REV_2_1,
558 std::vector<int> candidates(dbids, dbids+(sizeof(dbids)/sizeof(int)));
559 return pick_subdev(d_ub_rx, candidates);
563 usrp_usb_interface::pick_tx_subdevice()
566 USRP_DBID_FLEX_400_TX,
567 USRP_DBID_FLEX_900_TX,
568 USRP_DBID_FLEX_1200_TX,
569 USRP_DBID_FLEX_2400_TX,
573 std::vector<int> candidates(dbids, dbids+(sizeof(dbids)/sizeof(int)));
574 return pick_subdev(d_ub_tx, candidates);
578 usrp_usb_interface::pick_subdev(boost::shared_ptr<usrp_basic> d_usrp_basic, std::vector<int> candidates)
580 int dbid0 = d_usrp_basic->selected_subdev(usrp_subdev_spec(0, 0))->dbid();
581 int dbid1 = d_usrp_basic->selected_subdev(usrp_subdev_spec(1, 0))->dbid();
583 for (int i = 0; i < candidates.size(); i++) {
584 int dbid = candidates[i];
586 return usrp_subdev_spec(0, 0);
588 return usrp_subdev_spec(1, 0);
592 return usrp_subdev_spec(0, 0);
594 return usrp_subdev_spec(1, 0);
596 throw std::runtime_error("No suitable daughterboard found!");
600 REGISTER_MBLOCK_CLASS(usrp_usb_interface);