diff options
Diffstat (limited to 'usrp/host')
34 files changed, 1680 insertions, 2280 deletions
diff --git a/usrp/host/apps-inband/Makefile.am b/usrp/host/apps-inband/Makefile.am index 86bb40618..f231b57f7 100644 --- a/usrp/host/apps-inband/Makefile.am +++ b/usrp/host/apps-inband/Makefile.am @@ -30,46 +30,31 @@ AM_CPPFLAGS = \ bin_PROGRAMS = noinst_PROGRAMS = \ - test_usrp_inband_cs \ test_usrp_inband_ping \ test_usrp_inband_registers \ test_usrp_inband_rx \ + test_usrp_inband_2rx \ test_usrp_inband_tx \ + test_usrp_inband_2tx \ test_usrp_inband_timestamps \ test_usrp_inband_overrun \ test_usrp_inband_underrun \ - test_gmac_tx \ read_packets noinst_HEADERS = \ ui_nco.h \ - ui_sincos.h \ - gmac.h \ - gmac_symbols.h + ui_sincos.h -EXTRA_DIST = \ - gmac.mbh - -#------------------------------------------------------------------ -# Build gmac sources - -BUILT_SOURCES = \ - gmac_mbh.cc - -gmac_mbh.cc : gmac.mbh - $(COMPILE_MBH) $(srcdir)/gmac.mbh gmac_mbh.cc - - -test_usrp_inband_cs_SOURCES = test_usrp_inband_cs.cc ui_sincos.c -test_usrp_inband_cs_LDADD = $(USRP_LA) $(USRP_INBAND_LA) - test_usrp_inband_ping_SOURCES = test_usrp_inband_ping.cc test_usrp_inband_ping_LDADD = $(USRP_LA) $(USRP_INBAND_LA) test_usrp_inband_tx_SOURCES = test_usrp_inband_tx.cc ui_sincos.c test_usrp_inband_tx_LDADD = $(USRP_LA) $(USRP_INBAND_LA) +test_usrp_inband_2tx_SOURCES = test_usrp_inband_2tx.cc ui_sincos.c +test_usrp_inband_2tx_LDADD = $(USRP_LA) $(USRP_INBAND_LA) + test_usrp_inband_timestamps_SOURCES = test_usrp_inband_timestamps.cc ui_sincos.c test_usrp_inband_timestamps_LDADD = $(USRP_LA) $(USRP_INBAND_LA) @@ -85,8 +70,8 @@ test_usrp_inband_underrun_LDADD = $(USRP_LA) $(USRP_INBAND_LA) test_usrp_inband_rx_SOURCES = test_usrp_inband_rx.cc ui_sincos.c test_usrp_inband_rx_LDADD = $(USRP_LA) $(USRP_INBAND_LA) -test_gmac_tx_SOURCES = test_gmac_tx.cc gmac.cc gmac_mbh.cc ui_sincos.c -test_gmac_tx_LDADD = $(USRP_LA) $(USRP_INBAND_LA) +test_usrp_inband_2rx_SOURCES = test_usrp_inband_2rx.cc ui_sincos.c +test_usrp_inband_2rx_LDADD = $(USRP_LA) $(USRP_INBAND_LA) read_packets_SOURCES = read_packets.cc read_packets_LDADD = $(USRP_LA) $(USRP_INBAND_LA) diff --git a/usrp/host/apps-inband/gmac.cc b/usrp/host/apps-inband/gmac.cc deleted file mode 100644 index 107582e12..000000000 --- a/usrp/host/apps-inband/gmac.cc +++ /dev/null @@ -1,690 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <gmac.h> - -#include <mb_mblock.h> -#include <mb_runtime.h> -#include <mb_protocol_class.h> -#include <mb_exception.h> -#include <mb_msg_queue.h> -#include <mb_message.h> -#include <mb_msg_accepter.h> -#include <mb_class_registry.h> -#include <pmt.h> -#include <stdio.h> -#include <string.h> -#include <iostream> -#include <ui_nco.h> - -#include <symbols_usrp_server_cs.h> -#include <symbols_usrp_channel.h> -#include <symbols_usrp_low_level_cs.h> -#include <symbols_usrp_tx.h> -#include <symbols_usrp_rx.h> - -#include <gmac_symbols.h> - -static bool verbose = true; - -gmac::gmac(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg) - : mb_mblock(rt, instance_name, user_arg), - d_us_rx_chan(PMT_NIL), d_us_tx_chan(PMT_NIL) -{ - - // When the MAC layer is initialized, we must connect to the USRP and setup - // channels. We begin by defining ports to connect to the 'usrp_server' block - // and then initialize the USRP by opening it through the 'usrp_server.' - - // Initialize the ports - define_ports(); - - // Initialize the connection to the USRP - initialize_usrp(); - -} - -gmac::~gmac() -{ -} - -// The full functionality of GMAC is based on messages passed back and forth -// between the application and a physical layer and/or usrp_server. Each -// message triggers additional events, states, and messages to be sent. -void gmac::handle_message(mb_message_sptr msg) -{ - - // The MAC functionality is dispatched based on the event, which is the - // driving force of the MAC. The event can be anything from incoming samples - // to a message to change the carrier sense threshold. - pmt_t event = msg->signal(); - pmt_t data = msg->data(); - pmt_t port_id = msg->port_id(); - - pmt_t handle = PMT_F; - pmt_t status = PMT_F; - pmt_t dict = PMT_NIL; - std::string error_msg; - - switch(d_state) { - - //---------------------------- INIT ------------------------------------// - // In the INIT state, there should be no messages across the ports. - case INIT: - error_msg = "no messages should be passed during the INIT state:"; - goto unhandled; - - //-------------------------- OPENING USRP -------------------------------// - // In this state we expect a response from usrp_server over the CS channel - // as to whether or not the opening of the USRP was successful. If so, we - // switch states to allocating the channels for use. - case OPENING_USRP: - - if(pmt_eq(event, s_response_open) - && pmt_eq(d_us_cs->port_symbol(), port_id)) { - - status = pmt_nth(1, data); // PMT_T or PMT_F - - if(pmt_eq(status, PMT_T)) { // on success, allocate channels! - allocate_channels(); - return; - } - else { - error_msg = "failed to open usrp:"; - goto bail; - } - - } - - goto unhandled; // all other messages not handled in this state - - //------------------------ ALLOCATING CHANNELS --------------------------// - // When allocating channels, we need to wait for 2 responses from USRP - // server: one for TX and one for RX. Both are initialized to NIL so we - // know to continue to the next state once both are set. - case ALLOCATING_CHANNELS: - - // ************* TX ALLOCATION RESPONSE ***************** // - if(pmt_eq(event, s_response_allocate_channel) - && pmt_eq(d_us_tx->port_symbol(), port_id)) - { - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { // extract channel on success - d_us_tx_chan = pmt_nth(2, data); - - if(verbose) - std::cout << "[GMAC] Received TX allocation" - << " on channel " << d_us_tx_chan << std::endl; - - // If the RX has also been allocated already, we can continue - if(!pmt_eqv(d_us_rx_chan, PMT_NIL)) { - //enter_receiving(); - initialize_gmac(); - } - - return; - } - else { // TX allocation failed - error_msg = "failed to allocate TX channel:"; - goto bail; - } - } - - // ************* RX ALLOCATION RESPONSE ****************// - if(pmt_eq(event, s_response_allocate_channel) - && pmt_eq(d_us_rx->port_symbol(), port_id)) - { - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { - - d_us_rx_chan = pmt_nth(2, data); - - if(verbose) - std::cout << "[GMAC] Received RX allocation" - << " on channel " << d_us_rx_chan << std::endl; - - // If the TX has also been allocated already, we can continue - if(!pmt_eqv(d_us_tx_chan, PMT_NIL)) { - //enter_receiving(); - initialize_gmac(); - } - - return; - } - else { // RX allocation failed - error_msg = "failed to allocate RX channel:"; - goto bail; - } - } - - goto unhandled; - - //----------------------------- INIT GMAC --------------------------------// - // In the INIT_GMAC state, now that the USRP is initialized we can do things - // like right the carrier sense threshold to the FPGA register. - case INIT_GMAC: - goto unhandled; - - - //----------------------------- IDLE ------------------------------------// - // In the idle state the MAC is not quite 'idle', it is just not doing - // anything specific. It is still being passive with data between the - // application and the lower layer. - case IDLE: - - //-------- TX PORT ----------------------------------------------------// - if(pmt_eq(d_tx->port_symbol(), port_id)) { - - //-------- INCOMING PACKET ------------------------------------------// - if(pmt_eq(event, s_cmd_tx_pkt)) { - handle_cmd_tx_pkt(data); - return; - } - - } - - //--------- USRP TX PORT ----------------------------------------------// - if(pmt_eq(d_us_tx->port_symbol(), port_id)) { - - //-------- INCOMING PACKET RESPONSE ---------------------------------// - if(pmt_eq(event, s_response_xmit_raw_frame)) { - handle_response_xmit_raw_frame(data); - return; - } - - } - - //--------- CS PORT ---------------------------------------------------// - if(pmt_eq(d_cs->port_symbol(), port_id)) { - - //------- ENABLE CARRIER SENSE --------------------------------------// - if(pmt_eq(event, s_cmd_carrier_sense_enable)) { - handle_cmd_carrier_sense_enable(data); - return; - } - - //------- CARRIER SENSE THRESHOLD -----------------------------------// - if(pmt_eq(event, s_cmd_carrier_sense_threshold)) { - handle_cmd_carrier_sense_threshold(data); - return; - } - - //------- CARRIER SENSE DEADLINE ------------------------------------// - if(pmt_eq(event, s_cmd_carrier_sense_deadline)) { - handle_cmd_carrier_sense_deadline(data); - return; - } - - //------- DISABLE CARRIER SENSE -------------------------------------// - if(pmt_eq(event, s_cmd_carrier_sense_disable)) { - handle_cmd_carrier_sense_disable(data); - return; - } - - } - - goto unhandled; - - //------------------------ CLOSING CHANNELS -----------------------------// - case CLOSING_CHANNELS: - - if (pmt_eq(event, s_response_deallocate_channel) - && pmt_eq(d_us_tx->port_symbol(), port_id)) - { - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { - d_us_tx_chan = PMT_NIL; - - if(verbose) - std::cout << "[GMAC] Received TX deallocation\n"; - - // If the RX is also deallocated, we can close the USRP - if(pmt_eq(d_us_rx_chan, PMT_NIL)) - close_usrp(); - - return; - - } else { - - error_msg = "failed to deallocate TX channel:"; - goto bail; - - } - } - - if (pmt_eq(event, s_response_deallocate_channel) - && pmt_eq(d_us_rx->port_symbol(), port_id)) - { - status = pmt_nth(1, data); - - // If successful, set the port to NIL - if(pmt_eq(status, PMT_T)) { - d_us_rx_chan = PMT_NIL; - - if(verbose) - std::cout << "[GMAC] Received RX deallocation\n"; - - // If the TX is also deallocated, we can close the USRP - if(pmt_eq(d_us_tx_chan, PMT_NIL)) - close_usrp(); - - return; - - } else { - - error_msg = "failed to deallocate RX channel:"; - goto bail; - - } - } - - goto unhandled; - - //-------------------------- CLOSING USRP -------------------------------// - case CLOSING_USRP: - goto unhandled; - - } - - // An error occured, print it, and shutdown all m-blocks - bail: - std::cerr << error_msg << data - << "status = " << status << std::endl; - shutdown_all(PMT_F); - return; - - // Received an unhandled message for a specific state - unhandled: - if(0 && verbose && !pmt_eq(event, pmt_intern("%shutdown"))) - std::cout << "[GMAC] unhandled msg: " << msg - << "in state "<< d_state << std::endl; -} - -// The MAC layer connects to 'usrp_server' which has a control/status channel, -// a TX, and an RX port. The MAC layer can then relay TX/RX data back and -// forth to the application, or a physical layer once available. -void gmac::define_ports() -{ - // Ports we use to connect to usrp_server - d_us_tx = define_port("us-tx0", "usrp-tx", false, mb_port::INTERNAL); - d_us_rx = define_port("us-rx0", "usrp-rx", false, mb_port::INTERNAL); - d_us_cs = define_port("us-cs", "usrp-server-cs", false, mb_port::INTERNAL); - - // Ports applications used to connect to us - d_tx = define_port("tx0", "gmac-tx", true, mb_port::EXTERNAL); - d_rx = define_port("rx0", "gmac-rx", true, mb_port::EXTERNAL); - d_cs = define_port("cs", "gmac-cs", true, mb_port::EXTERNAL); -} - -// To initialize the USRP we must pass several parameters to 'usrp_server' such -// as the RBF to use, and the interpolation/decimation rate. The MAC layer will -// then pass these parameters to the block with a message to establish the -// connection to the USRP. -void gmac::initialize_usrp() -{ - - if(verbose) - std::cout << "[GMAC] Initializing USRP\n"; - - // The initialization parameters are passed to usrp_server via a PMT - // dictionary. - pmt_t usrp_dict = pmt_make_dict(); - - // Specify the RBF to use - pmt_dict_set(usrp_dict, - pmt_intern("rbf"), - pmt_intern("test2.rbf")); - - pmt_dict_set(usrp_dict, - pmt_intern("interp-tx"), - pmt_from_long(128)); - - pmt_dict_set(usrp_dict, - pmt_intern("decim-rx"), - pmt_from_long(16)); - - // Center frequency - pmt_dict_set(usrp_dict, - pmt_intern("rf-freq"), - pmt_from_long((long)10e6)); - - // Default is to use USRP considered '0' (incase of multiple) - d_which_usrp = pmt_from_long(0); - - define_component("USRP-SERVER", "usrp_server", usrp_dict); - - connect("self", "us-tx0", "USRP-SERVER", "tx0"); - connect("self", "us-rx0", "USRP-SERVER", "rx0"); - connect("self", "us-cs", "USRP-SERVER", "cs"); - - // Finally, enter the OPENING_USRP state by sending a request to open the - // USRP. - open_usrp(); - -} - -// In the initialization state of the MAC layer we set default values for -// several functionalities. -void gmac::initialize_gmac() -{ - - // The initial state is the INIT state. - d_state = INIT_GMAC; - - // Set carrier sense to enabled by default with the specified threshold and - // the deadline to 0 -- which is wait forever. - set_carrier_sense(true, 25, 0, PMT_NIL); - - // Can now notify the application that we are initialized - d_cs->send(s_response_gmac_initialized, - pmt_list2(PMT_NIL, PMT_T)); - - // The MAC enters an IDLE state where it waits for messages and dispatches - // based on them - enter_idle(); -} - -// Method for setting the carrier sense and an associated threshold which is -// written to a register on the FPGA, which it will read if the CS flag is set -// and perform carrier sense based on. -// -// We currently do not wait for the successful response for the write to -// register command, we assume it will succeed else the MAC must -void gmac::set_carrier_sense(bool toggle, long threshold, long deadline, pmt_t invocation) -{ - d_carrier_sense = toggle; - - // Only waste the bandwidth and processing of a C/S packet if needed - if(threshold != d_cs_thresh) { - d_us_tx->send(s_cmd_to_control_channel, // C/S packet - pmt_list2(invocation, // invoc handle - pmt_list1( - pmt_list2(s_op_write_reg, - pmt_list2( - pmt_from_long(REG_CS_THRESH), - pmt_from_long(threshold)))))); - d_cs_thresh = threshold; - - if(verbose) - std::cout << "[GMAC] Changing CS threshold: " << d_cs_thresh << std::endl; - } - - if(deadline != d_cs_deadline) { - d_us_tx->send(s_cmd_to_control_channel, // C/S packet - pmt_list2(invocation, // invoc handle - pmt_list1( - pmt_list2(s_op_write_reg, - pmt_list2( - pmt_from_long(REG_CS_DEADLINE), - pmt_from_long(deadline)))))); - d_cs_deadline = deadline; - - if(verbose) - std::cout << "[GMAC] Changing CS deadline: " << d_cs_deadline << std::endl; - } - - if(verbose) - std::cout << "[GMAC] Setting carrier sense to " << toggle << std::endl; -} - -// The following sends a command to open the USRP, which will upload the -// specified RBF when creating the instance of the USRP server and set all other -// relevant parameters. -void gmac::open_usrp() -{ - d_state = OPENING_USRP; - - d_us_cs->send(s_cmd_open, pmt_list2(PMT_NIL, d_which_usrp)); - - if(verbose) - std::cout << "[GMAC] Opening USRP " - << d_which_usrp << std::endl; -} - -// Before sending the close to the USRP we wait a couple seconds to let any data -// through the USB exit, else a bug in the driver will kick an error and cause -// an abnormal termination. -void gmac::close_usrp() -{ - d_state = CLOSING_USRP; - - sleep(2); - - d_us_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); -} - -// RX and TX channels must be allocated so that the USRP server can -// properly share bandwidth across multiple USRPs. No commands will be -// successful to the USRP through the USRP server on the TX or RX channels until -// a bandwidth allocation has been received. -void gmac::allocate_channels() -{ - d_state = ALLOCATING_CHANNELS; - - if(verbose) - std::cout << "[GMAC] Sending channel allocation requests\n"; - - long capacity = (long) 16e6; - d_us_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); - d_us_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); - -} - -// Before closing the USRP connection, we deallocate our channels so that the -// capacity can be reused. -void gmac::close_channels() -{ - d_state = CLOSING_CHANNELS; - - d_us_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_us_tx_chan)); - d_us_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_us_rx_chan)); - - if(verbose) - std::cout << "[GMAC] Closing channels...\n"; -} - -// Used to enter the receiving state -void gmac::enter_receiving() -{ - d_us_rx->send(s_cmd_start_recv_raw_samples, - pmt_list2(PMT_F, - d_us_rx_chan)); - - if(verbose) - std::cout << "[GMAC] Started RX sample stream\n"; -} - -// A simple idle state, nothing more to it. -void gmac::enter_idle() -{ - d_state = IDLE; -} - -// Handles the transmission of a pkt from the application. The invocation -// handle is passed on but a response is not given back to the application until -// the response is passed from usrp_server. This ensures that the MAC passes -// back the success or failure. Furthermore, the MAC could decide to retransmit -// on a failure based on the result of the packet transmission. -// -// This should eventually be connected to a physically layer rather than -// directly to usrp_server. (d_us_tx should be replaced with a different -// connection) -void gmac::handle_cmd_tx_pkt(pmt_t data) -{ - pmt_t invocation_handle = pmt_nth(0, data); - pmt_t dst = pmt_nth(1, data); - pmt_t samples = pmt_nth(2, data); - pmt_t pkt_properties = pmt_nth(3, data); - - pmt_t us_tx_properties = pmt_make_dict(); - - // Set the packet to be carrier sensed? - if(carrier_sense_pkt(pkt_properties)) - pmt_dict_set(us_tx_properties, - pmt_intern("carrier-sense"), - PMT_T); - - pmt_t timestamp = pmt_from_long(0xffffffff); // NOW - - // Construct the proper message for USRP server - d_us_tx->send(s_cmd_xmit_raw_frame, - pmt_list5(invocation_handle, - d_us_tx_chan, - samples, - timestamp, - us_tx_properties)); - - if(verbose && 0) - std::cout << "[GMAC] Transmitted packet\n"; -} - -// Handles a response from the USRP server about the transmission of a frame, -// whether it was successful or failed. This should eventually be replaced with -// a response from the PHY layer. This is where a retransmit could be -// implemented. -void gmac::handle_response_xmit_raw_frame(pmt_t data) -{ - pmt_t invocation_handle = pmt_nth(0, data); - pmt_t status = pmt_nth(1, data); - - d_tx->send(s_response_tx_pkt, - pmt_list2(invocation_handle, - status)); -} - -// This method determines whether carrier sense should be enabled based on two -// properties. The first is the MAC setting, which the user can set to carrier -// sense packets by default or not. The second is a per packet setting, which -// can be used to override the MAC setting for the given packet only. -bool gmac::carrier_sense_pkt(pmt_t pkt_properties) -{ - // First we extract the per packet properties to check the per packet setting - // if it exists - if(pmt_is_dict(pkt_properties)) { - - if(pmt_t pkt_cs = pmt_dict_ref(pkt_properties, - pmt_intern("carrier-sense"), - PMT_NIL)) { - // If the per packet property says true, enable carrier sense regardless - // of the MAC setting - if(pmt_eqv(pkt_cs, PMT_T)) - return true; - // If the per packet setting says false, disable carrier sense regardless - // of the MAC setting - else if(pmt_eqv(pkt_cs, PMT_F)) - return false; - } - } - - // If we've hit this point, the packet properties did not state whether - // carrier sense should be used or not, so we use the MAC setting - if(d_carrier_sense) - return true; - else - return false; - -} - -// This method is envoked by an incoming cmd-enable-carrier-sense signal on the -// C/S port. It can be used to re-adjust the threshold or simply enabled -// carrier sense. When a threshold is not provided, the MAC will use an -// averaging algorithm to determine the threshold (in the future). -void gmac::handle_cmd_carrier_sense_enable(pmt_t data) -{ - pmt_t invocation_handle = pmt_nth(0, data); - pmt_t threshold = pmt_nth(1, data); - pmt_t deadline = pmt_nth(2, data); - long l_threshold, l_deadline; - - // FIXME: for now, if threshold is NIL, we do not change the threshold. - // This should be replaced with an averaging algorithm - if(pmt_eqv(threshold, PMT_NIL)) - l_threshold = d_cs_thresh; - else - l_threshold = pmt_to_long(threshold); - - // If the deadline is NIL, we do not change the value - if(pmt_eqv(threshold, PMT_NIL)) - l_deadline = d_cs_deadline; - else - l_deadline = pmt_to_long(deadline); - - set_carrier_sense(true, l_threshold, l_deadline, invocation_handle); -} - -// This method is called when an incoming disable carrier sense command is sent -// over the control status channel. It so far does not ellicit a response, this -// needs to be added correctly. It needs to wait for the response for the C/S -// packet from usrp_server. -void gmac::handle_cmd_carrier_sense_disable(pmt_t data) -{ - pmt_t invocation_handle = pmt_nth(0, data); - - // We don't change the threshold, we leave it as is because the application - // did not request that it changes, only to disable carrier sense. - set_carrier_sense(false, d_cs_thresh, d_cs_deadline, invocation_handle); -} - -// When the app requests that the threshold changes, the state of the carrier -// sense should not change. If it was enabled, it should remain enabled. -// Likewise if it was disabled. The deadline value should also remain -// unchanged. -void gmac::handle_cmd_carrier_sense_threshold(pmt_t data) -{ - pmt_t invocation_handle = pmt_nth(0, data); - pmt_t threshold = pmt_nth(1, data); - long l_threshold; - - // FIXME: for now, if threshold is NIL, we do not change the threshold. - // This should be replaced with an averaging algorithm - if(pmt_eqv(threshold, PMT_NIL)) - l_threshold = d_cs_thresh; - else - l_threshold = pmt_to_long(threshold); - - set_carrier_sense(d_carrier_sense, l_threshold, d_cs_deadline, invocation_handle); -} - -// Ability to change the deadline using a C/S packet. The state of all other -// carrier sense parameters should not change. -void gmac::handle_cmd_carrier_sense_deadline(pmt_t data) -{ - pmt_t invocation_handle = pmt_nth(0, data); - pmt_t deadline = pmt_nth(1, data); - long l_deadline; - - // If the deadline passed is NIL, do *not* change the value. - if(pmt_eqv(deadline, PMT_NIL)) - l_deadline = d_cs_deadline; - else - l_deadline = pmt_to_long(deadline); - - set_carrier_sense(d_carrier_sense, d_cs_thresh, l_deadline, invocation_handle); -} - -REGISTER_MBLOCK_CLASS(gmac); diff --git a/usrp/host/apps-inband/gmac.h b/usrp/host/apps-inband/gmac.h deleted file mode 100644 index a6d0bcb12..000000000 --- a/usrp/host/apps-inband/gmac.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef INCLUDED_GMAC_H -#define INCLUDED_GMAC_H - -#include <mb_mblock.h> - -class gmac; - -class gmac : public mb_mblock -{ - - // The state is used to determine how to handle incoming messages and of - // course, the state of the MAC protocol. - enum state_t { - INIT, - OPENING_USRP, - ALLOCATING_CHANNELS, - INIT_GMAC, - IDLE, - CLOSING_CHANNELS, - CLOSING_USRP, - }; - state_t d_state; - - // Ports used for applications to connect to this block - mb_port_sptr d_tx, d_rx, d_cs; - - // Ports to connect to usrp_server (us) - mb_port_sptr d_us_tx, d_us_rx, d_us_cs; - - // The channel numbers assigned for use - pmt_t d_us_rx_chan, d_us_tx_chan; - - pmt_t d_which_usrp; - - bool d_carrier_sense; - long d_cs_thresh; - long d_cs_deadline; - - enum FPGA_REGISTERS { - REG_CS_THRESH = 1, - REG_CS_DEADLINE = 2 - }; - - public: - gmac(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg); - ~gmac(); - void handle_message(mb_message_sptr msg); - - private: - void define_ports(); - void initialize_usrp(); - void initialize_gmac(); - void set_carrier_sense(bool toggle, long threshold, long deadline, pmt_t invocation); - void allocate_channels(); - void enter_receiving(); - void enter_idle(); - void close_channels(); - void open_usrp(); - void close_usrp(); - void handle_cmd_tx_pkt(pmt_t data); - void handle_response_xmit_raw_frame(pmt_t data); - bool carrier_sense_pkt(pmt_t pkt_properties); - void handle_cmd_carrier_sense_enable(pmt_t data); - void handle_cmd_carrier_sense_threshold(pmt_t data); - void handle_cmd_carrier_sense_disable(pmt_t data); - void handle_cmd_carrier_sense_deadline(pmt_t data); - -}; - -#endif // INCLUDED_GMAC_H diff --git a/usrp/host/apps-inband/gmac.mbh b/usrp/host/apps-inband/gmac.mbh deleted file mode 100644 index 4fa9a062f..000000000 --- a/usrp/host/apps-inband/gmac.mbh +++ /dev/null @@ -1,146 +0,0 @@ -;; -*- scheme -*- ; not really, but tells emacs how to format this -;; -;; Copyright 2007 Free Software Foundation, Inc. -;; -;; This file is part of GNU Radio -;; -;; GNU Radio is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. -;; -;; GNU Radio is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License along -;; with this program; if not, write to the Free Software Foundation, Inc., -;; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -;; - -;; ---------------------------------------------------------------- -;; This is an mblock header file -;; -;; The format is very much a work-in-progress. -;; It'll be compiled to C++. -;; ---------------------------------------------------------------- - -;; In the outgoing messages described below, invocation-handle is an -;; identifier provided by the client to tag the method invocation. -;; The identifier will be returned with the response, to provide the -;; client with a mechanism to match asynchronous responses with the -;; commands that generate them. The value of the invocation-handle is -;; opaque the the server, and is not required by the server to be -;; unique. -;; -;; In the incoming messages described below, invocation-handle is the -;; identifier provided by the client in the prompting invocation. The -;; identifier is returned with the response, so that the client has a -;; mechanism to match asynchronous responses with the commands that -;; generated them. -;; -;; status is either #t, indicating success, or a symbol indicating an error. -;; All symbol's names shall begin with %error- - - -;; ---------------------------------------------------------------- -;; gmac-tx -;; -;; The protocol class is defined from the client's point-of-view. -;; (The client port is unconjugated, the server port is conjugated.) - -(define-protocol-class gmac-tx - - (:outgoing - - ;; Transmitting packets can carry an invocation handle so the application - ;; can get TX results on specific packets, such as whether a packet tagged - ;; as #1 was successfully transmitted or not. This would allow the - ;; application to implement something sliding window like. - ;; - ;; 'dst' is the destination MAC address (given a MAC addressing scheme) - ;; - ;; 'data' will be treated transparently and passed on as samples. - ;; - ;; 'properties' can be used in the future to set per-packet options such as - ;; carrier sense overriding functionality. - (cmd-tx-pkt invocation-handle dst data properties) - - ) - - (:incoming - - ;; The response will carry the same invocation-handle passed with cmd-tx-pkt - (response-tx-pkt invocation-handle status) - - ) - ) - -;; ---------------------------------------------------------------- -;; gmac-rx -;; -;; The protocol class is defined from the client's point-of-view. -;; (The client port is unconjugated, the server port is conjugated.) - -(define-protocol-class gmac-rx - - (:outgoing - - ;; There are currently no outgoing commands, I believe that the RX - ;; should always be enabled, there is no point in having an enable/disable - ;; that I can see. - - ) - - (:incoming - - ;; Contains packets decoded by the MAC destined for this machine, sent by - ;; the specified address. - (response-rx-pkt invocation-handle src data) - - ) - ) - - -;; ---------------------------------------------------------------- -;; gmac-cs -;; -;; The protocol class is defined from the client's point-of-view. -;; (The client port is unconjugated, the server port is conjugated.) -;; -;; This defines a control/status interface to the MAC layer, for control over -;; functionality such as carrier sense and future functionality such as channel -;; hopping. - - -(define-protocol-class gmac-cs - - (:outgoing - - ;; Threshold represents the carrier sense threshold based on the digital - ;; reading out of the DAC. If the threshold is set to PMT_NIL then the - ;; MAC will use averaging to determine an appropriate threshold. - (cmd-carrier-sense-enable invocation-handle threshold deadline) - (cmd-carrier-sense-threshold invocation-handle threshold) - (cmd-carrier-sense-disable invocation-handle) - - ;; Setting the number of fast transmission retries on a failure before - ;; reporting a loss back to the application. - (cmd-set-tx-retries invocation-handle retries) - - ) - - (:incoming - - (response-gmac-initialized invocation-handle status) - - (response-carrier-sense-enable invocation-handle status) - (response-carrier-sense-threshold invocation-handle status) - (response-carrier-sense-deadline invocation-handle status) - (response-carrier-sense-disable invocation-handle status) - - (response-set-tx-retries invocation-handle status) - - ) - ) diff --git a/usrp/host/apps-inband/gmac_symbols.h b/usrp/host/apps-inband/gmac_symbols.h deleted file mode 100644 index 0d7804be1..000000000 --- a/usrp/host/apps-inband/gmac_symbols.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef INCLUDED_GMAC_SYMBOLS_H -#define INCLUDED_GMAC_SYMBOLS_H - -#include <pmt.h> - -// TX -static pmt_t s_cmd_tx_pkt = pmt_intern("cmd-tx-pkt"); -static pmt_t s_response_tx_pkt = pmt_intern("response-tx-pkt"); - -// RX -static pmt_t s_response_rx_pkt = pmt_intern("response-rx-pkt"); - -// CS -static pmt_t s_cmd_carrier_sense_enable = pmt_intern("cmd-carrier-sense-enable"); -static pmt_t s_cmd_carrier_sense_threshold = pmt_intern("cmd-carrier-sense-threshold"); -static pmt_t s_cmd_carrier_sense_deadline = pmt_intern("cmd-carrier-sense-deadline"); -static pmt_t s_cmd_carrier_sense_disable = pmt_intern("cmd-carrier-sense-disable"); -static pmt_t s_cmd_set_tx_retries = pmt_intern("cmd-set-tx-retries"); -static pmt_t s_response_gmac_initialized = pmt_intern("response-gmac-initialized"); -static pmt_t s_response_carrier_sense_enable = pmt_intern("response-carrier-sense-enable"); -static pmt_t s_response_carrier_sense_treshold = pmt_intern("response-carrier-sense-threshold"); -static pmt_t s_response_carrier_sense_deadline = pmt_intern("response-carrier-sense-deadline"); -static pmt_t s_response_carrier_sense_disable = pmt_intern("response-carrier-sense-disable"); -static pmt_t s_response_set_tx_retries = pmt_intern("response-set-tx-retries"); - -#endif // INCLUDED_GMAC_SYMBOLS_H diff --git a/usrp/host/apps-inband/test_gmac_tx.cc b/usrp/host/apps-inband/test_gmac_tx.cc deleted file mode 100644 index 74f16c669..000000000 --- a/usrp/host/apps-inband/test_gmac_tx.cc +++ /dev/null @@ -1,330 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <mb_mblock.h> -#include <mb_runtime.h> -#include <mb_protocol_class.h> -#include <mb_exception.h> -#include <mb_msg_queue.h> -#include <mb_message.h> -#include <mb_msg_accepter.h> -#include <mb_class_registry.h> -#include <pmt.h> -#include <stdio.h> -#include <string.h> -#include <iostream> - -#include <ui_nco.h> -#include <gmac.h> -#include <gmac_symbols.h> - -static bool verbose = true; - -class test_gmac_tx : public mb_mblock -{ - mb_port_sptr d_tx; - mb_port_sptr d_cs; - pmt_t d_tx_chan; // returned tx channel handle - - enum state_t { - INIT, - TRANSMITTING, - }; - - state_t d_state; - long d_nsamples_to_send; - long d_nsamples_xmitted; - long d_nframes_xmitted; - long d_samples_per_frame; - bool d_done_sending; - - // for generating sine wave output - ui_nco<float,float> d_nco; - double d_amplitude; - - public: - test_gmac_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); - ~test_gmac_tx(); - void handle_message(mb_message_sptr msg); - - protected: - void open_usrp(); - void close_usrp(); - void allocate_channel(); - void send_packets(); - void enter_transmitting(); - void build_and_send_next_frame(); - void handle_xmit_response(pmt_t invocation_handle); - void enter_closing_channel(); -}; - -test_gmac_tx::test_gmac_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) - : mb_mblock(runtime, instance_name, user_arg), - d_state(INIT), d_nsamples_to_send((long) 40e6), - d_nsamples_xmitted(0), - d_nframes_xmitted(0), - d_samples_per_frame((long)(126 * 4)), // full packet - d_done_sending(false), - d_amplitude(16384) -{ - - define_component("GMAC", "gmac", PMT_NIL); - d_tx = define_port("tx0", "gmac-tx", false, mb_port::INTERNAL); - d_cs = define_port("cs", "gmac-cs", false, mb_port::INTERNAL); - - connect("self", "tx0", "GMAC", "tx0"); - connect("self", "cs", "GMAC", "cs"); - - // initialize NCO - double freq = 100e3; - int interp = 32; // 32 -> 4MS/s - double sample_rate = 128e6 / interp; - d_nco.set_freq(2*M_PI * freq/sample_rate); - -} - -test_gmac_tx::~test_gmac_tx() -{ -} - -void -test_gmac_tx::handle_message(mb_message_sptr msg) -{ - pmt_t event = msg->signal(); - pmt_t data = msg->data(); - pmt_t port_id = msg->port_id(); - - pmt_t handle = PMT_F; - pmt_t status = PMT_F; - pmt_t dict = PMT_NIL; - std::string error_msg; - - // Dispatch based on state - switch(d_state) { - - //------------------------------ INIT ---------------------------------// - // When GMAC is done initializing, it will send a response - case INIT: - - if(pmt_eq(event, s_response_gmac_initialized)) { - handle = pmt_nth(0, data); - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { - enter_transmitting(); - return; - } - else { - error_msg = "error initializing gmac:"; - goto bail; - } - } - goto unhandled; - - //-------------------------- TRANSMITTING ----------------------------// - // In the transmit state we count the number of underruns received and - // ballpark the number with an expected count (something >1 for starters) - case TRANSMITTING: - - // Check that the transmits are OK - if (pmt_eq(event, s_response_tx_pkt)){ - handle = pmt_nth(0, data); - status = pmt_nth(1, data); - - if (pmt_eq(status, PMT_T)){ - handle_xmit_response(handle); - return; - } - else { - error_msg = "bad response-tx-pkt:"; - goto bail; - } - } - - goto unhandled; - - } - - // An error occured, print it, and shutdown all m-blocks - bail: - std::cerr << error_msg << data - << "status = " << status << std::endl; - shutdown_all(PMT_F); - return; - - // Received an unhandled message for a specific state - unhandled: - if(verbose && !pmt_eq(event, pmt_intern("%shutdown"))) - std::cout << "[TEST_GMAC_TX] unhandled msg: " << msg - << "in state "<< d_state << std::endl; -} - -void -test_gmac_tx::enter_transmitting() -{ - d_state = TRANSMITTING; - d_nsamples_xmitted = 0; - - d_cs->send(s_cmd_carrier_sense_deadline, - pmt_list2(PMT_NIL, - pmt_from_long(50000000))); - - build_and_send_next_frame(); // fire off 4 to start pipeline - build_and_send_next_frame(); - build_and_send_next_frame(); - build_and_send_next_frame(); -} - -void -test_gmac_tx::build_and_send_next_frame() -{ - // allocate the uniform vector for the samples - // FIXME perhaps hold on to this between calls - -#if 0 - long nsamples_this_frame = - std::min(d_nsamples_to_send - d_nsamples_xmitted, - d_samples_per_frame); -#else - long nsamples_this_frame = d_samples_per_frame; -#endif - - if (nsamples_this_frame == 0){ - d_done_sending = true; - return; - } - - - size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q - pmt_t uvec = pmt_make_s16vector(nshorts, 0); - size_t ignore; - int16_t *samples = pmt_s16vector_writeable_elements(uvec, ignore); - - // fill in the complex sinusoid - for (int i = 0; i < nsamples_this_frame; i++){ - - if (1){ - gr_complex s; - d_nco.sincos(&s, 1, d_amplitude); - // write 16-bit i & q - samples[2*i] = (int16_t) s.real(); - samples[2*i+1] = (int16_t) s.imag(); - } - else { - gr_complex s(d_amplitude, d_amplitude); - - // write 16-bit i & q - samples[2*i] = (int16_t) s.real(); - samples[2*i+1] = (int16_t) s.imag(); - } - } - - // Per packet properties - pmt_t tx_properties = pmt_make_dict(); - - if(d_nframes_xmitted > 25000) { - pmt_dict_set(tx_properties, - pmt_intern("carrier-sense"), - PMT_F); - } - - if(d_nframes_xmitted > 35000) { - pmt_dict_set(tx_properties, - pmt_intern("carrier-sense"), - PMT_NIL); - } - - if(d_nframes_xmitted == 45000) { - d_cs->send(s_cmd_carrier_sense_threshold, - pmt_list2(PMT_NIL, - pmt_from_long(100))); - } - - if(d_nframes_xmitted == 60000) { - d_cs->send(s_cmd_carrier_sense_threshold, - pmt_list2(PMT_NIL, - pmt_from_long(25))); - } - - if(d_nframes_xmitted == 75000) { - d_cs->send(s_cmd_carrier_sense_disable, - pmt_list1(PMT_NIL)); - } - - if(d_nframes_xmitted > 90000 && d_nframes_xmitted < 110000) { - pmt_dict_set(tx_properties, - pmt_intern("carrier-sense"), - PMT_T); - } - - if(d_nframes_xmitted > 110000) { - - if(d_nframes_xmitted % 100 == 0) - pmt_dict_set(tx_properties, - pmt_intern("carrier-sense"), - PMT_T); -} - - pmt_t timestamp = pmt_from_long(0xffffffff); // NOW - d_tx->send(s_cmd_tx_pkt, - pmt_list4(PMT_NIL, // invocation-handle - PMT_NIL, // destination - uvec, // the samples - tx_properties)); // per pkt properties - - d_nsamples_xmitted += nsamples_this_frame; - d_nframes_xmitted++; - - if(verbose && 0) - std::cout << "[TEST_GMAC_TX] Transmitted frame\n"; -} - - -void -test_gmac_tx::handle_xmit_response(pmt_t handle) -{ - if (d_done_sending && - pmt_to_long(handle) == (d_nframes_xmitted - 1)){ - // We're done sending and have received all responses - } - - build_and_send_next_frame(); -} - -REGISTER_MBLOCK_CLASS(test_gmac_tx); - - -// ---------------------------------------------------------------- - -int -main (int argc, char **argv) -{ - // handle any command line args here - - mb_runtime_sptr rt = mb_make_runtime(); - pmt_t result = PMT_NIL; - - rt->run("test_gmac_tx", "test_gmac_tx", PMT_F, &result); -} diff --git a/usrp/host/apps-inband/test_usrp_inband_2rx.cc b/usrp/host/apps-inband/test_usrp_inband_2rx.cc new file mode 100644 index 000000000..da8d7271c --- /dev/null +++ b/usrp/host/apps-inband/test_usrp_inband_2rx.cc @@ -0,0 +1,371 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <mb_mblock.h> +#include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mb_protocol_class.h> +#include <mb_exception.h> +#include <mb_msg_queue.h> +#include <mb_message.h> +#include <mb_mblock_impl.h> +#include <mb_msg_accepter.h> +#include <mb_class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <iostream> +#include <fstream> + +// Include the symbols needed for communication with USRP server +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_rx.h> + +static bool verbose = true; + +class test_usrp_rx : public mb_mblock +{ + mb_port_sptr d_rx; + mb_port_sptr d_cs; + pmt_t d_rx_chan0, d_rx_chan1; + + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNEL, + RECEIVING, + CLOSING_CHANNEL, + CLOSING_USRP, + }; + + state_t d_state; + + std::ofstream d_ofile; + + long d_samples_recvd; + long d_samples_to_recv; + + public: + test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_rx(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void open_usrp(); + void close_usrp(); + void allocate_channel(); + void send_packets(); + void enter_receiving(); + void build_and_send_next_frame(); + void handle_response_recv_raw_samples(pmt_t invocation_handle); + void enter_closing_channel(); +}; + +test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_rx_chan0(PMT_NIL), d_rx_chan1(PMT_NIL), + d_samples_recvd(0), + d_samples_to_recv(20e6) +{ + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP + pmt_t usrp_dict = pmt_make_dict(); + + // To test the application without a USRP + bool fake_usrp_p = false; + if(fake_usrp_p) { + pmt_dict_set(usrp_dict, + pmt_intern("fake-usrp"), + PMT_T); + } + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("inband_2rxhb_2tx.rbf")); + + pmt_dict_set(usrp_dict, + pmt_intern("decim-rx"), + pmt_from_long(64)); + + define_component("server", "usrp_server", usrp_dict); + + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + +} + +test_usrp_rx::~test_usrp_rx() +{ +} + +void +test_usrp_rx::initial_transition() +{ + open_usrp(); +} + +void +test_usrp_rx::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + switch(d_state){ + + //----------------------------- OPENING_USRP ----------------------------// + // We only expect a response from opening the USRP which should be succesful + // or failed. + case OPENING_USRP: + if (pmt_eq(event, s_response_open)){ + status = pmt_nth(1, data); + if (pmt_eq(status, PMT_T)){ + allocate_channel(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + } + goto unhandled; + + //----------------------- ALLOCATING CHANNELS --------------------// + // Allocate an RX channel to perform the overrun test. + case ALLOCATING_CHANNEL: + if (pmt_eq(event, s_response_allocate_channel)){ + status = pmt_nth(1, data); + if(pmt_eqv(d_rx_chan0, PMT_NIL)) + d_rx_chan0 = pmt_nth(2, data); + else + d_rx_chan1 = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T) && !pmt_eqv(d_rx_chan1, PMT_NIL)){ + enter_receiving(); + return; + } + else if(pmt_eq(status, PMT_F)){ + error_msg = "failed to allocate channel:"; + goto bail; + } + return; + } + goto unhandled; + + //--------------------------- RECEIVING ------------------------------// + // In the receiving state, we receive samples until the specified amount + // while counting the number of overruns. + case RECEIVING: + if (pmt_eq(event, s_response_recv_raw_samples)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + handle_response_recv_raw_samples(data); + return; + } + else { + error_msg = "bad response-xmit-raw-frame:"; + goto bail; + } + } + goto unhandled; + + //------------------------- CLOSING CHANNEL ----------------------------// + // Check deallocation response for the RX channel + case CLOSING_CHANNEL: + if (pmt_eq(event, s_response_deallocate_channel)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + close_usrp(); + return; + } + else { + error_msg = "failed to deallocate channel:"; + goto bail; + } + } + + // Alternately, we ignore all response recv samples while waiting for the + // channel to actually close + if (pmt_eq(event, s_response_recv_raw_samples)) + return; + + goto unhandled; + + //--------------------------- CLOSING USRP ------------------------------// + // Once we have received a successful USRP close response, we shutdown all + // mblocks and exit. + case CLOSING_USRP: + if (pmt_eq(event, s_response_close)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + fflush(stdout); + shutdown_all(PMT_T); + return; + } + else { + error_msg = "failed to close USRP:"; + goto bail; + } + } + goto unhandled; + + default: + goto unhandled; + } + return; + + // An error occured, print it, and shutdown all m-blocks + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + // Received an unhandled message for a specific state + unhandled: + if(verbose && !pmt_eq(event, pmt_intern("%shutdown"))) + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; +} + + +void +test_usrp_rx::open_usrp() +{ + pmt_t which_usrp = pmt_from_long(0); + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp)); + d_state = OPENING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Opening the USRP\n"; +} + +void +test_usrp_rx::close_usrp() +{ + + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Closing the USRP\n"; +} + +void +test_usrp_rx::allocate_channel() +{ + long capacity = (long) 16e6; + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_state = ALLOCATING_CHANNEL; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Requesting RX channel allocation\n"; +} + +void +test_usrp_rx::enter_receiving() +{ + d_state = RECEIVING; + + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan0)); + + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan1)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Receiving...\n"; +} + +void +test_usrp_rx::handle_response_recv_raw_samples(pmt_t data) +{ + pmt_t invocation_handle = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + pmt_t v_samples = pmt_nth(2, data); + pmt_t timestamp = pmt_nth(3, data); + pmt_t channel = pmt_nth(4, data); + pmt_t properties = pmt_nth(5, data); + + d_samples_recvd += pmt_length(v_samples) / 4; + + // Check for overrun + if(!pmt_is_dict(properties)) { + std::cout << "[TEST_USRP_INBAND_RX] Recv samples dictionary is improper\n"; + return; + } + + // Check if the number samples we have received meets the test + if(d_samples_recvd >= d_samples_to_recv) { + d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan0)); + d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan1)); + enter_closing_channel(); + return; + } + +} + +void +test_usrp_rx::enter_closing_channel() +{ + d_state = CLOSING_CHANNEL; + + d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan0)); + d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan1)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Deallocating RX channel\n"; +} + +REGISTER_MBLOCK_CLASS(test_usrp_rx); + + +// ---------------------------------------------------------------- + +int +main (int argc, char **argv) +{ + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_rx", PMT_F, &result); + +} diff --git a/usrp/host/apps-inband/test_usrp_inband_cs.cc b/usrp/host/apps-inband/test_usrp_inband_2tx.cc index 2497f8d5c..5ab9be06a 100644 --- a/usrp/host/apps-inband/test_usrp_inband_cs.cc +++ b/usrp/host/apps-inband/test_usrp_inband_2tx.cc @@ -25,16 +25,17 @@ #include <mb_mblock.h> #include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only #include <mb_protocol_class.h> #include <mb_exception.h> #include <mb_msg_queue.h> #include <mb_message.h> +#include <mb_mblock_impl.h> #include <mb_msg_accepter.h> #include <mb_class_registry.h> #include <pmt.h> #include <stdio.h> #include <string.h> -#include <sys/time.h> #include <iostream> #include <ui_nco.h> @@ -42,21 +43,14 @@ #include <symbols_usrp_channel.h> #include <symbols_usrp_low_level_cs.h> #include <symbols_usrp_tx.h> -#include <symbols_usrp_rx.h> -#define NBPING 10 +static bool verbose = true; -static bool verbose = false; - -class test_usrp_cs : public mb_mblock +class test_usrp_tx : public mb_mblock { mb_port_sptr d_tx; - mb_port_sptr d_rx; mb_port_sptr d_cs; - pmt_t d_tx_chan; // returned tx channel handle - pmt_t d_rx_chan; // returned tx channel handle - - struct timeval times[NBPING]; + pmt_t d_tx_chan0, d_tx_chan1; enum state_t { INIT, @@ -79,8 +73,8 @@ class test_usrp_cs : public mb_mblock double d_amplitude; public: - test_usrp_cs(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); - ~test_usrp_cs(); + test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_tx(); void initial_transition(); void handle_message(mb_message_sptr msg); @@ -89,32 +83,25 @@ class test_usrp_cs : public mb_mblock void close_usrp(); void allocate_channel(); void send_packets(); - void enter_receiving(); void enter_transmitting(); - void build_and_send_ping(); void build_and_send_next_frame(); void handle_xmit_response(pmt_t invocation_handle); void enter_closing_channel(); }; -test_usrp_cs::test_usrp_cs(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) +test_usrp_tx::test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) : mb_mblock(runtime, instance_name, user_arg), - d_tx_chan(PMT_NIL), - d_rx_chan(PMT_NIL), - d_state(INIT), d_nsamples_to_send((long) 40e6), + d_tx_chan0(PMT_NIL), d_tx_chan1(PMT_NIL), + d_state(INIT), d_nsamples_to_send((long) 80e6), d_nsamples_xmitted(0), d_nframes_xmitted(0), - //d_samples_per_frame((long)(126)), - //d_samples_per_frame((long)(126 * 3.5)), // non-full packet d_samples_per_frame((long)(126 * 4)), // full packet d_done_sending(false), d_amplitude(16384) { - if(verbose) - std::cout << "[TEST_USRP_INBAND_CS] Initializing...\n"; + // std::cout << "[TEST_USRP_TX] Initializing...\n"; d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); - d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); //bool fake_usrp_p = true; @@ -129,6 +116,11 @@ test_usrp_cs::test_usrp_cs(mb_runtime *runtime, const std::string &instance_name pmt_intern("fake-usrp"), PMT_T); } + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("inband_2rxhb_2tx.rbf")); // Set TX and RX interpolations pmt_dict_set(usrp_dict, @@ -136,18 +128,12 @@ test_usrp_cs::test_usrp_cs(mb_runtime *runtime, const std::string &instance_name pmt_from_long(128)); pmt_dict_set(usrp_dict, - pmt_intern("decim-rx"), - pmt_from_long(16)); - - // Specify the RBF to use - pmt_dict_set(usrp_dict, - pmt_intern("rbf"), - pmt_intern("boe.rbf")); + pmt_intern("rf-freq"), + pmt_from_long(10e6)); define_component("server", "usrp_server", usrp_dict); connect("self", "tx0", "server", "tx0"); - connect("self", "rx0", "server", "rx0"); connect("self", "cs", "server", "cs"); // initialize NCO @@ -160,22 +146,21 @@ test_usrp_cs::test_usrp_cs(mb_runtime *runtime, const std::string &instance_name // for now, we'll have the low-level code hardwire it. } -test_usrp_cs::~test_usrp_cs() +test_usrp_tx::~test_usrp_tx() { } void -test_usrp_cs::initial_transition() +test_usrp_tx::initial_transition() { open_usrp(); } void -test_usrp_cs::handle_message(mb_message_sptr msg) +test_usrp_tx::handle_message(mb_message_sptr msg) { pmt_t event = msg->signal(); pmt_t data = msg->data(); - pmt_t port_id = msg->port_id(); pmt_t handle = PMT_F; pmt_t status = PMT_F; @@ -200,48 +185,21 @@ test_usrp_cs::handle_message(mb_message_sptr msg) case ALLOCATING_CHANNEL: if (pmt_eq(event, s_response_allocate_channel)){ + status = pmt_nth(1, data); + if(pmt_eqv(d_tx_chan0, PMT_NIL)) + d_tx_chan0 = pmt_nth(2, data); + else + d_tx_chan1 = pmt_nth(2, data); - if(pmt_eq(d_tx->port_symbol(), port_id)) { - status = pmt_nth(1, data); - d_tx_chan = pmt_nth(2, data); - - if (pmt_eq(status, PMT_T)){ - - if(verbose) - std::cout << "[TEST_USRP_INBAND_CS] Received allocation for TX\n"; - - if(!pmt_eqv(d_rx_chan, PMT_NIL)) { - enter_receiving(); - enter_transmitting(); - } - return; - } - else { - error_msg = "failed to allocate channel:"; - goto bail; - } + if (pmt_eq(status, PMT_T) && !pmt_eqv(d_tx_chan1, PMT_NIL)){ + enter_transmitting(); + return; } - - if(pmt_eq(d_rx->port_symbol(), port_id)) { - status = pmt_nth(1, data); - d_rx_chan = pmt_nth(2, data); - - if (pmt_eq(status, PMT_T)){ - - if(verbose) - std::cout << "[TEST_USRP_INBAND_CS] Received allocation for TX\n"; - - if(!pmt_eqv(d_tx_chan, PMT_NIL)) { - enter_receiving(); - enter_transmitting(); - } - return; - } - else { - error_msg = "failed to allocate channel:"; - goto bail; - } + else if(pmt_eq(status, PMT_F)){ + error_msg = "failed to allocate channel:"; + goto bail; } + return; } goto unhandled; @@ -303,81 +261,64 @@ test_usrp_cs::handle_message(mb_message_sptr msg) return; unhandled: - if(verbose) - std::cout << "test_usrp_inband_tx: unhandled msg: " << msg - << "in state "<< d_state << std::endl; + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; } void -test_usrp_cs::open_usrp() +test_usrp_tx::open_usrp() { pmt_t which_usrp = pmt_from_long(0); d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp)); d_state = OPENING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Opening the USRP\n"; } void -test_usrp_cs::close_usrp() +test_usrp_tx::close_usrp() { d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); d_state = CLOSING_USRP; - + if(verbose) - std::cout << "[TEST_USRP_INBAND_CS] Closing USRP\n"; + std::cout << "[TEST_USRP_INBAND_TX] Closing the USRP\n"; } void -test_usrp_cs::allocate_channel() +test_usrp_tx::allocate_channel() { long capacity = (long) 16e6; + + // Send two capacity requests, which will allocate us two channels + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); - d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); d_state = ALLOCATING_CHANNEL; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Requesting TX channel allocation\n"; } void -test_usrp_cs::enter_receiving() -{ - d_rx->send(s_cmd_start_recv_raw_samples, - pmt_list2(PMT_F, - d_rx_chan)); -} - -void -test_usrp_cs::enter_transmitting() +test_usrp_tx::enter_transmitting() { d_state = TRANSMITTING; d_nsamples_xmitted = 0; - - if(verbose) - std::cout << "[TEST_USRP_INBAND_CS] Beginning transmission\n"; - - sleep(1); - -// build_and_send_next_frame(); // fire off 4 to start pipeline - - build_and_send_ping(); - build_and_send_ping(); - build_and_send_ping(); -} - -void -test_usrp_cs::build_and_send_ping() -{ + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Transmitting...\n"; - d_tx->send(s_cmd_to_control_channel, - pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed, - pmt_list2(pmt_from_long(0), - pmt_from_long(0)))))); - - std::cout << "[TEST_USRP_INBAND_CS] Ping sent" << std::endl; + build_and_send_next_frame(); // fire off 4 to start pipeline + build_and_send_next_frame(); + build_and_send_next_frame(); + build_and_send_next_frame(); } void -test_usrp_cs::build_and_send_next_frame() +test_usrp_tx::build_and_send_next_frame() { // allocate the uniform vector for the samples // FIXME perhaps hold on to this between calls @@ -421,23 +362,34 @@ test_usrp_cs::build_and_send_next_frame() } } + pmt_t tx_properties = pmt_make_dict(); + pmt_t timestamp = pmt_from_long(0xffffffff); // NOW d_tx->send(s_cmd_xmit_raw_frame, - pmt_list4(pmt_from_long(d_nframes_xmitted), // invocation-handle - d_tx_chan, // channel + pmt_list5(pmt_from_long(d_nframes_xmitted), // invocation-handle + d_tx_chan0, // channel uvec, // the samples - timestamp)); + timestamp, + tx_properties)); + + // Resend on channel 1 + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list5(pmt_from_long(d_nframes_xmitted), // invocation-handle + d_tx_chan1, // channel + uvec, // the samples + timestamp, + tx_properties)); d_nsamples_xmitted += nsamples_this_frame; d_nframes_xmitted++; - if(verbose) - std::cout << "[TEST_USRP_INBAND_CS] Transmitted frame\n"; + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n"; } void -test_usrp_cs::handle_xmit_response(pmt_t handle) +test_usrp_tx::handle_xmit_response(pmt_t handle) { if (d_done_sending && pmt_to_long(handle) == (d_nframes_xmitted - 1)){ @@ -445,21 +397,23 @@ test_usrp_cs::handle_xmit_response(pmt_t handle) enter_closing_channel(); } - //build_and_send_next_frame(); + build_and_send_next_frame(); } void -test_usrp_cs::enter_closing_channel() +test_usrp_tx::enter_closing_channel() { d_state = CLOSING_CHANNEL; - d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan)); - + // Deallocate both channels + d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan0)); + d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan1)); + if(verbose) - std::cout << "[TEST_USRP_INBAND_CS] Closing channel\n"; + std::cout << "[TEST_USRP_INBAND_tX] Deallocating TX channel\n"; } -REGISTER_MBLOCK_CLASS(test_usrp_cs); +REGISTER_MBLOCK_CLASS(test_usrp_tx); // ---------------------------------------------------------------- @@ -472,5 +426,5 @@ main (int argc, char **argv) mb_runtime_sptr rt = mb_make_runtime(); pmt_t result = PMT_NIL; - rt->run("top", "test_usrp_cs", PMT_F, &result); + rt->run("top", "test_usrp_tx", PMT_F, &result); } diff --git a/usrp/host/apps-inband/test_usrp_inband_overrun.cc b/usrp/host/apps-inband/test_usrp_inband_overrun.cc index 9041a0984..107668b89 100644 --- a/usrp/host/apps-inband/test_usrp_inband_overrun.cc +++ b/usrp/host/apps-inband/test_usrp_inband_overrun.cc @@ -102,7 +102,7 @@ test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name // Specify the RBF to use pmt_dict_set(usrp_dict, pmt_intern("rbf"), - pmt_intern("nanocell9.rbf")); + pmt_intern("inband_1rxhb_1tx.rbf")); pmt_dict_set(usrp_dict, pmt_intern("decim-rx"), @@ -306,7 +306,8 @@ test_usrp_rx::handle_response_recv_raw_samples(pmt_t data) pmt_t status = pmt_nth(1, data); pmt_t v_samples = pmt_nth(2, data); pmt_t timestamp = pmt_nth(3, data); - pmt_t properties = pmt_nth(4, data); + pmt_t channel = pmt_nth(4, data); + pmt_t properties = pmt_nth(5, data); d_samples_recvd += pmt_length(v_samples) / 4; diff --git a/usrp/host/apps-inband/test_usrp_inband_registers.cc b/usrp/host/apps-inband/test_usrp_inband_registers.cc index 017ccdbf5..a1d9cc141 100644 --- a/usrp/host/apps-inband/test_usrp_inband_registers.cc +++ b/usrp/host/apps-inband/test_usrp_inband_registers.cc @@ -118,7 +118,7 @@ test_usrp_inband_registers::test_usrp_inband_registers(mb_runtime *runtime, cons // Specify the RBF to use pmt_dict_set(usrp_dict, pmt_intern("rbf"), - pmt_intern("boe2.rbf")); + pmt_intern("inband_1rxhb_1tx.rbf")); // Set TX and RX interpolations pmt_dict_set(usrp_dict, diff --git a/usrp/host/apps-inband/test_usrp_inband_rx.cc b/usrp/host/apps-inband/test_usrp_inband_rx.cc index 0429951f3..cff2aa723 100644 --- a/usrp/host/apps-inband/test_usrp_inband_rx.cc +++ b/usrp/host/apps-inband/test_usrp_inband_rx.cc @@ -87,23 +87,30 @@ class test_usrp_rx : public mb_mblock test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) : mb_mblock(runtime, instance_name, user_arg), d_samples_recvd(0), - d_samples_to_recv(5e6) + d_samples_to_recv(20e6) { - d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP pmt_t usrp_dict = pmt_make_dict(); + + // To test the application without a USRP + bool fake_usrp_p = false; + if(fake_usrp_p) { + pmt_dict_set(usrp_dict, + pmt_intern("fake-usrp"), + PMT_T); + } // Specify the RBF to use pmt_dict_set(usrp_dict, pmt_intern("rbf"), - pmt_intern("nanocell9.rbf")); + pmt_intern("inband_1rxhb_1tx.rbf")); pmt_dict_set(usrp_dict, pmt_intern("decim-rx"), - pmt_from_long(128)); + pmt_from_long(64)); define_component("server", "usrp_server", usrp_dict); @@ -264,6 +271,7 @@ test_usrp_rx::open_usrp() void test_usrp_rx::close_usrp() { + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); d_state = CLOSING_USRP; @@ -302,7 +310,8 @@ test_usrp_rx::handle_response_recv_raw_samples(pmt_t data) pmt_t status = pmt_nth(1, data); pmt_t v_samples = pmt_nth(2, data); pmt_t timestamp = pmt_nth(3, data); - pmt_t properties = pmt_nth(4, data); + pmt_t channel = pmt_nth(4, data); + pmt_t properties = pmt_nth(5, data); d_samples_recvd += pmt_length(v_samples) / 4; @@ -325,9 +334,7 @@ void test_usrp_rx::enter_closing_channel() { d_state = CLOSING_CHANNEL; - - sleep(2); - + d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan)); if(verbose) @@ -342,10 +349,9 @@ REGISTER_MBLOCK_CLASS(test_usrp_rx); int main (int argc, char **argv) { - // handle any command line args here - mb_runtime_sptr rt = mb_make_runtime(); pmt_t result = PMT_NIL; rt->run("top", "test_usrp_rx", PMT_F, &result); + } diff --git a/usrp/host/apps-inband/test_usrp_inband_timestamps.cc b/usrp/host/apps-inband/test_usrp_inband_timestamps.cc index 8824a72fe..297c7126a 100644 --- a/usrp/host/apps-inband/test_usrp_inband_timestamps.cc +++ b/usrp/host/apps-inband/test_usrp_inband_timestamps.cc @@ -147,7 +147,7 @@ test_usrp_inband_timestamps::test_usrp_inband_timestamps(mb_runtime *runtime, co // Specify the RBF to use pmt_dict_set(usrp_dict, pmt_intern("rbf"), - pmt_intern("tmac5.rbf")); + pmt_intern("inband_1rxhb_1tx.rbf")); define_component("server", "usrp_server", usrp_dict); diff --git a/usrp/host/apps-inband/test_usrp_inband_tx.cc b/usrp/host/apps-inband/test_usrp_inband_tx.cc index 7118d2d0f..7f894a4c3 100644 --- a/usrp/host/apps-inband/test_usrp_inband_tx.cc +++ b/usrp/host/apps-inband/test_usrp_inband_tx.cc @@ -42,7 +42,7 @@ #include <symbols_usrp_low_level_cs.h> #include <symbols_usrp_tx.h> -static bool verbose = false; +static bool verbose = true; class test_usrp_tx : public mb_mblock { @@ -89,11 +89,9 @@ class test_usrp_tx : public mb_mblock test_usrp_tx::test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) : mb_mblock(runtime, instance_name, user_arg), - d_state(INIT), d_nsamples_to_send((long) 40e6), + d_state(INIT), d_nsamples_to_send((long) 80e6), d_nsamples_xmitted(0), d_nframes_xmitted(0), - //d_samples_per_frame((long)(126)), - //d_samples_per_frame((long)(126 * 3.5)), // non-full packet d_samples_per_frame((long)(126 * 4)), // full packet d_done_sending(false), d_amplitude(16384) @@ -119,18 +117,14 @@ test_usrp_tx::test_usrp_tx(mb_runtime *runtime, const std::string &instance_name // Specify the RBF to use pmt_dict_set(usrp_dict, pmt_intern("rbf"), - pmt_intern("cs1.rbf")); + pmt_intern("inband_1rxhb_1tx.rbf")); // Set TX and RX interpolations pmt_dict_set(usrp_dict, pmt_intern("interp-tx"), - pmt_from_long(128)); + pmt_from_long(64)); pmt_dict_set(usrp_dict, - pmt_intern("decim-rx"), - pmt_from_long(16)); - - pmt_dict_set(usrp_dict, pmt_intern("rf-freq"), pmt_from_long(10e6)); @@ -176,12 +170,12 @@ test_usrp_tx::handle_message(mb_message_sptr msg) if (pmt_eq(event, s_response_open)){ status = pmt_nth(1, data); if (pmt_eq(status, PMT_T)){ - allocate_channel(); - return; + allocate_channel(); + return; } else { - error_msg = "failed to open usrp:"; - goto bail; + error_msg = "failed to open usrp:"; + goto bail; } } goto unhandled; @@ -192,12 +186,12 @@ test_usrp_tx::handle_message(mb_message_sptr msg) d_tx_chan = pmt_nth(2, data); if (pmt_eq(status, PMT_T)){ - enter_transmitting(); - return; + enter_transmitting(); + return; } else { - error_msg = "failed to allocate channel:"; - goto bail; + error_msg = "failed to allocate channel:"; + goto bail; } } goto unhandled; @@ -208,12 +202,12 @@ test_usrp_tx::handle_message(mb_message_sptr msg) status = pmt_nth(1, data); if (pmt_eq(status, PMT_T)){ - handle_xmit_response(handle); - return; + handle_xmit_response(handle); + return; } else { - error_msg = "bad response-xmit-raw-frame:"; - goto bail; + error_msg = "bad response-xmit-raw-frame:"; + goto bail; } } goto unhandled; @@ -223,12 +217,12 @@ test_usrp_tx::handle_message(mb_message_sptr msg) status = pmt_nth(1, data); if (pmt_eq(status, PMT_T)){ - close_usrp(); - return; + close_usrp(); + return; } else { - error_msg = "failed to deallocate channel:"; - goto bail; + error_msg = "failed to deallocate channel:"; + goto bail; } } goto unhandled; @@ -238,12 +232,12 @@ test_usrp_tx::handle_message(mb_message_sptr msg) status = pmt_nth(1, data); if (pmt_eq(status, PMT_T)){ - shutdown_all(PMT_T); - return; + shutdown_all(PMT_T); + return; } else { - error_msg = "failed to close USRP:"; - goto bail; + error_msg = "failed to close USRP:"; + goto bail; } } goto unhandled; @@ -272,6 +266,9 @@ test_usrp_tx::open_usrp() d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp)); d_state = OPENING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Opening the USRP\n"; } void @@ -279,6 +276,9 @@ test_usrp_tx::close_usrp() { d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); d_state = CLOSING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Closing the USRP\n"; } void @@ -287,6 +287,9 @@ test_usrp_tx::allocate_channel() long capacity = (long) 16e6; d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); d_state = ALLOCATING_CHANNEL; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Requesting TX channel allocation\n"; } void @@ -295,15 +298,9 @@ test_usrp_tx::enter_transmitting() d_state = TRANSMITTING; d_nsamples_xmitted = 0; - // FIXME: carrier sense hack - d_tx->send(s_cmd_to_control_channel, // C/S packet - pmt_list2(PMT_NIL, // invoc handle - pmt_list1( - pmt_list2(s_op_write_reg, - pmt_list2( - pmt_from_long(1), - pmt_from_long(21)))))); - + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Transmitting...\n"; + build_and_send_next_frame(); // fire off 4 to start pipeline build_and_send_next_frame(); build_and_send_next_frame(); @@ -356,9 +353,6 @@ test_usrp_tx::build_and_send_next_frame() } pmt_t tx_properties = pmt_make_dict(); - pmt_dict_set(tx_properties, - pmt_intern("carrier-sense"), - PMT_T); pmt_t timestamp = pmt_from_long(0xffffffff); // NOW d_tx->send(s_cmd_xmit_raw_frame, @@ -371,7 +365,7 @@ test_usrp_tx::build_and_send_next_frame() d_nsamples_xmitted += nsamples_this_frame; d_nframes_xmitted++; - if(verbose) + if(verbose && 0) std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n"; } @@ -394,6 +388,9 @@ test_usrp_tx::enter_closing_channel() d_state = CLOSING_CHANNEL; d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_tX] Deallocating TX channel\n"; } REGISTER_MBLOCK_CLASS(test_usrp_tx); diff --git a/usrp/host/apps-inband/test_usrp_inband_underrun.cc b/usrp/host/apps-inband/test_usrp_inband_underrun.cc index 0404208b4..c9630cec2 100644 --- a/usrp/host/apps-inband/test_usrp_inband_underrun.cc +++ b/usrp/host/apps-inband/test_usrp_inband_underrun.cc @@ -127,7 +127,7 @@ test_usrp_inband_underrun::test_usrp_inband_underrun(mb_runtime *runtime, const d_rx_chan(PMT_NIL), d_which_usrp(pmt_from_long(0)), d_state(INIT), - d_nsamples_to_send((long) 20e6), + d_nsamples_to_send((long) 27e6), d_nsamples_xmitted(0), d_nframes_xmitted(0), d_samples_per_frame(d_nsamples_to_send), // full packet @@ -143,12 +143,12 @@ test_usrp_inband_underrun::test_usrp_inband_underrun(mb_runtime *runtime, const // Specify the RBF to use pmt_dict_set(usrp_dict, pmt_intern("rbf"), - pmt_intern("nanocell9.rbf")); + pmt_intern("inband_1rxhb_1tx.rbf")); // Set TX and RX interpolations pmt_dict_set(usrp_dict, pmt_intern("interp-tx"), - pmt_from_long(8)); + pmt_from_long(64)); pmt_dict_set(usrp_dict, pmt_intern("decim-rx"), @@ -668,8 +668,6 @@ test_usrp_inband_underrun::closing_usrp() { d_state = CLOSING_USRP; - sleep(2); - d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); } diff --git a/usrp/host/lib/inband/Makefile.am b/usrp/host/lib/inband/Makefile.am index 77d1f6699..a41ac18b8 100644 --- a/usrp/host/lib/inband/Makefile.am +++ b/usrp/host/lib/inband/Makefile.am @@ -76,7 +76,6 @@ include_HEADERS = \ usrp_usb_interface.h noinst_HEADERS = \ - fake_usrp.h \ qa_inband.h \ qa_inband_packet_prims.h \ qa_inband_usrp_server.h \ @@ -109,14 +108,10 @@ libusrp_inband_qa_la_LIBADD = \ # ------------------------------------------------------------------------ noinst_PROGRAMS = \ - test_inband \ - test_usrp_inband + test_inband test_inband_SOURCES = test_inband.cc test_inband_LDADD = libusrp_inband-qa.la -test_usrp_inband_SOURCES = test_usrp_inband.cc -test_usrp_inband_LDADD = libusrp_inband-qa.la - MOSTLYCLEANFILES = \ $(BUILT_SOURCES) *~ *.pyc diff --git a/usrp/host/lib/inband/fake_usrp.cc b/usrp/host/lib/inband/fake_usrp.cc deleted file mode 100644 index 8a66d5c18..000000000 --- a/usrp/host/lib/inband/fake_usrp.cc +++ /dev/null @@ -1,135 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <fake_usrp.h> -#include <iostream> -#include <usrp_inband_usb_packet.h> -#include <mb_class_registry.h> -#include <vector> - -typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy - -fake_usrp::fake_usrp() -{ - std::cout << "[fake_usrp] Initializing...\n"; -} - -fake_usrp::~fake_usrp() {} - -long -fake_usrp::write_bus(transport_pkt *pkts, long n_bytes) -{ - std::cout << "[fake_usrp] Bytes over bus: " << n_bytes << "\n"; - - // I'm assuming that a control packet cannot exist in a burst of data packets, - // therefore i read only the first packet's channel in the current burst - if(pkts[0].chan() == 0x1f) { - return control_block(pkts, n_bytes); - } else { - return data_block(pkts, n_bytes); - } - -} - -long -fake_usrp::data_block(transport_pkt *pkts, long n_bytes) -{ - std::cout << "[fake_usrp] Entering data block\n"; - - // Infer the number of packets from the byte count to do logical tests - long n_pkts = static_cast<long>(std::ceil(n_bytes / (double)transport_pkt::max_pkt_size())); - - std::cout << "[fake_usrp] Number of packets: " << n_pkts << "\n"; - - // The first packet should have the start of burst, and the last packet should have end of burst - if(pkts[0].start_of_burst() && pkts[n_pkts-1].end_of_burst()) { - std::cout << "[fake_usrp] Correct burst flags set\n"; - } else { - std::cout << "[fake_usrp] Incorrect burst flags set!\n"; - return 0; - } - - // All other flags should be set to 0 (e.g., overrun should not be set yet) on ALL packets - for(int i=0; i < n_pkts; i++) { - if(pkts[i].overrun()) { - std::cout << "[fake_usrp] Incorrect set of overrun flag on transmit\n"; - return 0; - } else if(pkts[i].underrun()) { - std::cout << "[fake_usrp] Incorrect set of underrun flag on transmit\n"; - return 0; - } else if(pkts[i].dropped()) { - std::cout << "[fake_usrp] Incorrect set of drop flag on transmit\n"; - return 0; - } - } - std::cout << "[fake_usrp] Correct overrun, underrun, and drop flags on transmit (initialized to 0)\n"; - - // The first packet should have a timestamp, other packets should have "NOW" - if(pkts[0].timestamp() != 0xffffffff) { - std::cout << "[fake_usrp] Correct timestamp on first packet\n"; - } else { - std::cout << "[fake_usrp] Initial packet should not have the 0xffffffff timestamp\n"; - return 0; - } - - // Check that all of the other packets include the NOW timestamp - int check_stamps=1; - for(int i=1; i < n_pkts; i++) // start at 1 to skip the first packet - if(pkts[i].timestamp() != 0xffffffff) - check_stamps=0; - - if(check_stamps) { - std::cout << "[fake_usrp] Correct NOW timestamps (0xffffffff) on intermediate burst packets\n"; - } else { - std::cout << "[fake_usrp] Incorrect timestamps on intermediate burst packets\n"; - return 0; - } - - // Since we are being transparent about samples, we do not ensure the payload is correct, however - // it should be the case that if there are >1 packets, all packets except the last packet should - // have a full payload size - if(n_pkts > 1) { - int check_size=1; - for(int i=0; i < n_pkts-1; i++) - if(pkts[i].payload_len() != transport_pkt::max_payload()) - check_size=0; - - if(check_size) { - std::cout << "[fake_usrp] Correct payload size sanity check on packets\n"; - } else { - std::cout << "[fake_usrp] Failed payload size sanity check\n"; - return 0; - } - } - - return 1; -} - -long -fake_usrp::control_block(transport_pkt *pkts, long n_bytes) -{ - std::cout << "[fake_usrp] Entering control block\n"; - - return 1; -} diff --git a/usrp/host/lib/inband/fake_usrp.h b/usrp/host/lib/inband/fake_usrp.h deleted file mode 100644 index 818c5a506..000000000 --- a/usrp/host/lib/inband/fake_usrp.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef INCLUDED_FAKE_USRP_H -#define INCLUDED_FAKE_USRP_H - -#include <usrp_inband_usb_packet.h> -typedef usrp_inband_usb_packet transport_pkt; - -/*! - * \brief Implements a fake USRP for testing without hardware - */ -class fake_usrp -{ - public: - fake_usrp(); - ~fake_usrp(); - long write_bus(transport_pkt *pkts, long n_bytes); - - protected: - long data_block(transport_pkt *pkts, long n_bytes); - long control_block(transport_pkt *pkts, long n_bytes); -}; - -#endif /* INCLUDED_FAKE_USRP_H */ - diff --git a/usrp/host/lib/inband/qa_inband_usrp_server.cc b/usrp/host/lib/inband/qa_inband_usrp_server.cc index b01e74e00..e457e8d64 100644 --- a/usrp/host/lib/inband/qa_inband_usrp_server.cc +++ b/usrp/host/lib/inband/qa_inband_usrp_server.cc @@ -46,6 +46,8 @@ typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit e static bool verbose = false; +static pmt_t s_timeout = pmt_intern("%timeout"); + // ---------------------------------------------------------------------------------------------- class qa_alloc_top : public mb_mblock @@ -903,10 +905,10 @@ class qa_rx_top : public mb_mblock long d_rx_chan; - long d_got_response_recv; + bool d_got_response_recv; - long d_nmsg_to_recv; - long d_nmsg_recvd; + mb_time d_t0; + double d_delta_t; public: qa_rx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); @@ -927,18 +929,19 @@ qa_rx_top::qa_rx_top(mb_runtime *runtime, const std::string &instance_name, pmt_ d_got_response_recv(false) { - d_nmsg_to_recv=12; - d_nmsg_recvd=0; - d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); // Use the stub with the usrp_server - pmt_t usrp_server_dict = pmt_make_dict(); - pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"), PMT_T); + pmt_t usrp_dict = pmt_make_dict(); + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("decim-rx"), + pmt_from_long(128)); + pmt_dict_set(usrp_dict, pmt_intern("fake-usrp"), PMT_T); // Test the TX side - define_component("server", "usrp_server", usrp_server_dict); + define_component("server", "usrp_server", usrp_dict); connect("self", "rx0", "server", "rx0"); connect("self", "cs", "server", "cs"); } @@ -967,17 +970,10 @@ qa_rx_top::run_tests() pmt_list2(PMT_NIL, pmt_from_long(0))); - // A small sleep is used to ensure, if working properly, a recv - // response comes through successfully before the close gets - // through - usleep(1000); - - d_rx->send(s_cmd_stop_recv_raw_samples, - pmt_list2(PMT_NIL, - pmt_from_long(0))); - - d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T))); - + // Schedule a small timeout in which we expect to have received at least one + // packet worth of samples from the stub + d_t0 = mb_time::time(); + schedule_one_shot_timeout(d_t0 + 0.01, PMT_NIL); } @@ -992,26 +988,37 @@ qa_rx_top::handle_message(mb_message_sptr msg) pmt_t expected = pmt_nth(0, data); pmt_t status = pmt_nth(1, data); + + // If we get a timeout we shutdown + if(pmt_eq(event, s_timeout)) { + if(verbose) + std::cout << "[qa_rx_top] Got timeout\n"; + d_rx->send(s_cmd_stop_recv_raw_samples, + pmt_list2(PMT_NIL, + pmt_from_long(0))); + + d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T))); + return; + } // For testing RX, an invocation handle is not generated by the stub, // therefore the same approach for testing is not used. We simply // expect all responses to be true. if(pmt_eq(event, s_response_recv_raw_samples)) { - if(!pmt_eqv(status, PMT_T)) { - if(verbose) - std::cout << "Got: " << status << " Expected: " << PMT_T << "\n"; - shutdown_all(PMT_F); - return; - } - else { + if(pmt_eqv(status, PMT_T)) { + if(verbose) std::cout << "[qa_rx_top] Received expected response for message " - << d_nmsg_recvd << " (" << event << ")\n"; // All we want is 1 response receive! Can't guarantee exact numbers d_got_response_recv = true; } + else { + if(verbose) + std::cout << "Got: " << status << " Expected: " << PMT_T << "\n"; + shutdown_all(PMT_F); + } return; } @@ -1026,8 +1033,7 @@ qa_rx_top::handle_message(mb_message_sptr msg) } else { if(verbose) std::cout << "[qa_rx_top] Received expected response for message " - << d_nmsg_recvd - << " (" << event << ")\n"; + << " (" << event << ")\n"; } if (pmt_eq(msg->port_id(), d_rx->port_symbol())) { @@ -1051,12 +1057,7 @@ qa_rx_top::handle_message(mb_message_sptr msg) std::cout << "[qa_rx_top] No response message before close\n"; return; } - } - - - d_nmsg_recvd++; - } @@ -1079,6 +1080,160 @@ qa_rx_top::check_allocation(mb_message_sptr msg) REGISTER_MBLOCK_CLASS(qa_rx_top); +// ---------------------------------------------------------------------------------------------- + +class qa_rid_top : public mb_mblock +{ + mb_port_sptr d_tx; + mb_port_sptr d_rx; + mb_port_sptr d_cs; + + long d_npongs; + long d_tcycles; + long d_cycles; + long d_max_rid; + + mb_time d_t0; + double d_delta_t; + + public: + qa_rid_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~qa_rid_top(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void run_tests(); + void send_max_pings(); +}; + +qa_rid_top::qa_rid_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg) +{ + d_npongs = 0; + d_tcycles = 3; + d_cycles = d_tcycles; + d_max_rid = usrp_server::D_MAX_RID; + d_delta_t = 0.1; + + + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + // Use the stub with the usrp_server + pmt_t usrp_server_dict = pmt_make_dict(); + pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T); + + // Test the TX side + define_component("server", "usrp_server", usrp_server_dict); + connect("self", "tx0", "server", "tx0"); + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + +} + +qa_rid_top::~qa_rid_top(){} + +void +qa_rid_top::initial_transition() +{ + run_tests(); +} + +void +qa_rid_top::run_tests() +{ + if(verbose) + std::cout << "[qa_rid_top] Starting tests...\n"; + + // Retrieve information about the USRP, then run tests + d_cs->send(s_cmd_open, + pmt_list2(pmt_list2(s_response_open, PMT_T), + pmt_from_long(0))); + + // should be able to allocate 1 byte + d_tx->send(s_cmd_allocate_channel, + pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T), + pmt_from_long(1))); + + d_rx->send(s_cmd_allocate_channel, + pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T), + pmt_from_long(1))); + + // Need to start receiving to read from the USRP to get C/S responses + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_NIL, + pmt_from_long(0))); + + // Build a subpacket of MAX_RID pings and wait a small amount for all of the + // responses and fire off another MAX_RID. If MAX_RID*2 responses are + // received, the RID recycling is working correctly. + // Schedule a timer in which we expect to have received all of the responses, + // which will send off another MAX_RID worth. + send_max_pings(); + d_t0 = mb_time::time(); + schedule_one_shot_timeout(d_t0 + d_delta_t, PMT_NIL); +} + +void +qa_rid_top::send_max_pings() +{ + pmt_t ping = pmt_list2(s_op_ping_fixed, + pmt_list2(pmt_from_long(0), + pmt_from_long(0))); + + pmt_t sub_packets = PMT_NIL; + + for(int i=0; i<d_max_rid; i++) + sub_packets = pmt_list_add(sub_packets, ping); + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T), + sub_packets)); +} + +void +qa_rid_top::handle_message(mb_message_sptr msg) +{ + pmt_t data = msg->data(); + pmt_t event = msg->signal(); + + // If we get a timeout we ensure we got a maximum RID number of responses. + if(pmt_eq(event, s_timeout)) { + if(verbose) + std::cout << "[qa_rid_top] Got timeout, received so far: " + << d_npongs << "\n"; + + d_cycles--; + + if(d_cycles==0 && d_npongs == d_max_rid*d_tcycles) { + shutdown_all(PMT_T); + } + else if(d_cycles==0) { + + std::cout << "[qa_rid_top] d_npongs: " << d_npongs + << " expected: " << d_max_rid*d_tcycles + << std::endl; + + shutdown_all(PMT_F); + } + else { + send_max_pings(); + d_t0 = mb_time::time(); + schedule_one_shot_timeout(d_t0 + d_delta_t, PMT_NIL); + } + + } + else if(pmt_eq(event, s_response_from_control_channel)) + { + d_npongs++; + } + +} + +REGISTER_MBLOCK_CLASS(qa_rid_top); + // ---------------------------------------------------------------------------------------------- @@ -1398,3 +1553,17 @@ qa_inband_usrp_server::test_cs() CPPUNIT_ASSERT(pmt_equal(PMT_T, result)); } + +void +qa_inband_usrp_server::test_rid() +{ + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_T; + + // std::cout << "\n\n-----------------\n"; + // std::cout << " RUNNING RID TESTS \n"; + + rt->run("top", "qa_rid_top", PMT_F, &result); + + CPPUNIT_ASSERT(pmt_equal(PMT_T, result)); +} diff --git a/usrp/host/lib/inband/qa_inband_usrp_server.h b/usrp/host/lib/inband/qa_inband_usrp_server.h index 5db57c3ed..52a4a0b06 100644 --- a/usrp/host/lib/inband/qa_inband_usrp_server.h +++ b/usrp/host/lib/inband/qa_inband_usrp_server.h @@ -34,6 +34,7 @@ class qa_inband_usrp_server : public CppUnit::TestCase { CPPUNIT_TEST(test_tx); CPPUNIT_TEST(test_rx); CPPUNIT_TEST(test_cs); + CPPUNIT_TEST(test_rid); CPPUNIT_TEST_SUITE_END(); private: @@ -43,6 +44,7 @@ class qa_inband_usrp_server : public CppUnit::TestCase { void test_tx(); void test_rx(); void test_cs(); + void test_rid(); }; #endif /* INCLUDED_QA_INBAND_USRP_SERVER_H */ diff --git a/usrp/host/lib/inband/test_usrp_inband.cc b/usrp/host/lib/inband/test_usrp_inband.cc deleted file mode 100644 index 64fbf3a97..000000000 --- a/usrp/host/lib/inband/test_usrp_inband.cc +++ /dev/null @@ -1,298 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <string.h> -#include <iostream> -#include <usrp_inband_usb_packet.h> -#include <mb_mblock.h> -#include <mb_runtime.h> -#include <mb_protocol_class.h> -#include <mb_class_registry.h> -#include <pmt.h> -#include "usrp_standard.h" - -typedef usrp_inband_usb_packet transport_pkt; - -// Signal set for the USRP server -static pmt_t s_cmd_open = pmt_intern("cmd-open"); -static pmt_t s_response_open = pmt_intern("response-open"); -static pmt_t s_cmd_close = pmt_intern("cmd-close"); -static pmt_t s_response_close = pmt_intern("response-close"); -static pmt_t s_cmd_allocate_channel = pmt_intern("cmd-allocate-channel"); -static pmt_t s_response_allocate_channel = pmt_intern("response-allocate-channel"); -static pmt_t s_send_allocate_channel = pmt_intern("send-allocate-channel"); -static pmt_t s_cmd_deallocate_channel = pmt_intern("cmd-deallocate-channel"); -static pmt_t s_response_deallocate_channel = pmt_intern("response-deallocate-channel"); -static pmt_t s_send_deallocate_channel = pmt_intern("send-deallocate-channel"); -static pmt_t s_cmd_max_capacity = pmt_intern("cmd-max-capacity"); -static pmt_t s_response_max_capacity = pmt_intern("response-max-capacity"); -static pmt_t s_cmd_ntx_chan = pmt_intern("cmd-ntx-chan"); -static pmt_t s_cmd_nrx_chan = pmt_intern("cmd-nrx-chan"); -static pmt_t s_response_ntx_chan = pmt_intern("response-ntx-chan"); -static pmt_t s_response_nrx_chan = pmt_intern("response-nrx-chan"); -static pmt_t s_cmd_current_capacity_allocation = pmt_intern("cmd-current-capacity-allocation"); -static pmt_t s_response_current_capacity_allocation = pmt_intern("response-current-capacity-allocation"); -static pmt_t s_cmd_xmit_raw_frame = pmt_intern("cmd-xmit-raw-frame"); -static pmt_t s_response_xmit_raw_frame = pmt_intern("response-xmit-raw-frame"); - -bool loopback_p = false; -bool counting_p = false; -bool fake_usrp_p = false; -char *prog_name; - -static void -set_progname (char *path) -{ - char *p = strrchr (path, '/'); - if (p != 0) - prog_name = p+1; - else - prog_name = path; -} - -static void -usage() -{ - fprintf (stderr, "usage: %s [-l]\n", prog_name); - fprintf (stderr, " [-l] digital loopback in FPGA\n"); - fprintf (stderr, " [-c] counting in FPGA\n"); - fprintf (stderr, " [-f] fake usrp\n"); - - exit(1); -} - -int -main(int argc, char **argv) -{ - int ch; - - set_progname(argv[0]); - - mb_runtime_sptr rt = mb_make_runtime(); - pmt_t result = PMT_T; - - while ((ch = getopt(argc, argv, "flc")) != EOF) { - switch(ch) { - - case 'l': - loopback_p = true; - break; - - case 'c': - counting_p = true; - break; - - case 'f': - fake_usrp_p = true; - break; - - default: - usage(); - } - } - - - std::cout << "[test_usrp_inband] Starting...\n"; - - rt->run("top", "test_usrp_inband_top", PMT_F, &result); -} - -class test_usrp_inband_top : public mb_mblock -{ - mb_port_sptr d_tx; - mb_port_sptr d_cs; - - long d_tx_chan; - - public: - test_usrp_inband_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); - ~test_usrp_inband_top(); - void initial_transition(); - void handle_message(mb_message_sptr msg); - - protected: - void open_usrp(); - void close_usrp(); - void check_message(mb_message_sptr msg); - void allocate_channel(); - void send_packets(); -}; - -test_usrp_inband_top::test_usrp_inband_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) - : mb_mblock(runtime, instance_name, user_arg) -{ - std::cout << "[TEST_USRP_INBAND_TOP] Initializing...\n"; - - d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); - d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); - - // Test the TX side - - // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP - pmt_t usrp_server_dict = pmt_make_dict(); - - if(fake_usrp_p) - pmt_dict_set(usrp_server_dict, pmt_intern("usrp-interface"), pmt_intern("usrp_usb_interface_stub")); - - define_component("server", "usrp_server", usrp_server_dict); - connect("self", "tx0", "server", "tx0"); - connect("self", "cs", "server", "cs"); -} - -test_usrp_inband_top::~test_usrp_inband_top() -{ -} - -void -test_usrp_inband_top::initial_transition() -{ - open_usrp(); -} - -void -test_usrp_inband_top::handle_message(mb_message_sptr msg) -{ - pmt_t event = msg->signal(); // the "name" of the message - pmt_t port_id = msg->port_id(); // which port it came in on - pmt_t data = msg->data(); - pmt_t metadata = msg->metadata(); - pmt_t status; - - if (pmt_eq(port_id, d_cs->port_symbol())) { // message came in on our control/status port - - //---------- OPEN RESPONSE ----------// - if (pmt_eq(event, s_response_open)) { - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { - std::cout << "[TEST_USRP_INBAND_TOP] Success opening USRP\n"; - } - else { - std::cout << "[TEST_USRP_INBAND_TOP] Received error message opening USRP\n"; - shutdown_all(PMT_F); - } - - allocate_channel(); - - return; - } - //--------- CLOSE RESPONSE -----------// - else if (pmt_eq(event, s_response_close)) { - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { - std::cout << "[TEST_USRP_INBAND_TOP] Successfully closed USRP\n"; - } - else { - std::cout << "[TEST_USRP_INBAND_TOP] Received error message closing USRP\n"; - shutdown_all(PMT_F); - } - - shutdown_all(PMT_T); - - return; - } - } - - if (pmt_eq(port_id, d_tx->port_symbol())) { - - //---------- ALLOCATE RESPONSE ---------// - if(pmt_eq(event, s_response_allocate_channel)) { - status = pmt_nth(1, data); - pmt_t channel = pmt_nth(2, data); - - if(pmt_eq(status, PMT_T)) { - d_tx_chan = pmt_to_long(channel); - std::cout << "[TEST_USRP_INBAND_TOP] Received allocation on channel " << d_tx_chan << "\n"; - } - else { - std::cout << "[TEST_USRP_INBAND_TOP] Error allocating channel\n"; - shutdown_all(PMT_F); - } - - send_packets(); - - return; - } - //----------- XMIT RESPONSE ------------// - else if(pmt_eq(event, s_response_xmit_raw_frame)) { - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { - std::cout << "[TEST_USRP_INBAND_TOP] Transmission successful\n"; - } - else { - std::cout << "[TEST_USRP_INBAND_TOP] Failed transmission\n"; - shutdown_all(PMT_F); - } - - close_usrp(); - - return; - } - } - - std::cout << "[TEST_USRP_INBAND_TOP] Received unhandled message: " << event << "\n"; -} - -void -test_usrp_inband_top::allocate_channel() -{ - std::cout << "[TEST_USRP_INBAND_TOP] Requesting channel allocation...\n"; - - d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1))); -} - -void -test_usrp_inband_top::send_packets() -{ - std::cout << "[TEST_USRP_INBAND_TOP] Sending single packet..\n"; - d_tx->send(s_cmd_xmit_raw_frame, pmt_list4(pmt_from_long(1), pmt_from_long(d_tx_chan), pmt_make_u32vector(transport_pkt::max_payload()/4, 0), pmt_from_long(0))); - -} - -void -test_usrp_inband_top::open_usrp() -{ - pmt_t usrp = pmt_from_long(0); - - long rx_mode = 0; - - if(loopback_p) - rx_mode |= usrp_standard_rx::FPGA_MODE_LOOPBACK; - if(counting_p) - rx_mode |= usrp_standard_rx::FPGA_MODE_COUNTING; - - d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, usrp)); -} - -void -test_usrp_inband_top::close_usrp() -{ - d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); -} - -REGISTER_MBLOCK_CLASS(test_usrp_inband_top); diff --git a/usrp/host/lib/inband/usrp_inband_usb_packet.cc b/usrp/host/lib/inband/usrp_inband_usb_packet.cc index ee4cb22f3..2f02ecc3f 100644 --- a/usrp/host/lib/inband/usrp_inband_usb_packet.cc +++ b/usrp/host/lib/inband/usrp_inband_usb_packet.cc @@ -30,6 +30,14 @@ #include <stdio.h> #include <string.h> +/*! + * \brief Aligns the packet payload on a 32 bit boundary. This is essential to + * all control/status packets so that the inband FPGA code can parse them + * easily. + * + * \returns true if successful or if the packet was already aligned; false if it + * cannot be aligned. + */ bool usrp_inband_usb_packet::align32() { int p_len = payload_len(); @@ -44,18 +52,20 @@ bool usrp_inband_usb_packet::align32() if((MAX_PAYLOAD - p_len) < bytes_needed) return false; - p_len += bytes_needed; - - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = p_len; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(bytes_needed); return true; } +/*! + * \brief Adds a ping command to the current control packet. + * + * The \p rid is the rid to be associated with the ping response and \p ping_val + * is currently unused. + * + * \returns true if adding the ping command was successful, false otherwise + * (i.e. no space in the current packet). + */ bool usrp_inband_usb_packet::cs_ping(long rid, long ping_val) { if(!align32()) @@ -78,17 +88,20 @@ bool usrp_inband_usb_packet::cs_ping(long rid, long ping_val) *payload = host_to_usrp_u32(ping); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_PING_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_PING_LEN); return true; } - +/*! + * \brief Adds a ping response to the packet. This is used by the fake USRP + * code to generate fake responses for pings. + * + * The \p rid is the RID to be associated with the response and \p ping_val is + * currently unused. + * + * \returns true if the ping reply was added successfully, false otherwise. + */ bool usrp_inband_usb_packet::cs_ping_reply(long rid, long ping_val) { if(!align32()) @@ -111,16 +124,20 @@ bool usrp_inband_usb_packet::cs_ping_reply(long rid, long ping_val) *payload = host_to_usrp_u32(ping); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_PING_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_PING_LEN); return true; } +/*! + * \brief Adds a write register command to the packet. + * + * The \p reg_num is the register number for which the value \p val will be + * written to. + * + * \returns true if the command was added to the packet successfully, false + * otherwise. + */ bool usrp_inband_usb_packet::cs_write_reg(long reg_num, long val) { if(!align32()) @@ -149,16 +166,19 @@ bool usrp_inband_usb_packet::cs_write_reg(long reg_num, long val) *payload = host_to_usrp_u32((uint32_t) val); // Rebuild the header to update the payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_WRITEREG_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_WRITEREG_LEN); return true; } +/*! + * \brief Adds a write register masked command to the packet. + * + * The \p reg_num is the register number for which the value \p val will be + * written, masked by \p mask + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_write_reg_masked(long reg_num, long val, long mask) { if(!align32()) @@ -190,16 +210,19 @@ bool usrp_inband_usb_packet::cs_write_reg_masked(long reg_num, long val, long ma *payload = host_to_usrp_u32((uint32_t) mask); // Rebuild the header to update the payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_WRITEREGMASKED_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_WRITEREGMASKED_LEN); return true; } +/*! + * \brief Adds a read register message to the packet. + * + * The \p rid will be the associated RID returned with the response, and \p + * reg_num is the register to be read. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_read_reg(long rid, long reg_num) { if(!align32()) @@ -222,16 +245,22 @@ bool usrp_inband_usb_packet::cs_read_reg(long rid, long reg_num) *payload = host_to_usrp_u32(read_reg); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_READREG_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_READREG_LEN); return true; } +/*! + * \brief Adds a read register reply response to the current packet. This is + * used by the fake USRP code to generate fake register read responses for + * testing. + * + * The \p rid is the associated RID to be included in the response, \p reg_num + * is the register the read is coming from, and \p reg_val is the value of the + * read. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_read_reg_reply(long rid, long reg_num, long reg_val) { if(!align32()) @@ -258,16 +287,19 @@ bool usrp_inband_usb_packet::cs_read_reg_reply(long rid, long reg_num, long reg_ *payload = host_to_usrp_u32((uint32_t) reg_val); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_READREGREPLY_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_READREGREPLY_LEN); return true; } +/*! + * \brief Adds a delay command to the current packet. + * + * The \p ticks parameter is the number of clock ticks the FPGA should delay + * parsing for, which is added to the packet. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_delay(long ticks) { if(!align32()) @@ -289,16 +321,16 @@ bool usrp_inband_usb_packet::cs_delay(long ticks) *payload = host_to_usrp_u32(delay); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_DELAY_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_DELAY_LEN); return true; } +/*! + * \brief + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_i2c_write(long i2c_addr, uint8_t *i2c_data, size_t data_len) { if(!align32()) @@ -328,16 +360,20 @@ bool usrp_inband_usb_packet::cs_i2c_write(long i2c_addr, uint8_t *i2c_data, size memcpy(payload, i2c_data, data_len); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + i2c_len; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + i2c_len); return true; } +/*! + * \brief Adds an I2C read command to the current packet. + * + * The \p rid is the associated RID to return with the read response, \p + * i2c_addr is the address to read from on the I2C bus, and \p n_bytes is the + * number of bytes to be read from the bus. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_i2c_read(long rid, long i2c_addr, long n_bytes) { if(!align32()) @@ -367,16 +403,20 @@ bool usrp_inband_usb_packet::cs_i2c_read(long rid, long i2c_addr, long n_bytes) *payload = host_to_usrp_u32(word1); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_I2CREAD_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_I2CREAD_LEN); return true; } +/*! + * \brief Adds an I2C read reply response to the current packet. This is used + * by the fake USRP code to generate fake I2C responses. + * + * The \p rid is the RID to be associated with the response, \p i2c_addr is the + * address on the I2C bus that the \p i2c_data of \p i2c_data_len was read from. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_i2c_read_reply(long rid, long i2c_addr, uint8_t *i2c_data, long i2c_data_len) { if(!align32()) @@ -406,16 +446,16 @@ bool usrp_inband_usb_packet::cs_i2c_read_reply(long rid, long i2c_addr, uint8_t memcpy(payload, i2c_data, i2c_data_len); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + i2c_len; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + i2c_len); return true; } +/*! + * \brief Adds a SPI write command to the current packet. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_spi_write(long enables, long format, long opt_header_bytes, uint8_t *spi_data, long spi_data_len) { if(!align32()) @@ -454,16 +494,16 @@ bool usrp_inband_usb_packet::cs_spi_write(long enables, long format, long opt_he memcpy(payload, spi_data, spi_data_len); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + spi_len; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + spi_len); return true; } +/*! + * \brief Adds a SPI bus read command to the packet. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_spi_read(long rid, long enables, long format, long opt_header_bytes, long n_bytes) { if(!align32()) @@ -508,16 +548,17 @@ bool usrp_inband_usb_packet::cs_spi_read(long rid, long enables, long format, lo *payload = host_to_usrp_u32(word); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_SPIREAD_LEN; + incr_header_len(CS_FIXED_LEN + CS_SPIREAD_LEN); - set_header(h_flags, h_chan, h_tag, h_payload_len); - return true; } +/*! + * \brief Adds an SPI read reply to the current packet. This is used by the + * fake USRP code to generate fake responses for SPI reads. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_spi_read_reply(long rid, uint8_t *spi_data, long spi_data_len) { if(!align32()) @@ -546,30 +587,32 @@ bool usrp_inband_usb_packet::cs_spi_read_reply(long rid, uint8_t *spi_data, long memcpy(payload, spi_data, spi_data_len); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + spi_len; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + spi_len); return true; } -// Takes an offset to the beginning of a subpacket and extracts the -// length of the subpacket +/*! + * \brief Since all control packets contain subpackets which have the length of + * the subpacket at a uniform location in the subpacket, this will return the + * subpacket length given a byte offset of the start of the subpacket from the beginning of the packet. + * + * \returns the length of the subpacket + */ int usrp_inband_usb_packet::cs_len(int payload_offset) { uint32_t subpkt = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset))); return (subpkt >> CS_LEN_SHIFT) & CS_LEN_MASK; } -// The following method takes an offset within the packet payload to extract -// a control/status subpacket and construct a pmt response which includes the -// proper signal and arguments specified by usrp-low-level-cs. The USRP -// server could therefore use this to read subpackets and pass them responses -// back up to the application. It's arguable that only reply packets should -// be parsed here, however we parse others for use in debugging or failure -// reporting on the transmit side of packets. +/*! + * \brief The following method takes an offset within the packet payload to + * extract a control/status subpacket and constructs a pmt response which + * includes the proper signal and arguments specified by usrp-low-level-cs. The + * USRP server could therefore use this to read subpackets and pass them + * responses back up to the application. It's arguable that only reply packets + * should be parsed here, however we parse others for use in debugging or + * failure reporting on the transmit side of packets. + */ pmt_t usrp_inband_usb_packet::read_subpacket(int payload_offset) { uint32_t subpkt = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset))); diff --git a/usrp/host/lib/inband/usrp_inband_usb_packet.h b/usrp/host/lib/inband/usrp_inband_usb_packet.h index 8c19b1aeb..8f59d1b65 100644 --- a/usrp/host/lib/inband/usrp_inband_usb_packet.h +++ b/usrp/host/lib/inband/usrp_inband_usb_packet.h @@ -31,6 +31,7 @@ static const int USB_PKT_SIZE = 512; // bytes static const int MAX_PAYLOAD = USB_PKT_SIZE-2*sizeof(uint32_t); +static const int CONTROL_CHAN = 0x1f; class usrp_inband_usb_packet { // @@ -150,6 +151,10 @@ public: | ((payload_len & PAYLOAD_LEN_MASK) << PAYLOAD_LEN_SHIFT)); d_word0 = host_to_usrp_u32(word0); } + + void incr_header_len(int val) { + set_header(flags(), chan(), tag(), payload_len() + val); + } uint32_t timestamp() const { return usrp_to_host_u32(d_timestamp); diff --git a/usrp/host/lib/inband/usrp_rx.cc b/usrp/host/lib/inband/usrp_rx.cc index caa2d7175..71c042a50 100644 --- a/usrp/host/lib/inband/usrp_rx.cc +++ b/usrp/host/lib/inband/usrp_rx.cc @@ -40,25 +40,30 @@ typedef usrp_inband_usb_packet transport_pkt; static const bool verbose = false; +bool usrp_rx_stop; + usrp_rx::usrp_rx(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg) : mb_mblock(rt, instance_name, user_arg), - d_disk_write(false) + d_disk_write(false), + d_disk_write_pkt(false) // if true, writes full packet, else just the payload { d_cs = define_port("cs", "usrp-rx-cs", true, mb_port::EXTERNAL); - //d_disk_write=true; - if(d_disk_write) { - d_ofile.open("rx_data.dat",std::ios::binary|std::ios::out); + d_ofile0.open("rx_data_chan0.dat",std::ios::binary|std::ios::out); + d_ofile1.open("rx_data_chan1.dat",std::ios::binary|std::ios::out); d_cs_ofile.open("rx_cs.dat",std::ios::binary|std::ios::out); } + + usrp_rx_stop = false; } usrp_rx::~usrp_rx() { if(d_disk_write) { - d_ofile.close(); + d_ofile0.close(); + d_ofile1.close(); d_cs_ofile.close(); } } @@ -69,6 +74,12 @@ usrp_rx::initial_transition() } +/*! + * \brief Handles incoming signals to to the m-block, wihch should only ever be + * a single message: cmd-usrrp-rx-start-reading. There is no signal to stop + * reading as the m-block goes in to a forever loop to read inband packets from + * the bus. + */ void usrp_rx::handle_message(mb_message_sptr msg) { @@ -85,6 +96,17 @@ usrp_rx::handle_message(mb_message_sptr msg) } } +/*! + * \brief Performs the actual reading of data from the USB bus, called by + * handle_message() when a cmd-usrp-rx-start-reading signal is received. + * + * The method enters a forever loop where it continues to read data from the bus + * and generate read responses to the higher layer. Currently, shared memory is + * used to exit this loop. + * + * The \p data parameter is a PMT list which contains only a single element, an + * invocation handle which will be returned with all read respones. + */ void usrp_rx::read_and_respond(pmt_t data) { @@ -104,7 +126,7 @@ usrp_rx::read_and_respond(pmt_t data) std::cout << "[usrp_rx] Waiting for packets..\n"; // Read by 512 which is packet size and send them back up - while(1) { + while(!usrp_rx_stop) { pmt_t v_pkt = pmt_make_u8vector(pkt_size, 0); transport_pkt *pkt = @@ -124,19 +146,38 @@ usrp_rx::read_and_respond(pmt_t data) d_cs->send(s_response_usrp_rx_read, pmt_list3(PMT_NIL, PMT_T, v_pkt)); - if(verbose) + if(verbose && 0) std::cout << "[usrp_rx] Read 1 packet\n"; if(d_disk_write) { - if(pkt->chan() == 0x1f) + if(pkt->chan() == CONTROL_CHAN) d_cs_ofile.write((const char *)pkt, transport_pkt::max_pkt_size()); - else - d_ofile.write((const char *)pkt, transport_pkt::max_pkt_size()); + else { + if(d_disk_write_pkt) { + if(pkt->chan() == 0) + d_ofile0.write((const char *)pkt, transport_pkt::max_pkt_size()); + else if(pkt->chan() == 1) + d_ofile1.write((const char *)pkt, transport_pkt::max_pkt_size()); + } else { + if(pkt->chan() == 0) + d_ofile0.write((const char *)pkt->payload(), transport_pkt::max_payload()); + else if(pkt->chan() == 1) + d_ofile1.write((const char *)pkt->payload(), transport_pkt::max_payload()); + } + } d_cs_ofile.flush(); - d_ofile.flush(); + d_ofile0.flush(); + d_ofile1.flush(); } } + + usrp_rx_stop = false; + + if(verbose) { + std::cout << "[USRP_RX] Stopping...\n"; + fflush(stdout); + } } REGISTER_MBLOCK_CLASS(usrp_rx); diff --git a/usrp/host/lib/inband/usrp_rx.h b/usrp/host/lib/inband/usrp_rx.h index e1a90a781..10104bd66 100644 --- a/usrp/host/lib/inband/usrp_rx.h +++ b/usrp/host/lib/inband/usrp_rx.h @@ -26,6 +26,8 @@ class usrp_standard_rx; +extern bool usrp_rx_stop; // used to communicate a 'stop' to the RX stub + /*! * \brief Implements the low level usb interface to the USRP */ @@ -35,7 +37,9 @@ class usrp_rx : public mb_mblock usrp_standard_rx *d_urx; bool d_disk_write; - std::ofstream d_ofile; + bool d_disk_write_pkt; + std::ofstream d_ofile0; + std::ofstream d_ofile1; std::ofstream d_cs_ofile; public: diff --git a/usrp/host/lib/inband/usrp_rx_stub.cc b/usrp/host/lib/inband/usrp_rx_stub.cc index 4bdb106b1..1c96b7a7a 100644 --- a/usrp/host/lib/inband/usrp_rx_stub.cc +++ b/usrp/host/lib/inband/usrp_rx_stub.cc @@ -43,7 +43,7 @@ typedef usrp_inband_usb_packet transport_pkt; static const bool verbose = false; -bool usrp_rx_stop; +bool usrp_rx_stop_stub; // Used for the fake control packet response code to send the responses back up // the RX. The TX stub dumps responses in to this queue. @@ -52,15 +52,32 @@ std::queue<pmt_t> d_cs_queue; usrp_rx_stub::usrp_rx_stub(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg) : mb_mblock(rt, instance_name, user_arg), d_samples_per_frame((long)(126)), + d_decim_rx(128), d_amplitude(16384), d_disk_write(false) { + + // Information about the rates are passed all the way from the app in the form + // of a dictionary. We use this to read the RX decimation rate and compute + // the approximate number of MS/s as a form of flow control for the stub. + pmt_t usrp_dict = user_arg; + + if (pmt_is_dict(usrp_dict)) { + // Read the RX decimation rate + if(pmt_t decim_rx = pmt_dict_ref(usrp_dict, + pmt_intern("decim-rx"), + PMT_NIL)) { + if(!pmt_eqv(decim_rx, PMT_NIL)) + d_decim_rx = pmt_to_long(decim_rx); + } + } + d_cs = define_port("cs", "usrp-rx-cs", true, mb_port::EXTERNAL); // initialize NCO double freq = 100e3; int interp = 32; // 32 -> 4MS/s - double sample_rate = 128e6 / interp; + double sample_rate = 64e6 / interp; d_nco.set_freq(2*M_PI * freq/sample_rate); //d_disk_write = true; @@ -68,7 +85,7 @@ usrp_rx_stub::usrp_rx_stub(mb_runtime *rt, const std::string &instance_name, pmt if(d_disk_write) d_ofile.open("raw_rx.dat",std::ios::binary|std::ios::out); - usrp_rx_stop = false; + usrp_rx_stop_stub = false; } usrp_rx_stub::~usrp_rx_stub() @@ -80,7 +97,6 @@ usrp_rx_stub::~usrp_rx_stub() void usrp_rx_stub::initial_transition() { - } void @@ -90,94 +106,121 @@ usrp_rx_stub::handle_message(mb_message_sptr msg) pmt_t port_id = msg->port_id(); pmt_t data = msg->data(); + if (pmt_eq(msg->signal(), s_timeout) + && !pmt_eq(msg->data(), s_done)) { + + if(!usrp_rx_stop_stub) + read_and_respond(); + else { // requested to stop + cancel_timeout(msg->metadata()); + usrp_rx_stop_stub=false; + if(verbose) + std::cout << "[USRP_RX_STUB] Stopping RX stub\n"; + } + + } + // Theoretically only have 1 message to ever expect, but // want to make sure its at least what we want - if(pmt_eq(port_id, d_cs->port_symbol())) { + if(pmt_eq(port_id, d_cs->port_symbol()) + && pmt_eqv(event, s_cmd_usrp_rx_start_reading)) { if(verbose) - std::cout << "[USRP_RX_STUB] Starting...\n"; + std::cout << "[USRP_RX_STUB] Starting with decim @ " + << d_decim_rx << std::endl; - if(pmt_eqv(event, s_cmd_usrp_rx_start_reading)) - read_and_respond(data); + start_packet_timer(); } } +// Setup a periodic timer which will drive packet generation void -usrp_rx_stub::read_and_respond(pmt_t data) +usrp_rx_stub::start_packet_timer() { + d_t0 = mb_time::time(); // current time + + // Calculate the inter-packet arrival time. + double samples_per_sec = (64.0/(double)d_decim_rx)*1000000.0; + double frames_per_sec = samples_per_sec / (double)d_samples_per_frame; + double frame_rate = 1.0 / frames_per_sec; + + if(verbose) { + std::cout << "[USRP_RX_STUB] Scheduling periodic packet generator\n"; + std::cout << "\tsamples_per_sec: " << samples_per_sec << std::endl; + std::cout << "\tframes_per_sec: " << frames_per_sec << std::endl; + std::cout << "\tframe_rate: " << frame_rate << std::endl; + } - while(!usrp_rx_stop) { + schedule_periodic_timeout(d_t0 + frame_rate, mb_time(frame_rate), PMT_T); +} - long nsamples_this_frame = d_samples_per_frame; +void +usrp_rx_stub::read_and_respond() +{ - size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q - long channel = 0; - long n_bytes = nshorts*2; - pmt_t uvec = pmt_make_s16vector(nshorts, 0); - size_t ignore; - int16_t *samples = pmt_s16vector_writeable_elements(uvec, ignore); + long nsamples_this_frame = d_samples_per_frame; - // fill in the complex sinusoid + size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q + long channel = 0; + long n_bytes = nshorts*2; + pmt_t uvec = pmt_make_s16vector(nshorts, 0); + size_t ignore; + int16_t *samples = pmt_s16vector_writeable_elements(uvec, ignore); - for (int i = 0; i < nsamples_this_frame; i++){ + // fill in the complex sinusoid - if (1){ - gr_complex s; - d_nco.sincos(&s, 1, d_amplitude); - // write 16-bit i & q - samples[2*i] = (int16_t) s.real(); - samples[2*i+1] = (int16_t) s.imag(); - } - else { - gr_complex s(d_amplitude, d_amplitude); + for (int i = 0; i < nsamples_this_frame; i++){ - // write 16-bit i & q - samples[2*i] = (int16_t) s.real(); - samples[2*i+1] = (int16_t) s.imag(); - } + if (1){ + gr_complex s; + d_nco.sincos(&s, 1, d_amplitude); + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); } - - if(d_disk_write) - d_ofile.write((const char *)samples, n_bytes); - - pmt_t v_pkt = pmt_make_u8vector(sizeof(transport_pkt), 0); - transport_pkt *pkt = - (transport_pkt *) pmt_u8vector_writeable_elements(v_pkt, ignore); + else { + gr_complex s(d_amplitude, d_amplitude); - pkt->set_header(0, channel, 0, n_bytes); - pkt->set_timestamp(0xffffffff); - memcpy(pkt->payload(), samples, n_bytes); - - d_cs->send(s_response_usrp_rx_read, pmt_list3(PMT_NIL, PMT_T, v_pkt)); - - // Now lets check the shared CS queue between the TX and RX stub. Each - // element in a queue is a list where the first element is an invocation - // handle and the second element is a PMT u8 vect representation of the - // CS packet response which can just be passed transparently. - while(!d_cs_queue.empty()) { - - pmt_t cs_pkt = d_cs_queue.front(); - d_cs_queue.pop(); - - pmt_t invocation_handle = pmt_nth(0, cs_pkt); - pmt_t v_pkt = pmt_nth(1, cs_pkt); - - d_cs->send(s_response_usrp_rx_read, - pmt_list3(invocation_handle, - PMT_T, - v_pkt)); // Take the front CS pkt - - - if(verbose) - std::cout << "[USRP_RX_STUB] Received CS response from TX stub\n"; + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); } - } - usrp_rx_stop = false; + if(d_disk_write) + d_ofile.write((const char *)samples, n_bytes); + + pmt_t v_pkt = pmt_make_u8vector(sizeof(transport_pkt), 0); + transport_pkt *pkt = + (transport_pkt *) pmt_u8vector_writeable_elements(v_pkt, ignore); + + pkt->set_header(0, channel, 0, n_bytes); + pkt->set_timestamp(0xffffffff); + memcpy(pkt->payload(), samples, n_bytes); + + d_cs->send(s_response_usrp_rx_read, pmt_list3(PMT_NIL, PMT_T, v_pkt)); - if(verbose) - std::cout << "[USRP_RX_STUB] Got fake RX stop\n"; + // Now lets check the shared CS queue between the TX and RX stub. Each + // element in a queue is a list where the first element is an invocation + // handle and the second element is a PMT u8 vect representation of the + // CS packet response which can just be passed transparently. + while(!d_cs_queue.empty()) { + + pmt_t cs_pkt = d_cs_queue.front(); + d_cs_queue.pop(); + + pmt_t invocation_handle = pmt_nth(0, cs_pkt); + pmt_t v_pkt = pmt_nth(1, cs_pkt); + + d_cs->send(s_response_usrp_rx_read, + pmt_list3(invocation_handle, + PMT_T, + v_pkt)); // Take the front CS pkt + + + if(verbose) + std::cout << "[USRP_RX_STUB] Received CS response from TX stub\n"; + } } diff --git a/usrp/host/lib/inband/usrp_rx_stub.h b/usrp/host/lib/inband/usrp_rx_stub.h index 5a75bf00a..9cf308a99 100644 --- a/usrp/host/lib/inband/usrp_rx_stub.h +++ b/usrp/host/lib/inband/usrp_rx_stub.h @@ -31,9 +31,12 @@ typedef usrp_inband_usb_packet transport_pkt; -extern bool usrp_rx_stop; // used to communicate a 'stop' to the RX stub +extern bool usrp_rx_stop_stub; // used to communicate a 'stop' to the RX stub extern std::queue<pmt_t> d_cs_queue; +static pmt_t s_timeout = pmt_intern("%timeout"); +static pmt_t s_done = pmt_intern("done"); + /*! * \brief Implements the low level usb interface to the USRP */ @@ -45,6 +48,10 @@ class usrp_rx_stub : public mb_mblock usrp_standard_rx* d_urx; long d_samples_per_frame; + long d_decim_rx; + + mb_time d_t0; + double d_delta_t; // for generating sine wave output ui_nco<float,float> d_nco; @@ -61,8 +68,9 @@ class usrp_rx_stub : public mb_mblock void handle_message(mb_message_sptr msg); private: - void read_and_respond(pmt_t data); + void read_and_respond(); void read_data(); + void start_packet_timer(); }; diff --git a/usrp/host/lib/inband/usrp_server.cc b/usrp/host/lib/inband/usrp_server.cc index 1948a43b2..6a3643e56 100644 --- a/usrp/host/lib/inband/usrp_server.cc +++ b/usrp/host/lib/inband/usrp_server.cc @@ -29,6 +29,8 @@ #include <vector> #include <usrp_usb_interface.h> #include <string.h> +#include <fpga_regs_common.h> +#include <fpga_regs_standard.h> #include <symbols_usrp_server_cs.h> #include <symbols_usrp_channel.h> @@ -53,13 +55,42 @@ str(long x) usrp_server::usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg) : mb_mblock(rt, instance_name, user_arg), + d_fpga_debug(false), + d_interp_tx(128), // these should match the lower level defaults (rx also) + d_decim_rx(128), d_fake_rx(false) { if(verbose) std::cout << "[USRP_SERVER] Initializing...\n"; // Dictionary for arguments to all of the components - pmt_t usrp_dict = user_arg; + d_usrp_dict = user_arg; + + if (pmt_is_dict(d_usrp_dict)) { + + if(pmt_t fpga_debug = pmt_dict_ref(d_usrp_dict, + pmt_intern("fpga-debug"), + PMT_NIL)) { + if(pmt_eqv(fpga_debug, PMT_T)) + d_fpga_debug=true; + } + + // Read the TX interpolations + if(pmt_t interp_tx = pmt_dict_ref(d_usrp_dict, + pmt_intern("interp-tx"), + PMT_NIL)) { + if(!pmt_eqv(interp_tx, PMT_NIL)) + d_interp_tx = pmt_to_long(interp_tx); + } + + // Read the RX decimation rate + if(pmt_t decim_rx = pmt_dict_ref(d_usrp_dict, + pmt_intern("decim-rx"), + PMT_NIL)) { + if(!pmt_eqv(decim_rx, PMT_NIL)) + d_decim_rx = pmt_to_long(decim_rx); + } + } // control & status port d_cs = define_port("cs", "usrp-server-cs", true, mb_port::EXTERNAL); @@ -82,7 +113,7 @@ usrp_server::usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t mb_port::EXTERNAL)); } - define_component("usrp", "usrp_usb_interface", usrp_dict); + define_component("usrp", "usrp_usb_interface", d_usrp_dict); connect("self", "cs_usrp", "usrp", "cs"); d_defer=false; @@ -108,6 +139,10 @@ usrp_server::usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t //d_fake_rx=true; } +/*! + * \brief resets the assigned capacity and owners of each RX and TX channel from + * allocations. + */ void usrp_server::reset_channels() { @@ -136,6 +171,11 @@ usrp_server::initial_transition() // the initial transition } +/*! + * \brief Reads all incoming messages to USRP server from the TX, RX, and the CS + * ports. This drives the state of USRP server and dispatches based on the + * message. + */ void usrp_server::handle_message(mb_message_sptr msg) { @@ -178,6 +218,9 @@ usrp_server::handle_message(mb_message_sptr msg) pmt_t status = pmt_nth(1, data); d_cs->send(s_response_open, pmt_list2(invocation_handle, status)); + //reset_all_registers(); + //initialize_registers(); + if(pmt_eqv(status,PMT_T)) { d_opened = true; d_defer = false; @@ -209,7 +252,7 @@ usrp_server::handle_message(mb_message_sptr msg) // Do not report back responses if they were generated from a // command packet - if(channel == 0x1f) + if(channel == CONTROL_CHAN) return; // Find the port through the owner of the channel @@ -470,7 +513,14 @@ usrp_server::handle_message(mb_message_sptr msg) std::cout << "[USRP_SERVER] unhandled msg: " << msg << std::endl; } -// Return -1 if it is not an RX port, or an index +/*! + * \brief Takes a port_symbol() as parameter \p port_id and is used to determine + * if the port is a TX port, or to find an index in the d_tx vector which stores + * the port. + * + * \returns -1 if \p port_id is not in the d_tx vector (i.e., it's not a TX + * port), otherwise returns an index in the d_tx vector which stores the port. + */ int usrp_server::tx_port_index(pmt_t port_id) { for(int i=0; i < (int) d_tx.size(); i++) @@ -480,7 +530,14 @@ int usrp_server::tx_port_index(pmt_t port_id) { return -1; } -// Return -1 if it is not an RX port, or an index +/*! + * \brief Takes a port_symbol() as parameter \p port_id and is used to determine + * if the port is an RX port, or to find an index in the d_rx vector which + * stores the port. + * + * \returns -1 if \p port_id is not in the d_rx vector (i.e., it's not an RX + * port), otherwise returns an index in the d_rx vector which stores the port. + */ int usrp_server::rx_port_index(pmt_t port_id) { for(int i=0; i < (int) d_rx.size(); i++) @@ -490,8 +547,12 @@ int usrp_server::rx_port_index(pmt_t port_id) { return -1; } -// Go through all TX and RX channels, sum up the assigned capacity -// and return it +/*! + * \brief Determines the current total capacity allocated by all RX and TX + * channels. + * + * \returns the total allocated capacity + */ long usrp_server::current_capacity_allocation() { long capacity = 0; @@ -504,6 +565,14 @@ long usrp_server::current_capacity_allocation() { return capacity; } + +/*! + * \brief Called by the handle_message() method if the incoming message to + * usrp_server is to allocate a channel (cmd-allocate-channel). The method + * checks if the requested capacity exists and if so it will reserve it for the + * caller on the channel that is returned via a response-allocate-channel + * signal. + */ void usrp_server::handle_cmd_allocate_channel( mb_port_sptr port, @@ -564,9 +633,13 @@ usrp_server::handle_cmd_allocate_channel( return; } -// Check the port type and deallocate assigned capacity based on this, ensuring -// that the owner of the method invocation is the owner of the port and that the -// channel number is valid. +/*! + * \brief Called by the handle_message() method if the incoming message to + * usrp_server is to deallocate a channel (cmd-deallocate-channel). The method + * ensures that the sender of the signal owns the channel and that the channel + * number is valid. A response-deallocate-channel signal is sent back with the + * result of the deallocation. + */ void usrp_server::handle_cmd_deallocate_channel( mb_port_sptr port, @@ -591,8 +664,26 @@ usrp_server::handle_cmd_deallocate_channel( return; } -void usrp_server::handle_cmd_xmit_raw_frame(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data) { - +/*! + * \brief Called by the handle_message() method if the incoming message to + * usrp_server is to transmit a frame (cmd-xmit-raw-frame). The method + * allocates enough memory to support a burst of packets which contain the frame + * over the bus of the frame, sets the packet headers, and sends a signal to the + * lower block for the data (packets) to be written to the bus. + * + * The \p port the command was sent on and the channel info (\p chan_info) of + * the channel the frame is to be transmitted on are passed to ensure that the + * caller owns the channel. + * + * The \p data parameter is in the format of a cmd-xmit-raw-frame signal. + * + * The properties + */ +void usrp_server::handle_cmd_xmit_raw_frame( + mb_port_sptr port, + std::vector<struct channel_info> &chan_info, + pmt_t data) +{ size_t n_bytes, psize; long max_payload_len = transport_pkt::max_payload(); @@ -667,7 +758,8 @@ void usrp_server::handle_cmd_xmit_raw_frame(mb_port_sptr port, std::vector<struc << invocation_handle << std::endl; // The actual response to the write will be generated by a - // s_response_usrp_write + // s_response_usrp_write since we cannot determine whether to transmit was + // successful until we hear from the lower layers. d_cs_usrp->send(s_cmd_usrp_write, pmt_list3(invocation_handle, pmt_from_long(channel), @@ -676,7 +768,29 @@ void usrp_server::handle_cmd_xmit_raw_frame(mb_port_sptr port, std::vector<struc return; } -void usrp_server::handle_cmd_to_control_channel(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data) +/*! + * \brief Called by the handle_message() method to parse incoming control/status + * signals (cmd-to-control-channel). + * + * The \p port the command was sent on and the channel info (\p chan_info) of + * the channel are passed to ensure that the caller owns the channel. + * + * The \p data parameter is in the format of a PMT list, where each element + * follows the format of a control/status signal (i.e. op-ping-fixed). + * + * The method will parse all of the C/S commands included in \p data and place + * the commands in to a lower level packet sent to the control channel. The + * method will pack as many commands as possible in t oa single packet, and once + * it is fill generate as many lower level packets as needed. + * + * Anything that needs to be returned to the sender of the signal (i.e. the + * value of a register) will be generated by the parse_control_pkt() method as + * the responses to the commands are read back from the USRP. + */ +void usrp_server::handle_cmd_to_control_channel( + mb_port_sptr port, + std::vector<struct channel_info> &chan_info, + pmt_t data) { pmt_t invocation_handle = pmt_nth(0, data); @@ -687,7 +801,10 @@ void usrp_server::handle_cmd_to_control_channel(mb_port_sptr port, std::vector<s size_t psize; long payload_len = 0; - long channel = 0x1f; + long channel = CONTROL_CHAN; + + if(verbose) + std::cout << "[USRP_SERVER] Handling " << n_subpkts << " commands\n"; // The design of the following code is optimized for simplicity, not // performance. To performance optimize this code, the total size in bytes @@ -990,8 +1107,22 @@ void usrp_server::handle_cmd_to_control_channel(mb_port_sptr port, std::vector<s return; } +/*! + * \brief Called by the handle_message() method when the incoming signal is a + * command to start reading samples from the USRP (cmd-start-recv-raw-samples). + * + * The \p port the command was sent on and the channel info (\p chan_info) of + * the channel are passed to ensure that the caller owns the channel. + * + * The \p data parameter should be in the format of a cmd-start-recv-raw-samples + * command where the first element in the list is an invocation handle, and the + * second is the channel the signal generator wants to receive the samples on. + */ void -usrp_server::handle_cmd_start_recv_raw_samples(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data) +usrp_server::handle_cmd_start_recv_raw_samples( + mb_port_sptr port, + std::vector<struct channel_info> &chan_info, + pmt_t data) { pmt_t invocation_handle = pmt_nth(0, data); long channel = pmt_to_long(pmt_nth(1, data)); @@ -1032,6 +1163,18 @@ usrp_server::handle_cmd_start_recv_raw_samples(mb_port_sptr port, std::vector<st return; } +/*! + * \brief Called by the handle_message() method when the incoming signal is to + * stop receiving samples from the USRP (cmd-stop-recv-raw-samples). + * + * The \p port the command was sent on and the channel info (\p chan_info) of + * the channel are passed to ensure that the caller owns the channel. + * + * The \p data parameter should be in the format of a cmd-stop-recv-raw-samples + * command where the first element in the list is an invocation handle, and the + * second is the channel the signal generator wants to stop receiving the + * samples from. + */ void usrp_server::handle_cmd_stop_recv_raw_samples( mb_port_sptr port, @@ -1067,7 +1210,22 @@ usrp_server::handle_cmd_stop_recv_raw_samples( return; } -// Read the packet header, determine the port by the channel owner +/*! + * \brief Called by the handle_message() method when an incoming signal is + * generated to USRP server that contains raw samples from the USRP. This + * method generates the response-recv-raw-samples signals that are the result of + * a cmd-start-recv-raw-samples signal. + * + * The raw lower-level packet is extracted from \p data, where the format for \p + * data is a PMT list. The PMT \p data list should contain an invocation handle + * as the first element, the status of the lower-level read as the second + * element, and a uniform vector representation of the packets as the third + * element. + * + * The packet contains a channel field that the samples are destined to, and the + * method determines where to send the samples based on this channel since each + * channel has an associated port which allocated it. + */ void usrp_server::handle_response_usrp_read(pmt_t data) { @@ -1106,7 +1264,7 @@ usrp_server::handle_response_usrp_read(pmt_t data) return; // If the packet is a C/S packet, parse it separately - if(channel == 0x1f) { + if(channel == CONTROL_CHAN) { parse_control_pkt(invocation_handle, pkt); return; } @@ -1137,14 +1295,28 @@ usrp_server::handle_response_usrp_read(pmt_t data) PMT_T); d_rx[port]->send(s_response_recv_raw_samples, - pmt_list5(invocation_handle, + pmt_list6(invocation_handle, status, v_samples, pmt_from_long(pkt->timestamp()), + pmt_from_long(channel), properties)); return; } +/*! + * \brief Called by handle_response_usrp_read() when the incoming packet has a + * channel of CONTROL_CHAN. This means that the incoming packet contains a + * response for a command sent to the control channel, which this method will + * parse. + * + * The \p pkt parameter is a pointer to the full packet (transport_pkt) in + * memory. + * + * Given that all commands sent to the control channel that require responses + * will carry an RID (request ID), the method will use the RID passed back with + * the response to determine which port the response should be sent on. + */ void usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt) { @@ -1190,6 +1362,9 @@ usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt) return; pmt_t owner = d_rids[srid].owner; + + // Return the RID + d_rids[srid].owner = PMT_NIL; // FIXME: should be 1 response for all subpackets here ? if((port = tx_port_index(owner)) != -1) @@ -1225,6 +1400,9 @@ usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt) return; pmt_t owner = d_rids[srid].owner; + + // Return the RID + d_rids[srid].owner = PMT_NIL; // FIXME: should be 1 response for all subpackets here ? if((port = tx_port_index(owner)) != -1) @@ -1261,6 +1439,9 @@ usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt) return; pmt_t owner = d_rids[srid].owner; + + // Return the RID + d_rids[srid].owner = PMT_NIL; if((port = tx_port_index(owner)) != -1) d_tx[port]->send(s_response_from_control_channel, @@ -1294,6 +1475,9 @@ usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt) return; pmt_t owner = d_rids[srid].owner; + + // Return the RID + d_rids[srid].owner = PMT_NIL; if((port = tx_port_index(owner)) != -1) d_tx[port]->send(s_response_from_control_channel, @@ -1317,6 +1501,10 @@ usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt) } } +/*! + * \brief Used to recall all incoming signals that were deferred when USRP + * server was in the initialization state. + */ void usrp_server::recall_defer_queue() { @@ -1335,6 +1523,25 @@ usrp_server::recall_defer_queue() return; } +/*! + * \brief Commonly called by any method which handles outgoing frames or control + * packets to the USRP to check if the port on which the signal was sent owns + * the channel the outgoing packet will be associated with. This helps ensure + * that applications do not send data on other application's ports. + * + * The \p port parameter is the port symbol that the caller wishes to determine + * owns the channel specified by \p chan_info. + * + * The \p signal_info parameter is a PMT list containing two elements: the + * response signal to use if the permissions are invalid, and the invocation + * handle that was passed. This allows the method to generate detailed failure + * responses to signals without having to return some sort of structured + * information which the caller must then parse and interpret to determine the + * failure type. + * + * \returns true if \p port owns the channel specified by \p chan_info, false + * otherwise. + */ bool usrp_server::check_valid(mb_port_sptr port, long channel, @@ -1346,7 +1553,7 @@ usrp_server::check_valid(mb_port_sptr port, pmt_t invocation_handle = pmt_nth(1, signal_info); // not a valid channel number? - if(channel >= (long)chan_info.size() && channel != 0x1f) { + if(channel >= (long)chan_info.size() && channel != CONTROL_CHAN) { port->send(response_signal, pmt_list2(invocation_handle, s_err_channel_invalid)); @@ -1377,8 +1584,12 @@ usrp_server::check_valid(mb_port_sptr port, return true; } -// Goes through the vector of RIDs and retreieves an -// available one for use +/*! + * \brief Finds the next available RID for internal USRP server use with control + * and status packets. + * + * \returns the next valid RID or -1 if no more RIDs are available. + */ long usrp_server::next_rid() { @@ -1386,7 +1597,264 @@ usrp_server::next_rid() if(pmt_eqv(d_rids[i].owner, PMT_NIL)) return i; + if(verbose) + std::cout << "[USRP_SERVER] No RIDs left\n"; return -1; } +/*! + * \brief Called by handle_message() when USRP server gets a response that the + * USRP was opened successfully to initialize the registers using the new + * register read/write control packets. + */ +void +usrp_server::initialize_registers() +{ + // We use handle_cmd_to_control_channel() to create the register writes using + // PMT_NIL as the response port to tell usrp_server not to pass the response + // up to any application. + if(verbose) + std::cout << "[USRP_SERVER] Initializing registers...\n"; + + // RX mode to normal (0) + set_register(FR_MODE, 0); + + // FPGA debugging? + if(d_fpga_debug) { + set_register(FR_DEBUG_EN, 1); + // FIXME: need to figure out exact register writes to control daughterboard + // pins that need to be written to + } else { + set_register(FR_DEBUG_EN, 0); + } + + // Set the transmit sample rate divisor, which is 4-1 + set_register(FR_TX_SAMPLE_RATE_DIV, 3); + + // Dboard IO buffer and register settings + set_register(FR_OE_0, (0xffff << 16) | 0x0000); + set_register(FR_IO_0, (0xffff << 16) | 0x0000); + set_register(FR_OE_1, (0xffff << 16) | 0x0000); + set_register(FR_IO_1, (0xffff << 16) | 0x0000); + set_register(FR_OE_2, (0xffff << 16) | 0x0000); + set_register(FR_IO_2, (0xffff << 16) | 0x0000); + set_register(FR_OE_3, (0xffff << 16) | 0x0000); + set_register(FR_IO_3, (0xffff << 16) | 0x0000); + + // zero Tx side Auto Transmit/Receive regs + set_register(FR_ATR_MASK_0, 0); + set_register(FR_ATR_TXVAL_0, 0); + set_register(FR_ATR_RXVAL_0, 0); + set_register(FR_ATR_MASK_1, 0); + set_register(FR_ATR_TXVAL_1, 0); + set_register(FR_ATR_RXVAL_1, 0); + set_register(FR_ATR_MASK_2, 0); + set_register(FR_ATR_TXVAL_2, 0); + set_register(FR_ATR_RXVAL_2, 0); + set_register(FR_ATR_MASK_3, 0); + set_register(FR_ATR_TXVAL_3, 0); + set_register(FR_ATR_RXVAL_3, 0); + + // Configure TX mux, this is a hacked value + set_register(FR_TX_MUX, 0x00000081); + + // Set the interpolation rate, which is the rate divided by 4, minus 1 + set_register(FR_INTERP_RATE, (d_interp_tx/4)-1); + + // Apparently this register changes again + set_register(FR_TX_MUX, 0x00000981); + + // Set the receive sample rate divisor, which is 2-1 + set_register(FR_RX_SAMPLE_RATE_DIV, 1); + + // DC offset + set_register(FR_DC_OFFSET_CL_EN, 0x0000000f); + + // Reset the DC correction offsets + set_register(FR_ADC_OFFSET_0, 0); + set_register(FR_ADC_OFFSET_1, 0); + + // Some hard-coded RX configuration + set_register(FR_RX_FORMAT, 0x00000300); + set_register(FR_RX_MUX, 1); + + // RX decimation rate is divided by two, then subtract 1 + set_register(FR_DECIM_RATE, (d_decim_rx/2)-1); + + // More hard coding + set_register(FR_RX_MUX, 0x000e4e41); + + // Resetting RX registers + set_register(FR_RX_PHASE_0, 0); + set_register(FR_RX_PHASE_1, 0); + set_register(FR_RX_PHASE_2, 0); + set_register(FR_RX_PHASE_3, 0); + set_register(FR_RX_FREQ_0, 0x28000000); + set_register(FR_RX_FREQ_1, 0); + set_register(FR_RX_FREQ_2, 0); + set_register(FR_RX_FREQ_3, 0); + + // Enable debug bus + set_register(FR_DEBUG_EN, 0xf); + set_register(FR_OE_0, -1); + set_register(FR_OE_1, -1); + set_register(FR_OE_2, -1); + set_register(FR_OE_3, -1); + + // DEBUGGING + //check_register_initialization(); +} + +// FIXME: used for debugging to determine if all the registers are actually +// being set correctly +void +usrp_server::check_register_initialization() +{ + // RX mode to normal (0) + read_register(FR_MODE); + + // FPGA debugging? + if(d_fpga_debug) { + read_register(FR_DEBUG_EN); + // FIXME: need to figure out exact register writes to control daughterboard + // pins that need to be written to + } else { + read_register(FR_DEBUG_EN); + } + + // Set the transmit sample rate divisor, which is 4-1 + read_register(FR_TX_SAMPLE_RATE_DIV); + + // Dboard IO buffer and register settings + read_register(FR_OE_0); + read_register(FR_IO_0); + read_register(FR_OE_1); + read_register(FR_IO_1); + read_register(FR_OE_2); + read_register(FR_IO_2); + read_register(FR_OE_3); + read_register(FR_IO_3); + + // zero Tx side Auto Transmit/Receive regs + read_register(FR_ATR_MASK_0); + read_register(FR_ATR_TXVAL_0); + read_register(FR_ATR_RXVAL_0); + read_register(FR_ATR_MASK_1); + read_register(FR_ATR_TXVAL_1); + read_register(FR_ATR_RXVAL_1); + read_register(FR_ATR_MASK_2); + read_register(FR_ATR_TXVAL_2); + read_register(FR_ATR_RXVAL_2); + read_register(FR_ATR_MASK_3); + read_register(FR_ATR_TXVAL_3); + read_register(FR_ATR_RXVAL_3); + + // Configure TX mux, this is a hacked value + read_register(FR_TX_MUX); + + // Set the interpolation rate, which is the rate divided by 4, minus 1 + read_register(FR_INTERP_RATE); + + // Apparently this register changes again + read_register(FR_TX_MUX); + + // Set the receive sample rate divisor, which is 2-1 + read_register(FR_RX_SAMPLE_RATE_DIV); + + // DC offset + read_register(FR_DC_OFFSET_CL_EN); + + // Reset the DC correction offsets + read_register(FR_ADC_OFFSET_0); + read_register(FR_ADC_OFFSET_1); + + // Some hard-coded RX configuration + read_register(FR_RX_FORMAT); + read_register(FR_RX_MUX); + + // RX decimation rate is divided by two, then subtract 1 + read_register(FR_DECIM_RATE); + + // More hard coding + read_register(FR_RX_MUX); + + // Resetting RX registers + read_register(FR_RX_PHASE_0); + read_register(FR_RX_PHASE_1); + read_register(FR_RX_PHASE_2); + read_register(FR_RX_PHASE_3); + read_register(FR_RX_FREQ_0); + read_register(FR_RX_FREQ_1); + read_register(FR_RX_FREQ_2); + read_register(FR_RX_FREQ_3); +} + +/*! + * \brief Used to generate FPGA register write commands to reset all of the FPGA + * registers to a value of 0. + */ +void +usrp_server::reset_all_registers() +{ + for(int i=0; i<64; i++) + set_register(i, 0); +} + +/*! + * \brief Used internally by USRP server to generate a control/status packet + * which contains a register write. + * + * The \p reg parameter is the register number that the value \p val will be + * written to. + */ +void +usrp_server::set_register(long reg, long val) +{ + size_t psize; + long payload_len = 0; + + pmt_t v_packet = pmt_make_u8vector(sizeof(transport_pkt), 0); + transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writeable_elements(v_packet, psize); + + pkt->set_header(0, CONTROL_CHAN, 0, payload_len); + pkt->set_timestamp(0xffffffff); + + pkt->cs_write_reg(reg, val); + + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(PMT_NIL, + pmt_from_long(CONTROL_CHAN), + v_packet)); +} + +/*! + * \brief Used internally by USRP server to generate a control/status packet + * which contains a register read. This is important to use internally so that + * USRP server can bypass the use of RIDs with register reads, as they are not + * needed and it would use up the finite number of RIDs available for use for + * applications to receive responses. + * + * The \p reg parameter is the register number that the value should be read + * from. + */ +void +usrp_server::read_register(long reg) +{ + size_t psize; + long payload_len = 0; + + pmt_t v_packet = pmt_make_u8vector(sizeof(transport_pkt), 0); + transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writeable_elements(v_packet, psize); + + pkt->set_header(0, CONTROL_CHAN, 0, payload_len); + pkt->set_timestamp(0xffffffff); + + pkt->cs_read_reg(0, reg); + + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(PMT_NIL, + pmt_from_long(CONTROL_CHAN), + v_packet)); +} + REGISTER_MBLOCK_CLASS(usrp_server); diff --git a/usrp/host/lib/inband/usrp_server.h b/usrp/host/lib/inband/usrp_server.h index 81dceb1f4..09c82faac 100644 --- a/usrp/host/lib/inband/usrp_server.h +++ b/usrp/host/lib/inband/usrp_server.h @@ -51,6 +51,13 @@ public: long d_ntx_chan; long d_nrx_chan; + pmt_t d_usrp_dict; + + bool d_fpga_debug; + + long d_interp_tx; + long d_decim_rx; + // Keep track of the request IDs struct rid_info { pmt_t owner; @@ -114,6 +121,11 @@ private: bool check_valid(mb_port_sptr port, long channel, std::vector<struct channel_info> &chan_info, pmt_t signal_info); void parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt); long next_rid(); + void initialize_registers(); + void set_register(long reg, long val); + void read_register(long reg); + void check_register_initialization(); + void reset_all_registers(); }; #endif /* INCLUDED_USRP_SERVER_H */ diff --git a/usrp/host/lib/inband/usrp_server.mbh b/usrp/host/lib/inband/usrp_server.mbh index 3fd0db139..ed7943fc3 100644 --- a/usrp/host/lib/inband/usrp_server.mbh +++ b/usrp/host/lib/inband/usrp_server.mbh @@ -202,7 +202,7 @@ (:incoming - (response-recv-raw-samples invocation-handle status samples timestamp properties) + (response-recv-raw-samples invocation-handle status samples timestamp channel properties) ;; samples is a uniform numeric vector. The contents of the sample ;; vector is treated as opaque and is passed from the FPGA diff --git a/usrp/host/lib/inband/usrp_tx.cc b/usrp/host/lib/inband/usrp_tx.cc index a7a5e4a89..da8777513 100644 --- a/usrp/host/lib/inband/usrp_tx.cc +++ b/usrp/host/lib/inband/usrp_tx.cc @@ -66,6 +66,10 @@ usrp_tx::initial_transition() } +/*! + * \brief Handles incoming signals to to the m-block, wihch should only ever be + * a single message: cmd-usrp-tx-write. + */ void usrp_tx::handle_message(mb_message_sptr msg) { @@ -82,6 +86,14 @@ usrp_tx::handle_message(mb_message_sptr msg) } } +/*! + * \brief Performs the actual writing of data to the USB bus, called by + * handle_message() when a cmd-usrp-tx-write signal is received. + * + * The \p data parameter is a PMT list which contains three mandatory elements, + * in the following order: an invocation handle, a channel, and a uniform vector + * of memory which contains the packets to be written to the bus. + */ void usrp_tx::write(pmt_t data) { @@ -121,7 +133,7 @@ usrp_tx::write(pmt_t data) for(int i=0; i < n_packets; i++) { if(d_disk_write) { - if(pkts[i].chan() == 0x1f) + if(pkts[i].chan() == CONTROL_CHAN) d_cs_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size()); else d_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size()); diff --git a/usrp/host/lib/inband/usrp_tx_stub.cc b/usrp/host/lib/inband/usrp_tx_stub.cc index 7a9876322..6cff3b4ee 100644 --- a/usrp/host/lib/inband/usrp_tx_stub.cc +++ b/usrp/host/lib/inband/usrp_tx_stub.cc @@ -103,7 +103,7 @@ usrp_tx_stub::write(pmt_t data) for(long i=0; i<n_packets; i++) { if(d_disk_write) { - if(pkts[i].chan() == 0x1f) + if(pkts[i].chan() == CONTROL_CHAN) d_cs_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size()); else d_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size()); @@ -112,7 +112,7 @@ usrp_tx_stub::write(pmt_t data) d_ofile.flush(); } - if(pkts[i].chan() == 0x1f) + if(pkts[i].chan() == CONTROL_CHAN) parse_cs(invocation_handle, pkts[i]); } @@ -140,7 +140,7 @@ usrp_tx_stub::parse_cs(pmt_t invocation_handle, transport_pkt pkt) transport_pkt *q_pkt = (transport_pkt *) pmt_u8vector_writeable_elements(v_pkt, ignore); - q_pkt->set_header(0, 0x1f, 0, 0); + q_pkt->set_header(0, CONTROL_CHAN, 0, 0); q_pkt->set_timestamp(0xffffffff); // We dispatch based on the control packet type, however we can extract the diff --git a/usrp/host/lib/inband/usrp_usb_interface.cc b/usrp/host/lib/inband/usrp_usb_interface.cc index 269ed2706..51b6d4646 100644 --- a/usrp/host/lib/inband/usrp_usb_interface.cc +++ b/usrp/host/lib/inband/usrp_usb_interface.cc @@ -47,12 +47,16 @@ static pmt_t s_shutdown = pmt_intern("%shutdown"); static const bool verbose = false; - -// need to take number of TX and RX channels as parameter +/*! + * \brief Initializes the USB interface m-block. + * + * The \p user_arg should be a PMT dictionary which can contain optional + * arguments for the block, such as the decimatoin and interpolation rate. + */ usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg) : mb_mblock(rt, instance_name, user_arg), - d_fpga_debug(false), d_fake_usrp(false), + d_rx_reading(false), d_interp_tx(128), d_decim_rx(128), d_rf_freq(10e6), @@ -86,7 +90,7 @@ usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instan d_interp_tx = pmt_to_long(interp_tx); } - // Read the RX interpolations + // Read the RX decimation rate if(pmt_t decim_rx = pmt_dict_ref(usrp_dict, pmt_intern("decim-rx"), PMT_NIL)) { @@ -134,8 +138,8 @@ usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instan d_tx_cs = define_port("tx_cs", "usrp-tx-cs", false, mb_port::INTERNAL); // Connect to TX and RX - define_component("tx", tx_interface, PMT_F); - define_component("rx", rx_interface, PMT_F); + define_component("tx", tx_interface, usrp_dict); + define_component("rx", rx_interface, usrp_dict); connect("self", "rx_cs", "rx", "cs"); connect("self", "tx_cs", "tx", "cs"); @@ -146,8 +150,6 @@ usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instan d_utx = NULL; d_urx = NULL; - d_fpga_debug=true; // WARNING: DO NOT ENABLE WITH D'BOARDS OTHER THAN BASIC TX/RX - } usrp_usb_interface::~usrp_usb_interface() @@ -161,6 +163,10 @@ usrp_usb_interface::initial_transition() } +/*! + * \brief Handles all incoming signals to the block from the lowest m-blocks + * which read/write to the bus, or the higher m-block which is the USRP server. + */ void usrp_usb_interface::handle_message(mb_message_sptr msg) { @@ -256,6 +262,13 @@ usrp_usb_interface::handle_message(mb_message_sptr msg) std::cout << "[USRP_USB_INTERFACE] unhandled msg: " << msg << std::endl; } +/*! + * \brief Called by the handle_message() method when the incoming signal is to + * open a USB connection to the USRP (cmd-usrp-open). + * + * The \p data parameter is a PMT list, where the elements are an invocation + * handle and the USRP number. + */ void usrp_usb_interface::handle_cmd_open(pmt_t data) { @@ -290,7 +303,7 @@ usrp_usb_interface::handle_cmd_open(pmt_t data) return; } - if(!d_utx->set_tx_freq (0,d_rf_freq)) { // try setting center freq to 0 + 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 if (verbose) std::cout << "[USRP_USB_INTERFACE] Failed to set center frequency on TX\n"; reply_data = pmt_list2(invocation_handle, PMT_F); @@ -298,6 +311,14 @@ usrp_usb_interface::handle_cmd_open(pmt_t data) return; } + if(!d_utx->set_mux(0xBA98)) { + if (verbose) + std::cout << "[USRP_USB_INTERFACE] Failed to set TX mux\n"; + reply_data = pmt_list2(invocation_handle, PMT_F); + d_cs->send(s_response_usrp_open, reply_data); + return; + } + d_utx->start(); if (verbose) @@ -321,33 +342,44 @@ usrp_usb_interface::handle_cmd_open(pmt_t data) return; } - if(!d_urx->set_rx_freq (0, d_rf_freq)) { + if(!d_urx->set_rx_freq (0, -d_rf_freq) || !d_urx->set_rx_freq(1, -d_rf_freq)) { if (verbose) std::cout << "[usrp_server] Failed to set center frequency on RX\n"; reply_data = pmt_list2(invocation_handle, PMT_F); d_cs->send(s_response_usrp_open, reply_data); return; } - - if(d_fpga_debug) { - d_utx->_write_fpga_reg(FR_DEBUG_EN,0xf); - d_utx->_write_oe(0, 0xffff, 0xffff); - d_urx->_write_oe(0, 0xffff, 0xffff); - d_utx->_write_oe(1, 0xffff, 0xffff); - d_urx->_write_oe(1, 0xffff, 0xffff); - -// while(1){ -// for(int i=0; i<0xffff; i++) -// d_urx->write_io(0, i, 0xffff); -// } - } + // Two channels ... this really needs to end up being set correctly by + // querying for what dboards are connected + if(!d_urx->set_mux(0x32103210)) { + if (verbose) + std::cout << "[USRP_USB_INTERFACE] Failed to set RX mux\n"; + reply_data = pmt_list2(invocation_handle, PMT_F); + d_cs->send(s_response_usrp_open, reply_data); + return; + } + if (verbose) std::cout << "[USRP_USB_INTERFACE] Setup RX channel\n"; + +// d_utx->_write_fpga_reg(FR_DEBUG_EN,0xf); +// d_utx->_write_oe(0, 0xffff, 0xffff); +// d_urx->_write_oe(0, 0xffff, 0xffff); +// d_utx->_write_oe(1, 0xffff, 0xffff); +// d_urx->_write_oe(1, 0xffff, 0xffff); d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T)); } +/*! + * \brief Called by the handle_message() method when the incoming signal is to + * write data to the USB bus (cmd-usrp-write). + * + * The \p data parameter is a PMT list containing 3 mandatory elements in the + * following order: an invocation handle, channel, and a uniform vector + * representation of the packets. + */ void usrp_usb_interface::handle_cmd_write(pmt_t data) { @@ -366,6 +398,13 @@ usrp_usb_interface::handle_cmd_write(pmt_t data) return; } +/*! + * \brief Called by the handle_message() method when the incoming signal is to + * start reading data from the USB bus (cmd-usrp-start-reading). + * + * The \p data parameter is a PMT list with a single element: an invocation + * handle which can be returned with the response. + */ void usrp_usb_interface::handle_cmd_start_reading(pmt_t data) { @@ -381,9 +420,18 @@ usrp_usb_interface::handle_cmd_start_reading(pmt_t data) d_rx_cs->send(s_cmd_usrp_rx_start_reading, pmt_list2(PMT_NIL, rx_handle)); + d_rx_reading = true; + return; } +/*! + * \brief Called by the handle_message() method when the incoming signal is to + * stop reading data from the USB bus (cmd-usrp-stop-reading). + * + * The \p data parameter is a PMT list with a single element: an invocation + * handle which can be returned with the response. + */ void usrp_usb_interface::handle_cmd_stop_reading(pmt_t data) { @@ -392,22 +440,40 @@ usrp_usb_interface::handle_cmd_stop_reading(pmt_t data) if(!d_fake_usrp) { if(verbose) std::cout << "[USRP_USB_INTERFACE] Stopping RX...\n"; + usrp_rx_stop = true; + + // Used to allow a read() being called by a lower layer to complete before + // stopping, else there can be partial data left on the bus and can generate + // errors. + while(usrp_rx_stop) {usleep(1);} d_urx->stop(); } else { if(verbose) std::cout << "[USRP_USB_INTERFACE] Stopping fake RX...\n"; - usrp_rx_stop = true; // extern to communicate with stub to wait + usrp_rx_stop_stub = true; // extern to communicate with stub to wait } + d_rx_reading = false; + return; } +/*! + * \brief Called by the handle_message() method when the incoming signal is to + * close the USB connection to the USRP. + * + * The \p data parameter is a PMT list with a single element: an invocation + * handle which can be returned with the response. + */ void usrp_usb_interface::handle_cmd_close(pmt_t data) { pmt_t invocation_handle = pmt_nth(0, data); + if(d_rx_reading) + handle_cmd_stop_reading(PMT_NIL); + if(d_fake_usrp) { d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T)); return; diff --git a/usrp/host/lib/inband/usrp_usb_interface.h b/usrp/host/lib/inband/usrp_usb_interface.h index 8efce2ff6..6c2c15768 100644 --- a/usrp/host/lib/inband/usrp_usb_interface.h +++ b/usrp/host/lib/inband/usrp_usb_interface.h @@ -42,10 +42,10 @@ class usrp_usb_interface : public mb_mblock long d_ntx_chan; long d_nrx_chan; - long d_fpga_debug; - bool d_fake_usrp; + bool d_rx_reading; + long d_interp_tx; long d_decim_rx; diff --git a/usrp/host/lib/legacy/fusb_linux.cc b/usrp/host/lib/legacy/fusb_linux.cc index 60687a149..6dce8d9e0 100644 --- a/usrp/host/lib/legacy/fusb_linux.cc +++ b/usrp/host/lib/legacy/fusb_linux.cc @@ -386,14 +386,6 @@ fusb_ephandle_linux::stop () { if (!d_started) return true; - - d_devhandle->_cancel_pending_rqsts (this); - d_devhandle->_reap (false); - - - usbdevfs_urb *urb; - while ((urb = completed_list_get ()) != 0) - free_list_add (urb); if (d_write_work_in_progress){ free_list_add (d_write_work_in_progress); @@ -407,11 +399,19 @@ fusb_ephandle_linux::stop () d_read_buffer_end = 0; } - if (d_free_list.size () != (unsigned) d_nblocks) - fprintf (stderr, "d_free_list.size () = %d, d_nblocks = %d\n", - d_free_list.size (), d_nblocks); - - assert (d_free_list.size () == (unsigned) d_nblocks); + d_devhandle->_cancel_pending_rqsts (this); + d_devhandle->_reap (false); + + while (1){ + usbdevfs_urb *urb; + while ((urb = completed_list_get ()) != 0) + free_list_add (urb); + + if (d_free_list.size () == (unsigned) d_nblocks) + break; + + d_devhandle->_reap(true); + } d_started = false; return true; |