summaryrefslogtreecommitdiff
path: root/usrp/host/lib
diff options
context:
space:
mode:
Diffstat (limited to 'usrp/host/lib')
-rw-r--r--usrp/host/lib/inband/Makefile.am7
-rw-r--r--usrp/host/lib/inband/fake_usrp.cc135
-rw-r--r--usrp/host/lib/inband/fake_usrp.h43
-rw-r--r--usrp/host/lib/inband/qa_inband_usrp_server.cc239
-rw-r--r--usrp/host/lib/inband/qa_inband_usrp_server.h2
-rw-r--r--usrp/host/lib/inband/test_usrp_inband.cc298
-rw-r--r--usrp/host/lib/inband/usrp_inband_usb_packet.cc235
-rw-r--r--usrp/host/lib/inband/usrp_inband_usb_packet.h5
-rw-r--r--usrp/host/lib/inband/usrp_rx.cc63
-rw-r--r--usrp/host/lib/inband/usrp_rx.h6
-rw-r--r--usrp/host/lib/inband/usrp_rx_stub.cc181
-rw-r--r--usrp/host/lib/inband/usrp_rx_stub.h12
-rw-r--r--usrp/host/lib/inband/usrp_server.cc512
-rw-r--r--usrp/host/lib/inband/usrp_server.h12
-rw-r--r--usrp/host/lib/inband/usrp_server.mbh2
-rw-r--r--usrp/host/lib/inband/usrp_tx.cc14
-rw-r--r--usrp/host/lib/inband/usrp_tx_stub.cc6
-rw-r--r--usrp/host/lib/inband/usrp_usb_interface.cc114
-rw-r--r--usrp/host/lib/inband/usrp_usb_interface.h4
-rw-r--r--usrp/host/lib/legacy/fusb_linux.cc26
20 files changed, 1154 insertions, 762 deletions
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;