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"
40 typedef usrp_inband_usb_packet transport_pkt;
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");
47 static const bool verbose = false;
51 * \brief Initializes the USB interface m-block.
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.
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),
63 d_rbf("inband_tx_rx.rbf")
65 // Dictionary for arguments to all of the components
66 pmt_t usrp_dict = user_arg;
68 // Default TX/RX interface
69 std::string tx_interface = "usrp_tx";
70 std::string rx_interface = "usrp_rx";
72 if (pmt_is_dict(usrp_dict)) {
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"),
78 if(pmt_eqv(fake_usrp, PMT_T)) {
79 tx_interface = "usrp_tx_stub";
80 rx_interface = "usrp_rx_stub";
85 // Read the TX interpolations
86 if(pmt_t interp_tx = pmt_dict_ref(usrp_dict,
87 pmt_intern("interp-tx"),
89 if(!pmt_eqv(interp_tx, PMT_NIL))
90 d_interp_tx = pmt_to_long(interp_tx);
93 // Read the RX decimation rate
94 if(pmt_t decim_rx = pmt_dict_ref(usrp_dict,
95 pmt_intern("decim-rx"),
97 if(!pmt_eqv(decim_rx, PMT_NIL))
98 d_decim_rx = pmt_to_long(decim_rx);
102 if(pmt_t rbf = pmt_dict_ref(usrp_dict,
105 if(!pmt_eqv(rbf, PMT_NIL))
106 d_rbf = pmt_symbol_to_string(rbf);
109 // The RF center frequency
110 if(pmt_t rf_freq = pmt_dict_ref(usrp_dict,
111 pmt_intern("rf-freq"),
113 if(!pmt_eqv(rf_freq, PMT_NIL))
114 d_rf_freq = pmt_to_long(rf_freq);
119 std::cout << "[USRP_USB_INTERFACE] Setting USRP RBF to "
120 << d_rbf << std::endl;
122 std::cout << "[USRP_USB_INTERFACE] Setting TX interpolation to "
123 << d_interp_tx << std::endl;
125 std::cout << "[USRP_USB_INTERFACE] Setting RX interpolation to "
126 << d_decim_rx << std::endl;
128 std::cout << "[USRP_USB_INTERFACE] Using TX interface: "
129 << tx_interface << "\n";
131 std::cout << "[USRP_USB_INTERFACE] Using RX interface: "
132 << rx_interface << "\n";
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);
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");
146 // FIXME: the code should query the FPGA to retrieve the number of channels and such
151 usrp_usb_interface::~usrp_usb_interface()
157 usrp_usb_interface::initial_transition()
163 * \brief Handles all incoming signals to the block from the lowest m-blocks
164 * which read/write to the bus, or the higher m-block which is the USRP server.
167 usrp_usb_interface::handle_message(mb_message_sptr msg)
169 pmt_t event = msg->signal(); // the "name" of the message
170 pmt_t port_id = msg->port_id(); // which port it came in on
171 pmt_t data = msg->data();
172 pmt_t invocation_handle;
174 if (pmt_eq(event, s_shutdown)) // ignore (for now)
177 //------------- CONTROL / STATUS -------------//
178 if (pmt_eq(port_id, d_cs->port_symbol())) {
180 //------------ OPEN --------------//
181 if (pmt_eq(event, s_cmd_usrp_open)){
182 handle_cmd_open(data);
185 //----------- CLOSE -------------//
186 else if (pmt_eq(event, s_cmd_usrp_close)) {
187 handle_cmd_close(data);
190 //---------- NTX CHAN ----------//
191 else if (pmt_eq(event, s_cmd_usrp_ntx_chan)) {
192 invocation_handle = pmt_nth(0, data);
193 d_cs->send(s_response_usrp_ntx_chan,
194 pmt_list2(invocation_handle,
195 pmt_from_long(d_ntx_chan)));
198 //---------- NRX CHAN ----------//
199 else if (pmt_eq(event, s_cmd_usrp_nrx_chan)) {
200 invocation_handle = pmt_nth(0, data);
201 d_cs->send(s_response_usrp_nrx_chan,
202 pmt_list2(invocation_handle,
203 pmt_from_long(d_nrx_chan)));
206 //------------ WRITE -----------//
207 else if(pmt_eq(event, s_cmd_usrp_write)) {
208 handle_cmd_write(data);
211 //-------- START READING --------//
212 else if(pmt_eq(event, s_cmd_usrp_start_reading)) {
213 handle_cmd_start_reading(data);
216 //-------- STOP READING --------//
217 else if(pmt_eq(event, s_cmd_usrp_stop_reading)) {
218 handle_cmd_stop_reading(data);
225 //---------------- RX ------------------//
226 if (pmt_eq(port_id, d_rx_cs->port_symbol())) {
228 // Relay reads back up
229 if(pmt_eq(event, s_response_usrp_rx_read)) {
230 d_cs->send(s_response_usrp_read, data);
237 //---------------- TX ------------------//
238 if (pmt_eq(port_id, d_tx_cs->port_symbol())) {
240 if(pmt_eq(event, s_response_usrp_tx_write)) {
242 pmt_t invocation_handle = pmt_nth(0, data);
243 pmt_t status = pmt_nth(1, data);
244 pmt_t channel = pmt_nth(2, data);
246 d_cs->send(s_response_usrp_write,
247 pmt_list3(invocation_handle,
258 std::cout << "[USRP_USB_INTERFACE] unhandled msg: " << msg << std::endl;
262 * \brief Called by the handle_message() method when the incoming signal is to
263 * open a USB connection to the USRP (cmd-usrp-open).
265 * The \p data parameter is a PMT list, where the elements are an invocation
266 * handle and the USRP number.
269 usrp_usb_interface::handle_cmd_open(pmt_t data)
271 pmt_t invocation_handle = pmt_nth(0, data);
272 long which_usrp = pmt_to_long(pmt_nth(1, data));
276 d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
281 std::cout << "[USRP_USB_INTERFACE] Handling open request for USRP " << which_usrp << "\n";
283 // Open up a standard RX and TX for communication with the USRP
285 d_utx = usrp_standard_tx::make(which_usrp,
289 4096, // USB block size
290 16, // nblocks for async transfers
296 std::cout << "[USRP_USB_INTERFACE] Failed to open TX\n";
297 reply_data = pmt_list2(invocation_handle, PMT_F);
298 d_cs->send(s_response_usrp_open, reply_data);
302 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
304 std::cout << "[USRP_USB_INTERFACE] Failed to set center frequency on TX\n";
305 reply_data = pmt_list2(invocation_handle, PMT_F);
306 d_cs->send(s_response_usrp_open, reply_data);
310 if(!d_utx->set_mux(0xBA98)) {
312 std::cout << "[USRP_USB_INTERFACE] Failed to set TX mux\n";
313 reply_data = pmt_list2(invocation_handle, PMT_F);
314 d_cs->send(s_response_usrp_open, reply_data);
321 std::cout << "[USRP_USB_INTERFACE] Setup TX channel\n";
324 usrp_standard_rx::make (which_usrp,
328 0, // set blank mode to start
329 4096, // USB block size
330 16, // number of blocks for async transfers
335 std::cout << "[usrp_server] Failed to open RX\n";
336 reply_data = pmt_list2(invocation_handle, PMT_F);
337 d_cs->send(s_response_usrp_open, reply_data);
341 if(!d_urx->set_rx_freq (0, -d_rf_freq) || !d_urx->set_rx_freq(1, -d_rf_freq)) {
343 std::cout << "[usrp_server] Failed to set center frequency on RX\n";
344 reply_data = pmt_list2(invocation_handle, PMT_F);
345 d_cs->send(s_response_usrp_open, reply_data);
349 // Two channels ... this really needs to end up being set correctly by
350 // querying for what dboards are connected
351 if(!d_urx->set_mux(0x32103210)) {
353 std::cout << "[USRP_USB_INTERFACE] Failed to set RX mux\n";
354 reply_data = pmt_list2(invocation_handle, PMT_F);
355 d_cs->send(s_response_usrp_open, reply_data);
360 std::cout << "[USRP_USB_INTERFACE] Setup RX channel\n";
362 // d_utx->_write_fpga_reg(FR_DEBUG_EN,0xf);
363 // d_utx->_write_oe(0, 0xffff, 0xffff);
364 // d_urx->_write_oe(0, 0xffff, 0xffff);
365 // d_utx->_write_oe(1, 0xffff, 0xffff);
366 // d_urx->_write_oe(1, 0xffff, 0xffff);
368 d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T));
372 * \brief Called by the handle_message() method when the incoming signal is to
373 * write data to the USB bus (cmd-usrp-write).
375 * The \p data parameter is a PMT list containing 3 mandatory elements in the
376 * following order: an invocation handle, channel, and a uniform vector
377 * representation of the packets.
380 usrp_usb_interface::handle_cmd_write(pmt_t data)
382 pmt_t invocation_handle = pmt_nth(0, data);
383 pmt_t channel = pmt_nth(1, data);
384 pmt_t pkts = pmt_nth(2, data);
386 pmt_t tx_handle = pmt_make_any(d_utx);
388 d_tx_cs->send(s_cmd_usrp_tx_write,
389 pmt_list4(invocation_handle,
396 * \brief Called by the handle_message() method when the incoming signal is to
397 * start reading data from the USB bus (cmd-usrp-start-reading).
399 * The \p data parameter is a PMT list with a single element: an invocation
400 * handle which can be returned with the response.
403 usrp_usb_interface::handle_cmd_start_reading(pmt_t data)
405 pmt_t invocation_handle = pmt_nth(0, data);
408 std::cout << "[USRP_USB_INTERFACE] Starting RX...\n";
413 pmt_t rx_handle = pmt_make_any(d_urx);
415 d_rx_cs->send(s_cmd_usrp_rx_start_reading, pmt_list2(PMT_NIL, rx_handle));
423 * \brief Called by the handle_message() method when the incoming signal is to
424 * stop reading data from the USB bus (cmd-usrp-stop-reading).
426 * The \p data parameter is a PMT list with a single element: an invocation
427 * handle which can be returned with the response.
430 usrp_usb_interface::handle_cmd_stop_reading(pmt_t data)
432 pmt_t invocation_handle = pmt_nth(0, data);
436 std::cout << "[USRP_USB_INTERFACE] Stopping RX...\n";
439 // Used to allow a read() being called by a lower layer to complete before
440 // stopping, else there can be partial data left on the bus and can generate
442 while(usrp_rx_stop) {usleep(1);}
447 std::cout << "[USRP_USB_INTERFACE] Stopping fake RX...\n";
448 usrp_rx_stop_stub = true; // extern to communicate with stub to wait
451 d_rx_reading = false;
457 * \brief Called by the handle_message() method when the incoming signal is to
458 * close the USB connection to the USRP.
460 * The \p data parameter is a PMT list with a single element: an invocation
461 * handle which can be returned with the response.
464 usrp_usb_interface::handle_cmd_close(pmt_t data)
466 pmt_t invocation_handle = pmt_nth(0, data);
469 handle_cmd_stop_reading(PMT_NIL);
472 d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
477 std::cout << "[USRP_USB_INTERFACE] Handling close request for USRP\n";
482 d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T));
484 // FIXME This seems like a _very_ strange place to be calling shutdown_all.
485 // That decision should be left to high-level code, not low-level code like this.
490 REGISTER_MBLOCK_CLASS(usrp_usb_interface);