summaryrefslogtreecommitdiff
path: root/usrp/host/lib/inband
diff options
context:
space:
mode:
Diffstat (limited to 'usrp/host/lib/inband')
-rw-r--r--usrp/host/lib/inband/Makefile.am92
-rwxr-xr-xusrp/host/lib/inband/dump_packets.py65
-rwxr-xr-xusrp/host/lib/inband/gen_test_packets.py87
-rw-r--r--usrp/host/lib/inband/qa_inband.cc35
-rw-r--r--usrp/host/lib/inband/qa_inband.h35
-rw-r--r--usrp/host/lib/inband/qa_inband_packet_prims.cc161
-rw-r--r--usrp/host/lib/inband/qa_inband_packet_prims.h41
-rw-r--r--usrp/host/lib/inband/qa_inband_usrp_server.cc455
-rw-r--r--usrp/host/lib/inband/qa_inband_usrp_server.h42
-rw-r--r--usrp/host/lib/inband/test_inband.cc36
-rw-r--r--usrp/host/lib/inband/usb_packet.py115
-rw-r--r--usrp/host/lib/inband/usrp_inband_usb_packet.h149
-rw-r--r--usrp/host/lib/inband/usrp_server.cc394
-rw-r--r--usrp/host/lib/inband/usrp_server.h82
-rw-r--r--usrp/host/lib/inband/usrp_server.mbh256
15 files changed, 2045 insertions, 0 deletions
diff --git a/usrp/host/lib/inband/Makefile.am b/usrp/host/lib/inband/Makefile.am
new file mode 100644
index 000000000..9f6a7ab62
--- /dev/null
+++ b/usrp/host/lib/inband/Makefile.am
@@ -0,0 +1,92 @@
+#
+# 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.
+#
+
+include $(top_srcdir)/Makefile.common
+
+INCLUDES = \
+ $(DEFINES) $(OMNITHREAD_INCLUDES) $(PMT_INCLUDES) $(MBLOCK_INCLUDES) \
+ $(USRP_INCLUDES) $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES)
+
+TESTS = test_inband
+
+EXTRA_DIST =
+
+lib_LTLIBRARIES = \
+ libusrp_inband.la \
+ libusrp_inband-qa.la
+
+
+# ------------------------------------------------------------------------
+# Build the inband library
+
+BUILT_SOURCES = \
+ usrp_server_mbh.cc
+
+usrp_server_mbh.cc : usrp_server.mbh
+ $(COMPILE_MBH) usrp_server.mbh usrp_server_mbh.cc
+
+libusrp_inband_la_SOURCES = \
+ $(BUILT_SOURCES) \
+ usrp_server.cc
+
+libusrp_inband_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0
+
+libusrp_inband_la_LIBADD = \
+ $(MBLOCK_LA) \
+ -lstdc++
+
+
+include_HEADERS = \
+ usrp_server.h
+
+noinst_HEADERS = \
+ qa_inband.h \
+ qa_inband_packet_prims.h \
+ qa_inband_usrp_server.h
+
+# ------------------------------------------------------------------------
+# Build the qa code in its own library
+
+libusrp_inband_qa_la_SOURCES = \
+ qa_inband.cc \
+ qa_inband_packet_prims.cc \
+ qa_inband_usrp_server.cc
+
+# magic flags
+libusrp_inband_qa_la_LDFLAGS = $(NO_UNDEFINED) -avoid-version
+
+# link against c++ standard library
+libusrp_inband_qa_la_LIBADD = \
+ libusrp_inband.la \
+ $(CPPUNIT_LIBS) \
+ -lstdc++
+
+# ------------------------------------------------------------------------
+
+noinst_PROGRAMS = \
+ test_inband
+
+test_inband_SOURCES = test_inband.cc
+test_inband_LDADD = libusrp_inband-qa.la
+
+
+MOSTLYCLEANFILES = \
+ $(BUILT_SOURCES) *~ *.pyc
+
diff --git a/usrp/host/lib/inband/dump_packets.py b/usrp/host/lib/inband/dump_packets.py
new file mode 100755
index 000000000..ea27ca515
--- /dev/null
+++ b/usrp/host/lib/inband/dump_packets.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+import sys
+import struct
+from optparse import OptionParser
+
+from usb_packet import *
+
+def dump_packet(raw_pkt, outfile, dump_payload):
+ pkt = usb_packet(raw_pkt)
+ outfile.write(pkt.decoded_flags())
+ outfile.write(' chan= %2d len= %3d timestamp= 0x%08x rssi= % 2d tag= %2d\n' % (
+ pkt.chan(), pkt.payload_len(), pkt.timestamp(), pkt.rssi(), pkt.tag()))
+ if dump_payload:
+ assert pkt.payload_len() % 4 == 0
+ shorts = struct.unpack('<%dh' % (pkt.payload_len() // 2), pkt.payload())
+ for i in range(0, len(shorts), 2):
+ outfile.write(' %6d, %6d\n' % (shorts[i], shorts[i+1]))
+
+
+def dump_packets(infile, outfile, dump_payload):
+ raw_pkt = infile.read(512)
+ while raw_pkt:
+ if len(raw_pkt) != 512:
+ sys.stderr.write("File length is not a multiple of 512 bytes")
+ raise SystemExit, 1
+
+ dump_packet(raw_pkt, outfile, dump_payload)
+ raw_pkt = infile.read(512)
+
+
+def main():
+ parser = OptionParser()
+ parser.add_option('-p', '--dump-payload', action='store_true', default=False,
+ help='dump payload in decimal and hex')
+
+ (options, files) = parser.parse_args()
+ if len(files) == 0:
+ dump_packets(sys.stdin, sys.stdout, options.dump_payload)
+ else:
+ for f in files:
+ dump_packets(open(f, "r"), sys.stdout, options.dump_payload)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/usrp/host/lib/inband/gen_test_packets.py b/usrp/host/lib/inband/gen_test_packets.py
new file mode 100755
index 000000000..1e22722d2
--- /dev/null
+++ b/usrp/host/lib/inband/gen_test_packets.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+
+import random
+import struct
+from pprint import pprint
+from usb_packet import *
+
+MAX_PAYLOAD = 504
+TIME_NOW = 0xffffffff
+
+
+class sequence_generator(object):
+ def __init__(self):
+ self.i = 0
+
+ def __call__(self):
+ t = self.i
+ self.i += 1
+ return t
+
+def gen_shuffled_lengths():
+ valid_lengths = range(0, MAX_PAYLOAD+1, 4) # [0, 4, 8, ... 504]
+ random.shuffle(valid_lengths)
+ return valid_lengths
+
+
+class packet_sequence_generator(object):
+ def __init__(self, channel, lengths):
+ self.next = sequence_generator()
+ self.channel = channel
+ self.lengths = lengths
+
+ def __call__(self, output_file):
+ gen_packet(output_file, self.channel, self.next, self.lengths[0])
+ del self.lengths[0]
+
+
+def gen_packet(output_file, channel, content_generator, payload_len):
+ assert (payload_len % 4) == 0
+ payload = []
+ n_iq = payload_len // 4
+ for n in range(n_iq):
+ payload.append(content_generator()) # I
+ payload.append(content_generator()) # Q
+ for n in range(MAX_PAYLOAD // 4 - n_iq):
+ payload.append(0x0000)
+ payload.append(0xffff)
+
+ assert (len(payload) == MAX_PAYLOAD // 2)
+
+ #print "\npayload_len =", payload_len
+ #pprint(payload)
+
+ output_file.write(make_header(FL_START_OF_BURST|FL_END_OF_BURST,
+ channel, payload_len, TIME_NOW))
+ output_file.write(struct.pack('<252h', *payload))
+
+
+def gen_all_valid_packet_lengths_1_channel(output_file):
+ lengths = gen_shuffled_lengths()
+ npkts = len(lengths) # number of packets we'll generator on each stream
+ pkt_gen_0 = packet_sequence_generator(0, lengths)
+ for i in range(npkts):
+ pkt_gen_0(output_file)
+
+ assert pkt_gen_0.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127
+
+
+def gen_all_valid_packet_lengths_2_channels(output_file):
+ lengths = gen_shuffled_lengths()
+ npkts = len(lengths) # number of packets we'll generator on each stream
+ pkt_gen_0 = packet_sequence_generator(0, lengths)
+ pkt_gen_1 = packet_sequence_generator(1, gen_shuffled_lengths())
+ pkt_gen = (pkt_gen_0, pkt_gen_1)
+
+ which_gen = (npkts * [0]) + (npkts * [1])
+ random.shuffle(which_gen)
+
+ for i in which_gen:
+ pkt_gen[i](output_file)
+
+ assert pkt_gen_0.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127
+ assert pkt_gen_1.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127
+
+if __name__ == '__main__':
+ gen_all_valid_packet_lengths_1_channel(open("all_valid_packet_lengths_1_channel.dat", "w"))
+ gen_all_valid_packet_lengths_2_channels(open("all_valid_packet_lengths_2_channels.dat", "w"))
diff --git a/usrp/host/lib/inband/qa_inband.cc b/usrp/host/lib/inband/qa_inband.cc
new file mode 100644
index 000000000..00a821f39
--- /dev/null
+++ b/usrp/host/lib/inband/qa_inband.cc
@@ -0,0 +1,35 @@
+/* -*- 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 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.
+ */
+
+#include <qa_inband.h>
+#include <qa_inband_packet_prims.h>
+#include <qa_inband_usrp_server.h>
+
+CppUnit::TestSuite *
+qa_inband::suite()
+{
+ CppUnit::TestSuite *s = new CppUnit::TestSuite("inband");
+
+ s->addTest (qa_inband_packet_prims::suite());
+ s->addTest (qa_inband_usrp_server::suite());
+
+ return s;
+}
diff --git a/usrp/host/lib/inband/qa_inband.h b/usrp/host/lib/inband/qa_inband.h
new file mode 100644
index 000000000..92386f955
--- /dev/null
+++ b/usrp/host/lib/inband/qa_inband.h
@@ -0,0 +1,35 @@
+/* -*- 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 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.
+ */
+
+#ifndef INCLUDED_QA_INBAND_H
+#define INCLUDED_QA_INBAND_H
+
+#include <cppunit/TestSuite.h>
+
+//! collect all the tests for the user server
+
+class qa_inband {
+ public:
+ //! return suite of tests for all of usrp server
+ static CppUnit::TestSuite *suite();
+};
+
+#endif /* INCLUDED_QA_INBAND_H */
diff --git a/usrp/host/lib/inband/qa_inband_packet_prims.cc b/usrp/host/lib/inband/qa_inband_packet_prims.cc
new file mode 100644
index 000000000..9d9a0c70e
--- /dev/null
+++ b/usrp/host/lib/inband/qa_inband_packet_prims.cc
@@ -0,0 +1,161 @@
+/* -*- 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 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qa_inband_packet_prims.h>
+#include <cppunit/TestAssert.h>
+#include <stdio.h>
+#include <usrp_inband_usb_packet.h> // will change on gigabit crossover
+
+typedef usrp_inband_usb_packet transport_pkt;
+
+void
+qa_inband_packet_prims::test_flags()
+{
+ transport_pkt pkt;
+
+ // Test each one of the flags while ensuring no other fields become set in the process
+ pkt.set_header(pkt.FL_START_OF_BURST,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(1, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(pkt.FL_END_OF_BURST,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(pkt.FL_OVERRUN,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(pkt.FL_UNDERRUN,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(pkt.FL_DROPPED,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ // test of all fields set
+ pkt.set_header(
+ pkt.FL_START_OF_BURST |
+ pkt.FL_END_OF_BURST |
+ pkt.FL_UNDERRUN |
+ pkt.FL_OVERRUN |
+ pkt.FL_DROPPED
+ ,0,0,0);
+ CPPUNIT_ASSERT_EQUAL(1, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(1, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+
+}
+//////////////////////////////////////////////////////////////////////
+
+void
+qa_inband_packet_prims::test_fields()
+{
+ transport_pkt pkt;
+ void * payload;
+
+ // test word0 field exclusiveness
+ //
+ // I want to test max values of each field to ensure field boundaries
+ // but these max values could change based on technology? The
+ // max payload is returned by a private method so the code is not
+ // technology dependent
+ pkt.set_header(0,16,0,0);
+ CPPUNIT_ASSERT_EQUAL(16, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+
+ pkt.set_header(0,0,8,0);
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(8, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0,pkt.payload_len());
+
+ pkt.set_header(0,0,0,pkt.max_payload());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(pkt.max_payload(), pkt.payload_len());
+
+ // test timestamp, shouldn't have to test other fields since
+ // setting the timestamp only has the ability to affect one word
+ pkt.set_timestamp(54);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(54), pkt.timestamp());
+
+ // test the payload, ensure no other fields overwritten
+ //
+ // is there a better test for this?
+ pkt.set_header(0,0,0,0);
+ payload = malloc(pkt.payload_len());
+ memset(payload, 'f', pkt.payload_len());
+ memcpy(pkt.payload(), payload, pkt.payload_len());
+ CPPUNIT_ASSERT_EQUAL(0, memcmp(pkt.payload(), payload, pkt.payload_len()));
+ CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.overrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.underrun());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.dropped());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.chan());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.tag());
+ CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len());
+ free(payload);
+
+}
+//////////////////////////////////////////////////////////////////////
diff --git a/usrp/host/lib/inband/qa_inband_packet_prims.h b/usrp/host/lib/inband/qa_inband_packet_prims.h
new file mode 100644
index 000000000..5e60c60e7
--- /dev/null
+++ b/usrp/host/lib/inband/qa_inband_packet_prims.h
@@ -0,0 +1,41 @@
+/* -*- 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 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.
+ */
+
+#ifndef QA_INBAND_PACKET_PRIMS_H
+#define QA_INBAND_PACKET_PRIMS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+class qa_inband_packet_prims : public CppUnit::TestCase {
+
+ CPPUNIT_TEST_SUITE(qa_inband_packet_prims);
+ CPPUNIT_TEST(test_flags);
+ CPPUNIT_TEST(test_fields);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ void test_flags();
+ void test_fields();
+
+};
+
+#endif /* INCLUDED_QA_INBAND_PACKET_PRIMS_H */
diff --git a/usrp/host/lib/inband/qa_inband_usrp_server.cc b/usrp/host/lib/inband/qa_inband_usrp_server.cc
new file mode 100644
index 000000000..2885a4d88
--- /dev/null
+++ b/usrp/host/lib/inband/qa_inband_usrp_server.cc
@@ -0,0 +1,455 @@
+/* -*- 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 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qa_inband_usrp_server.h>
+#include <cppunit/TestAssert.h>
+#include <stdio.h>
+#include <usrp_server.h>
+#include <mb_mblock.h>
+#include <mb_runtime.h>
+#include <mb_protocol_class.h>
+#include <mb_class_registry.h>
+#include <vector>
+#include <iostream>
+
+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");
+
+
+// ----------------------------------------------------------------------------------------------
+
+class qa_alloc_top : public mb_mblock
+{
+ mb_port_sptr d_tx;
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+
+ long d_nmsgs_to_recv;
+ long d_nrecvd;
+
+ long d_max_capacity;
+ long d_ntx_chan, d_nrx_chan;
+
+ long d_nstatus;
+ long d_nstatus_to_recv;
+
+ public:
+ qa_alloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~qa_alloc_top();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void check_message(mb_message_sptr msg);
+ void run_tests();
+};
+
+qa_alloc_top::qa_alloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_nrecvd=0;
+ d_nmsgs_to_recv = 7;
+ d_nstatus=0;
+ d_nstatus_to_recv = 3;
+
+ 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);
+
+ // Test the TX side
+ define_component("server", "usrp_server", PMT_F);
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+
+}
+
+qa_alloc_top::~qa_alloc_top(){}
+
+void
+qa_alloc_top::initial_transition()
+{
+ // Retrieve information about the USRP, then run tests
+ d_cs->send(s_cmd_max_capacity, pmt_list1(PMT_F));
+ d_cs->send(s_cmd_ntx_chan, pmt_list1(PMT_F));
+ d_cs->send(s_cmd_nrx_chan, pmt_list1(PMT_F));
+}
+
+void
+qa_alloc_top::run_tests()
+{
+ std::cout << "[qa_alloc_top] Starting tests...\n";
+ // should be able to allocate 1 byte
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+
+ // should not be able to allocate max capacity after 100 bytes were allocated
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::RQSTD_CAPACITY_UNAVAIL), pmt_from_long(d_max_capacity)));
+
+ // keep allocating a little more until all of the channels are used and test the error response
+ // we start at 1 since we've already allocated 1 channel
+ for(int i=1; i < d_ntx_chan; i++) {
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+ d_nmsgs_to_recv++;
+ }
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_UNAVAIL), pmt_from_long(1)));
+
+ // test out the same on the RX side
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::RQSTD_CAPACITY_UNAVAIL), pmt_from_long(d_max_capacity)));
+
+ for(int i=1; i < d_nrx_chan; i++) {
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+ d_nmsgs_to_recv++;
+ }
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_UNAVAIL), pmt_from_long(1)));
+
+ // when all is said and done, there should be d_ntx_chan+d_ntx_chan bytes allocated
+ d_cs->send(s_cmd_current_capacity_allocation, pmt_list1(pmt_from_long(d_ntx_chan+d_nrx_chan)));
+}
+
+void
+qa_alloc_top::handle_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+
+ if ((pmt_eq(msg->port_id(), d_tx->port_symbol())
+ || pmt_eq(msg->port_id(), d_rx->port_symbol()))
+ && pmt_eq(msg->signal(), s_response_allocate_channel))
+ check_message(msg);
+
+ if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
+
+ if(pmt_eq(msg->signal(), s_response_max_capacity)) {
+ d_max_capacity = pmt_to_long(pmt_nth(1, data));
+ std::cout << "[qa_alloc_top] USRP has max capacity of " << d_max_capacity << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_ntx_chan)) {
+ d_ntx_chan = pmt_to_long(pmt_nth(1, data));
+ std::cout << "[qa_alloc_top] USRP tx channels: " << d_ntx_chan << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_nrx_chan)) {
+ d_nrx_chan = pmt_to_long(pmt_nth(1, data));
+ std::cout << "[qa_alloc_top] USRP rx channels: " << d_nrx_chan << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) {
+ check_message(msg);
+ }
+
+ d_nstatus++;
+
+ if(d_nstatus==d_nstatus_to_recv)
+ run_tests();
+ }
+}
+
+void
+qa_alloc_top::check_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+
+ pmt_t expected_result = pmt_nth(0, data);
+ pmt_t result = pmt_nth(1, data);
+
+ d_nrecvd++;
+
+
+ if(!pmt_eqv(expected_result, result)) {
+ std::cout << "Got: " << result << " Expected: " << expected_result << "\n";
+ shutdown_all(PMT_F);
+ } else {
+ std::cout << "[qa_alloc_top] Received expected response for message " << d_nrecvd << "\n";
+ }
+
+ if(d_nrecvd == d_nmsgs_to_recv)
+ shutdown_all(PMT_T);
+}
+
+REGISTER_MBLOCK_CLASS(qa_alloc_top);
+
+// ----------------------------------------------------------------------------------------------
+
+class qa_dealloc_top : public mb_mblock
+{
+ mb_port_sptr d_tx;
+ mb_port_sptr d_rx;
+ mb_port_sptr d_cs;
+
+ long d_max_capacity;
+ long d_ntx_chan, d_nrx_chan;
+
+ long d_nstatus;
+ long d_nstatus_to_recv;
+
+ long d_nalloc_to_recv;
+ long d_nalloc_recvd;
+
+ long d_ndealloc_to_recv;
+ long d_ndealloc_recvd;
+
+ std::vector<long> d_tx_chans;
+ std::vector<long> d_rx_chans;
+
+ public:
+ qa_dealloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
+ ~qa_dealloc_top();
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+ protected:
+ void check_allocation(mb_message_sptr msg);
+ void check_deallocation(mb_message_sptr msg);
+ void allocate_max();
+ void deallocate_all();
+};
+
+qa_dealloc_top::qa_dealloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(runtime, instance_name, user_arg)
+{
+ d_ndealloc_recvd=0;
+ d_ndealloc_to_recv = 0;
+ d_nalloc_recvd=0;
+ d_nalloc_to_recv = 0;
+ d_nstatus=0;
+ d_nstatus_to_recv = 3;
+
+ 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);
+
+ // Test the TX side
+ define_component("server", "usrp_server", PMT_F);
+ connect("self", "tx0", "server", "tx0");
+ connect("self", "rx0", "server", "rx0");
+ connect("self", "cs", "server", "cs");
+}
+
+qa_dealloc_top::~qa_dealloc_top(){}
+
+void
+qa_dealloc_top::initial_transition()
+{
+ // Retrieve information about the USRP, then run tests
+ d_cs->send(s_cmd_max_capacity, pmt_list1(PMT_F));
+ d_cs->send(s_cmd_ntx_chan, pmt_list1(PMT_F));
+ d_cs->send(s_cmd_nrx_chan, pmt_list1(PMT_F));
+}
+
+void
+qa_dealloc_top::allocate_max()
+{
+ std::cout << "[qa_dealloc_top] Max allocating...\n";
+
+ // Keep allocating until we hit the maximum number of channels
+ for(int i=0; i < d_ntx_chan; i++) {
+ d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+ d_nalloc_to_recv++;
+ }
+ for(int i=0; i < d_nrx_chan; i++) {
+ d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
+ d_nalloc_to_recv++;
+ }
+}
+
+void
+qa_dealloc_top::deallocate_all() {
+
+ // Deallocate all of the channels that were allocated from allocate_max()
+ for(int i=0; i < (int)d_tx_chans.size(); i++) {
+ d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_T, pmt_from_long(d_tx_chans[i])));
+ d_ndealloc_to_recv++;
+ }
+ for(int i=0; i < (int)d_rx_chans.size(); i++) {
+ d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_T, pmt_from_long(d_rx_chans[i])));
+ d_ndealloc_to_recv++;
+ }
+
+ // Should get permission denied errors trying to re-dealloc the channels, as we no
+ // longer have permission to them after deallocating
+ for(int i=0; i < (int)d_tx_chans.size(); i++) {
+ d_tx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::PERMISSION_DENIED), pmt_from_long(d_tx_chans[i])));
+ d_ndealloc_to_recv++;
+ }
+ for(int i=0; i < (int)d_rx_chans.size(); i++) {
+ d_rx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::PERMISSION_DENIED), pmt_from_long(d_rx_chans[i])));
+ d_ndealloc_to_recv++;
+ }
+
+ // Try to deallocate a channel that doesn't exist on both sides, the last element in the vectors
+ // is the highest channel number, so we take that plus 1
+ d_ndealloc_to_recv+=2;
+ d_tx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_INVALID), pmt_from_long(d_rx_chans.back()+1)));
+ d_rx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_INVALID), pmt_from_long(d_rx_chans.back()+1)));
+
+
+ // The used capacity should be back to 0 now that we've deallocated everything
+ d_cs->send(s_cmd_current_capacity_allocation, pmt_list1(pmt_from_long(0)));
+}
+
+void
+qa_dealloc_top::handle_message(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+ if (pmt_eq(msg->port_id(), d_tx->port_symbol())
+ || pmt_eq(msg->port_id(), d_rx->port_symbol())) {
+
+ if(pmt_eq(msg->signal(), s_response_allocate_channel)) {
+ check_allocation(msg);
+ }
+
+ if(pmt_eq(msg->signal(), s_response_deallocate_channel)){
+ check_deallocation(msg);
+ }
+ }
+
+ if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
+
+ if(pmt_eq(msg->signal(), s_response_max_capacity)) {
+ d_max_capacity = pmt_to_long(pmt_nth(1, data));
+ std::cout << "[qa_dealloc_top] USRP has max capacity of " << d_max_capacity << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_ntx_chan)) {
+ d_ntx_chan = pmt_to_long(pmt_nth(1, data));
+ std::cout << "[qa_dealloc_top] USRP tx channels: " << d_ntx_chan << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_nrx_chan)) {
+ d_nrx_chan = pmt_to_long(pmt_nth(1, data));
+ std::cout << "[qa_dealloc_top] USRP rx channels: " << d_nrx_chan << "\n";
+ }
+ else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) {
+ // the final command is a capacity check which should be 0, then we shutdown
+ pmt_t expected_result = pmt_nth(0, data);
+ pmt_t result = pmt_nth(1, data);
+
+ if(pmt_eqv(expected_result, result))
+ shutdown_all(PMT_T);
+ else
+ shutdown_all(PMT_F);
+ }
+
+ d_nstatus++;
+
+ if(d_nstatus==d_nstatus_to_recv)
+ allocate_max();
+ }
+}
+
+void
+qa_dealloc_top::check_deallocation(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+
+ pmt_t expected_result = pmt_nth(0, data);
+ pmt_t result = pmt_nth(1, data);
+
+ d_ndealloc_recvd++;
+
+ if(!pmt_eqv(expected_result, result)) {
+ std::cout << "Got: " << result << " Expected: " << expected_result << "\n";
+ shutdown_all(PMT_F);
+ } else {
+ std::cout << "[qa_dealloc_top] Received expected deallocation response for message " << d_ndealloc_recvd << "\n";
+ }
+}
+
+void
+qa_dealloc_top::check_allocation(mb_message_sptr msg)
+{
+ pmt_t data = msg->data();
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ pmt_t status = pmt_nth(1, data);
+ pmt_t channel = pmt_nth(2, data);
+
+ d_nalloc_recvd++;
+
+ if(pmt_eqv(status, PMT_F)) {
+ std::cout << "[qa_dealloc_top] Unexpected error response when allocating channels\n";
+ shutdown_all(PMT_F);
+ } else {
+ // store all of the allocate channel numbers
+ if(pmt_eq(msg->port_id(), d_tx->port_symbol()))
+ d_tx_chans.push_back(pmt_to_long(channel));
+ if(pmt_eq(msg->port_id(), d_rx->port_symbol()))
+ d_rx_chans.push_back(pmt_to_long(channel));
+ }
+
+ if(d_nalloc_recvd == d_nalloc_to_recv) {
+
+ std::cout << "[qa_dealloc_top] Allocated TX channels: ";
+ for(int i=0; i < (int)d_tx_chans.size(); i++)
+ std::cout << d_tx_chans[i] << " ";
+
+ std::cout << "\n[qa_dealloc_top] Allocated RX channels: ";
+ for(int i=0; i < (int)d_rx_chans.size(); i++)
+ std::cout << d_rx_chans[i] << " ";
+ std::cout << "\n";
+
+ deallocate_all(); // once we've allocated all of our channels, try to dealloc them
+ }
+}
+
+REGISTER_MBLOCK_CLASS(qa_dealloc_top);
+
+// ----------------------------------------------------------------------------------------------
+
+void
+qa_inband_usrp_server::test_chan_allocation()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_T;
+
+ rt->run("top", "qa_alloc_top", PMT_F, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
+
+void
+qa_inband_usrp_server::test_chan_deallocation()
+{
+ mb_runtime_sptr rt = mb_make_runtime();
+ pmt_t result = PMT_T;
+
+ rt->run("top", "qa_dealloc_top", PMT_F, &result);
+
+ CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
+}
+
+void
+qa_inband_usrp_server::test_fragmentation()
+{
+
+}
diff --git a/usrp/host/lib/inband/qa_inband_usrp_server.h b/usrp/host/lib/inband/qa_inband_usrp_server.h
new file mode 100644
index 000000000..eb0f7a3e0
--- /dev/null
+++ b/usrp/host/lib/inband/qa_inband_usrp_server.h
@@ -0,0 +1,42 @@
+/* -*- 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 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.
+ */
+
+#ifndef QA_INBAND_USRP_SERVER_H
+#define QA_INBAND_USRP_SERVER_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+class qa_inband_usrp_server : public CppUnit::TestCase {
+
+ CPPUNIT_TEST_SUITE(qa_inband_usrp_server);
+ CPPUNIT_TEST(test_chan_allocation);
+ CPPUNIT_TEST(test_chan_deallocation);
+ CPPUNIT_TEST(test_fragmentation);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ void test_chan_allocation();
+ void test_chan_deallocation();
+ void test_fragmentation();
+};
+
+#endif /* INCLUDED_QA_INBAND_USRP_SERVER_H */
diff --git a/usrp/host/lib/inband/test_inband.cc b/usrp/host/lib/inband/test_inband.cc
new file mode 100644
index 000000000..49619bef2
--- /dev/null
+++ b/usrp/host/lib/inband/test_inband.cc
@@ -0,0 +1,36 @@
+/* -*- 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 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.
+ */
+
+#include <cppunit/TextTestRunner.h>
+#include <qa_inband.h>
+
+int
+main(int argc, char **argv)
+{
+
+ CppUnit::TextTestRunner runner;
+
+ runner.addTest(qa_inband::suite ());
+
+ bool was_successful = runner.run("", false);
+
+ return was_successful ? 0 : 1;
+}
diff --git a/usrp/host/lib/inband/usb_packet.py b/usrp/host/lib/inband/usb_packet.py
new file mode 100644
index 000000000..5ca19b790
--- /dev/null
+++ b/usrp/host/lib/inband/usb_packet.py
@@ -0,0 +1,115 @@
+#
+# 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.
+#
+
+import struct
+
+
+FL_OVERRUN = 0x80000000
+FL_UNDERRUN = 0x40000000
+FL_DROPPED = 0x20000000
+FL_END_OF_BURST = 0x10000000
+FL_START_OF_BURST = 0x08000000
+
+FL_ALL_FLAGS = 0xf8000000
+
+FL_OVERRUN_SHIFT = 31
+FL_UNDERRUN_SHIFT = 30
+FL_DROPPED_SHIFT = 29
+FL_END_OF_BURST_SHIFT = 28
+FL_START_OF_BURST_SHIFT = 27
+
+RSSI_MASK = 0x3f
+RSSI_SHIFT = 21
+
+CHAN_MASK = 0x1f
+CHAN_SHIFT = 16
+
+TAG_MASK = 0xf
+TAG_SHIFT = 9
+
+PAYLOAD_LEN_MASK = 0x1ff
+PAYLOAD_LEN_SHIFT = 0
+
+def make_header(flags, chan, payload_len, timestamp, rssi=0, tag=0):
+ word0 = ((flags & FL_ALL_FLAGS)
+ | ((rssi & RSSI_MASK) << RSSI_SHIFT)
+ | ((chan & CHAN_MASK) << CHAN_SHIFT)
+ | ((tag & TAG_MASK) << TAG_SHIFT)
+ | ((payload_len & PAYLOAD_LEN_MASK) << PAYLOAD_LEN_SHIFT))
+ word1 = timestamp
+ return struct.pack('<2I', word0, word1)
+
+
+def _decode(pred, indicator):
+ if pred:
+ return indicator
+ else:
+ return '-'
+
+
+class usb_packet(object):
+ def __init__(self, raw_pkt):
+ assert isinstance(raw_pkt, str) and len(raw_pkt) == 512
+ self._raw_pkt = raw_pkt;
+ (self._word0, self._word1) = struct.unpack('<2I', self._raw_pkt[0:8])
+
+ def timestamp(self):
+ return self._word1
+
+ def rssi(self):
+ return (self._word0 >> RSSI_SHIFT) & RSSI_MASK
+
+ def chan(self):
+ return (self._word0 >> CHAN_SHIFT) & CHAN_MASK
+
+ def tag(self):
+ return (self._word0 >> TAG_SHIFT) & TAG_MASK
+
+ def payload_len(self):
+ return (self._word0 >> PAYLOAD_LEN_SHIFT) & PAYLOAD_LEN_MASK
+
+ def flags(self):
+ return self._word0 & FL_ALL_FLAGS
+
+ def overrun(self):
+ return (self._word0 >> FL_OVERRUN_SHIFT) & 0x1
+
+ def underrun(self):
+ return (self._word0 >> FL_UNDERRUN_SHIFT) & 0x1
+
+ def start_of_burst(self):
+ return (self._word0 >> FL_START_OF_BURST_SHIFT) & 0x1
+
+ def end_of_burst(self):
+ return (self._word0 >> FL_END_OF_BURST_SHIFT) & 0x1
+
+ def dropped(self):
+ return (self._word0 >> FL_DROPPED_SHIFT) & 0x1
+
+ def payload(self):
+ return self._raw_pkt[8:8+self.payload_len()]
+
+ def decoded_flags(self):
+ s = (_decode(self.overrun(), 'O')
+ + _decode(self.underrun(), 'U')
+ + _decode(self.dropped(), 'D')
+ + _decode(self.end_of_burst(), 'E')
+ + _decode(self.start_of_burst(), 'S'))
+ return s
diff --git a/usrp/host/lib/inband/usrp_inband_usb_packet.h b/usrp/host/lib/inband/usrp_inband_usb_packet.h
new file mode 100644
index 000000000..471bfc666
--- /dev/null
+++ b/usrp/host/lib/inband/usrp_inband_usb_packet.h
@@ -0,0 +1,149 @@
+/* -*- 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 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.
+ */
+
+#ifndef INCLUDED_USRP_INBAND_USB_PACKET_H_
+#define INCLUDED_USRP_INBAND_USB_PACKET_H_
+
+#include <usrp_bytesex.h>
+#include <mb_mblock.h>
+
+static const int USB_PKT_SIZE = 512; // bytes
+static const int MAX_PAYLOAD = USB_PKT_SIZE-2*sizeof(uint32_t);
+
+class usrp_inband_usb_packet {
+ //
+ // keep raw packet in USRP-endian order
+ //
+ uint32_t d_word0;
+ uint32_t d_timestamp;
+ unsigned char d_payload[MAX_PAYLOAD];
+
+public:
+
+ enum flags {
+ FL_OVERRUN = 0x80000000,
+ FL_UNDERRUN = 0x40000000,
+ FL_DROPPED = 0x20000000,
+ FL_END_OF_BURST = 0x10000000,
+ FL_START_OF_BURST = 0x08000000,
+
+ FL_ALL_FLAGS = 0xf8000000
+ };
+
+ static const int FL_OVERRUN_SHIFT = 31;
+ static const int FL_UNDERRUN_SHIFT = 30;
+ static const int FL_DROPPED_SHIFT = 29;
+ static const int FL_END_OF_BURST_SHIFT = 28;
+ static const int FL_START_OF_BURST_SHIFT = 27;
+
+ static const int RSSI_MASK = 0x3f;
+ static const int RSSI_SHIFT = 21;
+
+ static const int CHAN_MASK = 0x1f;
+ static const int CHAN_SHIFT = 16;
+
+ static const int TAG_MASK = 0xf;
+ static const int TAG_SHIFT = 9;
+
+ static const int PAYLOAD_LEN_MASK = 0x1ff;
+ static const int PAYLOAD_LEN_SHIFT = 0;
+
+public:
+
+ void set_timestamp(uint32_t timestamp){
+ d_timestamp = host_to_usrp_u32(timestamp);
+ }
+
+ void set_end_of_burst() {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ word0 |= 1<<FL_END_OF_BURST_SHIFT;
+ d_word0 = host_to_usrp_u32(word0);
+ }
+
+ void set_header(int flags, int chan, int tag, int payload_len){
+ uint32_t word0 = ((flags & FL_ALL_FLAGS)
+ | ((chan & CHAN_MASK) << CHAN_SHIFT)
+ | ((tag & TAG_MASK) << TAG_SHIFT)
+ | ((payload_len & PAYLOAD_LEN_MASK) << PAYLOAD_LEN_SHIFT));
+ d_word0 = host_to_usrp_u32(word0);
+ }
+
+ uint32_t timestamp() const {
+ return usrp_to_host_u32(d_timestamp);
+ }
+
+ int rssi() const {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ return (word0 >> RSSI_SHIFT) & RSSI_MASK;
+ }
+
+ int chan() const {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ return (word0 >> CHAN_SHIFT) & CHAN_MASK;
+ }
+
+ int tag() const {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ return (word0 >> TAG_SHIFT) & TAG_MASK;
+ }
+
+ int payload_len() const {
+ uint32_t word0 = usrp_to_host_u32(d_word0);
+ return (word0 >> PAYLOAD_LEN_SHIFT) & PAYLOAD_LEN_MASK;
+ }
+
+ int flags() const {
+ return usrp_to_host_u32(d_word0) & FL_ALL_FLAGS;
+ }
+
+ int overrun() const {
+ return (usrp_to_host_u32(d_word0) & FL_OVERRUN) >> FL_OVERRUN_SHIFT;
+ }
+
+
+ int underrun() const {
+ return (usrp_to_host_u32(d_word0) & FL_UNDERRUN) >> FL_UNDERRUN_SHIFT;
+ }
+
+
+ int start_of_burst() const {
+ return (usrp_to_host_u32(d_word0) & FL_START_OF_BURST) >> FL_START_OF_BURST_SHIFT;
+ }
+
+ int end_of_burst() const {
+ return (usrp_to_host_u32(d_word0) & FL_END_OF_BURST) >> FL_END_OF_BURST_SHIFT;
+ }
+
+ int dropped() const {
+ return (usrp_to_host_u32(d_word0) & FL_DROPPED) >> FL_DROPPED_SHIFT;
+ }
+
+ unsigned char *payload() {
+ return d_payload;
+ }
+
+ static int max_payload() {
+ return MAX_PAYLOAD;
+ }
+
+};
+
+#endif
diff --git a/usrp/host/lib/inband/usrp_server.cc b/usrp/host/lib/inband/usrp_server.cc
new file mode 100644
index 000000000..5041a9213
--- /dev/null
+++ b/usrp/host/lib/inband/usrp_server.cc
@@ -0,0 +1,394 @@
+/* -*- 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 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <usrp_server.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
+
+// FIXME We should machine generate these by a simple preprocessor run over this file
+//
+// These are all the messages that we expect to receive.
+//
+// We "intern" these here (make them into symbols) so that our
+// comparisions below are effectively pointer comparisons.
+
+static pmt_t s_cmd_allocate_channel = pmt_intern("cmd-allocate-channel");
+static pmt_t s_cmd_close = pmt_intern("cmd-close");
+static pmt_t s_cmd_deallocate_channel = pmt_intern("cmd-deallocate-channel");
+static pmt_t s_cmd_open = pmt_intern("cmd-open");
+static pmt_t s_cmd_start_recv_raw_samples = pmt_intern("cmd-start-recv-raw-samples");
+static pmt_t s_cmd_stop_recv_raw_samples = pmt_intern("cmd-stop-recv-raw-samples");
+static pmt_t s_cmd_to_control_channel = pmt_intern("cmd-to-control-channel");
+static pmt_t s_cmd_xmit_raw_frame = pmt_intern("cmd-xmit-raw-frame");
+static pmt_t s_cmd_max_capacity = pmt_intern("cmd-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_cmd_current_capacity_allocation = pmt_intern("cmd-current-capacity-allocation");
+static pmt_t s_response_allocate_channel = pmt_intern("response-allocate-channel");
+static pmt_t s_response_close = pmt_intern("response-close");
+static pmt_t s_response_deallocate_channel = pmt_intern("response-deallocate-channel");
+static pmt_t s_response_from_control_channel = pmt_intern("response-from-control-channel");
+static pmt_t s_response_open = pmt_intern("response-open");
+static pmt_t s_response_recv_raw_samples = pmt_intern("response-recv-raw-samples");
+static pmt_t s_response_xmit_raw_frame = pmt_intern("response-xmit-raw-frame");
+static pmt_t s_response_max_capacity = pmt_intern("response-max-capacity");
+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_response_current_capacity_allocation = pmt_intern("response-current-capacity-allocation");
+
+static std::string
+str(long x)
+{
+ std::ostringstream s;
+ s << x;
+ return s.str();
+}
+
+usrp_server::usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
+ : mb_mblock(rt, instance_name, user_arg)
+{
+ // define our ports
+
+ // control & status port
+ d_cs = define_port("cs", "usrp-server-cs", true, mb_port::EXTERNAL);
+
+ // ports
+ //
+ // (if/when we do replicated ports, these will be replaced by a
+ // single replicated port)
+ for(int port=0; port < N_PORTS; port++) {
+ d_tx.push_back(define_port("tx"+str(port), "usrp-tx", true, mb_port::EXTERNAL));
+ d_rx.push_back(define_port("rx"+str(port), "usrp-rx", true, mb_port::EXTERNAL));
+ }
+
+ // FIXME ... initializing to 2 channels on each for now, eventually we should
+ // query the FPGA to get these values
+ d_ntx_chan = 2;
+ d_nrx_chan = 2;
+
+ // Initialize capacity on each channel to 0 and to no owner
+ for(int chan=0; chan < d_ntx_chan; chan++) {
+ d_chaninfo_tx[chan].assigned_capacity = 0;
+ d_chaninfo_tx[chan].owner = PMT_NIL;
+ }
+ for(int chan=0; chan < d_nrx_chan; chan++) {
+ d_chaninfo_rx[chan].assigned_capacity = 0;
+ d_chaninfo_rx[chan].owner = PMT_NIL;
+ }
+}
+
+usrp_server::~usrp_server()
+{
+}
+
+
+void
+usrp_server::initial_transition()
+{
+ // the initial transition
+}
+
+void
+usrp_server::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 invocation_handle;
+ pmt_t reply_data;
+ pmt_t status;
+
+ if (1){
+ std::cout << "[USRP_SERVER] event: " << event << std::endl;
+ std::cout << "[USRP_SERVER] port_id: " << port_id << std::endl;
+ }
+
+ // It would be nice if this were all table driven, and we could
+ // compute our state transition as f(current_state, port_id, signal)
+
+ if (pmt_eq(port_id, d_cs->port_symbol())){ // message came in on our control/status port
+
+ if (pmt_eq(event, s_cmd_open)){
+ // extract args from data
+ invocation_handle = pmt_nth(0, data);
+ long which_usrp = pmt_to_long(pmt_nth(1, data)); // integer usrp id, usually 0
+
+ // Do the right thing....
+ // build a reply
+
+ // if everything OK
+ status = PMT_T;
+ reply_data = pmt_list2(invocation_handle, status);
+
+ // ...and send it
+ d_cs->send(s_response_open, reply_data);
+ return;
+ }
+ else if (pmt_eq(event, s_cmd_close)){
+ // ...
+ }
+ else if (pmt_eq(event, s_cmd_max_capacity)) {
+ invocation_handle = pmt_nth(0, data);
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(max_capacity()));
+ d_cs->send(s_response_max_capacity, reply_data);
+ return;
+ }
+ else if (pmt_eq(event, s_cmd_ntx_chan)) {
+ invocation_handle = pmt_nth(0, data);
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(d_ntx_chan));
+ d_cs->send(s_response_ntx_chan, reply_data);
+ }
+ else if (pmt_eq(event, s_cmd_nrx_chan)) {
+ invocation_handle = pmt_nth(0, data);
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(d_nrx_chan));
+ d_cs->send(s_response_nrx_chan, reply_data);
+ }
+ else if (pmt_eq(event, s_cmd_current_capacity_allocation)) {
+ invocation_handle = pmt_nth(0, data);
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(current_capacity_allocation()));
+ d_cs->send(s_response_current_capacity_allocation, reply_data);
+ }
+ goto unhandled;
+ }
+
+ if (pmt_eq(event, s_cmd_allocate_channel)){
+ handle_cmd_allocate_channel(port_id, data);
+ return;
+ }
+
+ if (pmt_eq(event, s_cmd_deallocate_channel)) {
+ handle_cmd_deallocate_channel(port_id, data);
+ return;
+ }
+
+ if (pmt_eq(event, s_cmd_xmit_raw_frame)){
+ handle_cmd_xmit_raw_frame(data);
+ return;
+ }
+
+ unhandled:
+ std::cout << "[USRP_SERVER] unhandled msg: " << msg << std::endl;
+}
+
+// Return -1 if it is not an RX port, or an index
+int usrp_server::tx_port_index(pmt_t port_id) {
+
+ for(int i=0; i < (int) d_tx.size(); i++)
+ if(pmt_eq(d_tx[i]->port_symbol(), port_id))
+ return i;
+
+ return -1;
+}
+
+// Return -1 if it is not an RX port, or an index
+int usrp_server::rx_port_index(pmt_t port_id) {
+
+ for(int i=0; i < (int) d_rx.size(); i++)
+ if(pmt_eq(d_rx[i]->port_symbol(), port_id))
+ return i;
+
+ return -1;
+}
+
+// Go through all TX and RX channels, sum up the assigned capacity
+// and return it
+long usrp_server::current_capacity_allocation() {
+ long capacity = 0;
+
+ for(int chan=0; chan < d_ntx_chan; chan++)
+ capacity += d_chaninfo_tx[chan].assigned_capacity;
+
+ for(int chan=0; chan < d_nrx_chan; chan++)
+ capacity += d_chaninfo_rx[chan].assigned_capacity;
+
+ return capacity;
+}
+
+void usrp_server::handle_cmd_allocate_channel(pmt_t port_id, pmt_t data) {
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ long rqstd_capacity = pmt_to_long(pmt_nth(1, data));
+ long chan, port;
+ pmt_t reply_data;
+
+ // If it's a TX port, allocate on a free channel, else check if it's a RX port
+ // and allocate.
+ if((port = tx_port_index(port_id)) != -1) {
+
+ // Check capacity exists
+ if((D_USB_CAPACITY - current_capacity_allocation()) < rqstd_capacity) {
+ reply_data = pmt_list3(invocation_handle, pmt_from_long(RQSTD_CAPACITY_UNAVAIL), PMT_NIL); // no capacity available
+ d_tx[port]->send(s_response_allocate_channel, reply_data);
+ return;
+ }
+
+ // Find a free channel, assign the capacity and respond
+ for(chan=0; chan < d_ntx_chan; chan++) {
+ if(d_chaninfo_tx[chan].owner == PMT_NIL) {
+ d_chaninfo_tx[chan].owner = port_id;
+ d_chaninfo_tx[chan].assigned_capacity = rqstd_capacity;
+ reply_data = pmt_list3(invocation_handle, PMT_T, pmt_from_long(chan));
+ d_tx[port]->send(s_response_allocate_channel, reply_data);
+ return;
+ }
+ }
+
+ std::cout << "[USRP_SERVER] Couldnt find a TX chan\n";
+
+ reply_data = pmt_list3(invocation_handle, pmt_from_long(CHANNEL_UNAVAIL), PMT_NIL); // no free TX chan found
+ d_tx[port]->send(s_response_allocate_channel, reply_data);
+ return;
+ }
+
+ // Repeat the same process on the RX side if the port was not determined to be TX
+ if((port = rx_port_index(port_id)) != -1) {
+
+ if((D_USB_CAPACITY - current_capacity_allocation()) < rqstd_capacity) {
+ reply_data = pmt_list3(invocation_handle, pmt_from_long(RQSTD_CAPACITY_UNAVAIL), PMT_NIL); // no capacity available
+ d_rx[port]->send(s_response_allocate_channel, reply_data);
+ return;
+ }
+
+ for(chan=0; chan < d_nrx_chan; chan++) {
+ if(d_chaninfo_rx[chan].owner == PMT_NIL) {
+ d_chaninfo_rx[chan].owner = port_id;
+ d_chaninfo_rx[chan].assigned_capacity = rqstd_capacity;
+ reply_data = pmt_list3(invocation_handle, PMT_T, pmt_from_long(chan));
+ d_rx[port]->send(s_response_allocate_channel, reply_data);
+ return;
+ }
+ }
+
+ std::cout << "[USRP_SERVER] Couldnt find a RX chan\n";
+ reply_data = pmt_list3(invocation_handle, pmt_from_long(CHANNEL_UNAVAIL), PMT_NIL); // no free RX chan found
+ d_rx[port]->send(s_response_allocate_channel, reply_data);
+ 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.
+void usrp_server::handle_cmd_deallocate_channel(pmt_t port_id, pmt_t data) {
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ long channel = pmt_to_long(pmt_nth(1, data));
+ long port;
+ pmt_t reply_data;
+
+ // Check that the channel number is valid, and that the calling port is the owner
+ // of the channel, and if so remove the assigned capacity.
+ if((port = tx_port_index(port_id)) != -1) {
+
+ if(channel >= d_ntx_chan) {
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(CHANNEL_INVALID)); // not a legit channel number
+ d_tx[port]->send(s_response_deallocate_channel, reply_data);
+ return;
+ }
+
+ if(d_chaninfo_tx[channel].owner != port_id) {
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(PERMISSION_DENIED)); // not the owner of the port
+ d_tx[port]->send(s_response_deallocate_channel, reply_data);
+ return;
+ }
+
+ d_chaninfo_tx[channel].assigned_capacity = 0;
+ d_chaninfo_tx[channel].owner = PMT_NIL;
+
+ reply_data = pmt_list2(invocation_handle, PMT_T);
+ d_tx[port]->send(s_response_deallocate_channel, reply_data);
+ return;
+ }
+
+ // Repeated process on the RX side
+ if((port = rx_port_index(port_id)) != -1) {
+
+ if(channel >= d_nrx_chan) {
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(CHANNEL_INVALID)); // not a legit channel number
+ d_rx[port]->send(s_response_deallocate_channel, reply_data);
+ return;
+ }
+
+ if(d_chaninfo_rx[channel].owner != port_id) {
+ reply_data = pmt_list2(invocation_handle, pmt_from_long(PERMISSION_DENIED)); // not the owner of the port
+ d_rx[port]->send(s_response_deallocate_channel, reply_data);
+ return;
+ }
+
+ d_chaninfo_rx[channel].assigned_capacity = 0;
+ d_chaninfo_rx[channel].owner = PMT_NIL;
+
+ reply_data = pmt_list2(invocation_handle, PMT_T);
+ d_rx[port]->send(s_response_deallocate_channel, reply_data);
+ return;
+ }
+
+}
+
+void usrp_server::handle_cmd_xmit_raw_frame(pmt_t data) {
+
+ size_t n_bytes, psize;
+ long max_payload_len = transport_pkt::max_payload();
+
+ pmt_t invocation_handle = pmt_nth(0, data);
+ long channel = pmt_to_long(pmt_nth(1, data));
+ const void *samples = pmt_uniform_vector_elements(pmt_nth(2, data), n_bytes);
+ long timestamp = pmt_to_long(pmt_nth(3, data));
+
+ // Determine the number of packets to allocate contiguous memory for bursting over the
+ // USB and get a pointer to the memory to be used in building the packets
+ long n_packets = static_cast<long>(std::ceil(n_bytes / (double)max_payload_len));
+ pmt_t v_packets = pmt_make_u8vector(sizeof(transport_pkt) * n_packets, 0);
+
+ transport_pkt *pkts =
+ (transport_pkt *) pmt_u8vector_writeable_elements(v_packets, psize);
+
+ for(int n=0; n < n_packets; n++) {
+
+ long payload_len = std::min((long)(n_bytes-(n*max_payload_len)), (long)max_payload_len);
+
+ if(n == 0) { // first packet gets start of burst flag and timestamp
+ pkts[n].set_header(pkts[n].FL_START_OF_BURST, channel, 0, payload_len);
+ pkts[n].set_timestamp(timestamp);
+ } else {
+ pkts[n].set_header(0, channel, 0, payload_len);
+ pkts[n].set_timestamp(0xffffffff);
+ }
+
+ memcpy(pkts[n].payload(), (uint8_t *)samples+(max_payload_len * n), payload_len);
+ }
+
+ pkts[n_packets-1].set_end_of_burst(); // set the last packet's end of burst
+
+ // interface with the USRP to send the USB packet, since the memory is
+ // contiguous, this should be a serious of memory copies to the bus, each being
+ // USB_PKT_SIZE * MAX_PACKET_BURST bytes worth of data (given a full burst)
+}
+
+REGISTER_MBLOCK_CLASS(usrp_server);
diff --git a/usrp/host/lib/inband/usrp_server.h b/usrp/host/lib/inband/usrp_server.h
new file mode 100644
index 000000000..87c2768e5
--- /dev/null
+++ b/usrp/host/lib/inband/usrp_server.h
@@ -0,0 +1,82 @@
+/* -*- 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 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.
+ */
+#ifndef INCLUDED_USRP_SERVER_H
+#define INCLUDED_USRP_SERVER_H
+
+#include <mb_mblock.h>
+#include <vector>
+
+/*!
+ * \brief Implements the lowest-level mblock interface to the USRP
+ */
+class usrp_server : public mb_mblock
+{
+public:
+
+ enum error_codes {
+ RQSTD_CAPACITY_UNAVAIL = 0,
+ CHANNEL_UNAVAIL = 1,
+ CHANNEL_INVALID = 2,
+ PERMISSION_DENIED = 3
+ };
+
+ // our ports
+ enum port_types {
+ RX_PORT = 0,
+ TX_PORT = 1
+ };
+ static const int N_PORTS = 4;
+ std::vector<mb_port_sptr> d_tx, d_rx;
+ mb_port_sptr d_cs;
+
+ static const int D_USB_CAPACITY = 32 * 1024 * 1024;
+ static const int D_MAX_CHANNELS = 16;
+ long d_ntx_chan;
+ long d_nrx_chan;
+
+ struct channel_info {
+ long assigned_capacity; // the capacity currently assignedby the channel
+ pmt_t owner; // port ID of the owner of the channel
+ };
+
+ struct channel_info d_chaninfo_tx[D_MAX_CHANNELS];
+ struct channel_info d_chaninfo_rx[D_MAX_CHANNELS];
+
+public:
+ usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg);
+ ~usrp_server();
+
+ void initial_transition();
+ void handle_message(mb_message_sptr msg);
+
+protected:
+ static int max_capacity() { return D_USB_CAPACITY; }
+
+private:
+ void handle_cmd_allocate_channel(pmt_t port_id, pmt_t data);
+ void handle_cmd_deallocate_channel(pmt_t port_id, pmt_t data);
+ void handle_cmd_xmit_raw_frame(pmt_t data);
+ int rx_port_index(pmt_t port_id);
+ int tx_port_index(pmt_t port_id);
+ long current_capacity_allocation();
+};
+
+#endif /* INCLUDED_USRP_SERVER_H */
diff --git a/usrp/host/lib/inband/usrp_server.mbh b/usrp/host/lib/inband/usrp_server.mbh
new file mode 100644
index 000000000..97bb0e664
--- /dev/null
+++ b/usrp/host/lib/inband/usrp_server.mbh
@@ -0,0 +1,256 @@
+;; -*- 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 pair containing
+;; (status-code . message), where status-code is a symbol and message
+;; is a string.
+
+
+;; ----------------------------------------------------------------
+;; usrp-channel
+;;
+;; 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 usrp-channel
+
+ (:outgoing
+
+ (cmd-allocate-channel invocation-handle capacity-reservation)
+
+ ;; The cmd-allocate-channel message requests that the server
+ ;; allocates a logical channel in the FPGA for use.
+ ;; capacity-reservation specifies the number of bytes/s of
+ ;; interconnect capacity (USB or ethernet) to reserve for this
+ ;; channel. (The reservation is just a sanity check, no OS
+ ;; specific mechanism is used.)
+
+ (cmd-deallocate-channel invocation-handle channel)
+
+ ;; The integer channel specifies the channel to deallocate.
+
+ )
+
+ (:incoming
+
+
+ (response-allocate-channel invocation-handle status channel)
+
+ ;; If successful, a channel the specified capacity was allocated.
+ ;; channel, an integer, indicates which channel was allocated.
+
+ (response-deallocate-channel invocation-handle status)
+
+ ;; If successful, the specified channel and associated interconnect
+ ;; capacity were deallocated.
+
+ )
+ )
+
+;; ----------------------------------------------------------------
+;; usrp-low-level-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 low level control and status interface to the usrp.
+;; This will probably be replaced (or at least augmented) with a
+;; higher level interface. For now, this will allow us to get on
+;; the air.
+;;
+;; The subpackets are lists containing the relevant parameters. The
+;; server will marshall them appropriately. Below is a list of
+;; subpackets. See inband-signaling-usb for details. The opcodes are
+;; symbols; unless otherwise indicated the remaining parameters are
+;; integers. rid values are limited to 3-bits.
+;;
+;; (op-ping-fixed rid ping-value)
+;; (op-ping-fixed-reply rid ping-value)
+;; (op-write-reg reg-number reg-value)
+;; (op-write-reg-masked reg-number reg-value mask-value)
+;; (op-read-reg rid reg-number reg-value)
+;; (op-read-reg-reply rid reg-number reg-value)
+;; (op-i2c-write i2c-addr u8-vec)
+;; (op-i2c-read rid i2c-addr nbytes)
+;; (op-i2c-read-reply rid i2c-addr u8-vec)
+;; (op-spi-write enables format opt-header-bytes u8-vec)
+;; (op-spi-read rid enables format opt-header-bytes nbytes)
+;; (op-spi-read-reply rid u8-vec)
+;; (op-delay ticks)
+
+
+(define-protocol-class usrp-low-level-cs
+
+ (:outgoing
+
+ (cmd-to-control-channel invocation-handle list-of-subpackets)
+
+ )
+
+ (:incoming
+
+ (response-from-control-channel invocation-handle status list-of-subpackets)
+
+ )
+ )
+
+;; ----------------------------------------------------------------
+;; usrp-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 usrp-tx
+ (:include usrp-channel)
+ (:include usrp-low-level-cs)
+
+ (:outgoing
+
+ (cmd-xmit-raw-frame invocation-handle channel samples timestamp)
+
+ ;; The argument channel must be an integer. It specifies the
+ ;; channel on which the frame of samples will be be sent.
+ ;;
+ ;; samples must be a uniform numeric vector. The contents of the
+ ;; sample vector is treated as opaque and is passed on to the FPGA
+ ;; unmodified. It is the responsibility of the sender to ensure
+ ;; that the binary format is sensible for the current FPGA
+ ;; configuration.
+ ;;
+ ;; timestamp is a 32-bit integer that specifies the time at which
+ ;; the first sample in samples shall be sent to the D/A converter.
+ ;; The format and interpration of time is specified in the file
+ ;; inband-signaling-usb
+ )
+
+ (:incoming
+
+ (response-xmit-raw-frame invocation-handle status)
+
+ ;; If successful, the samples of the associated frame have been
+ ;; transmitted to the USRP. This message may be used to implement
+ ;; Tx flow control. The client could for example implement a
+ ;; policy of never having more than 4 unacknowledged
+ ;; cmd-xmit-raw-frame's outstanding.
+
+ )
+ )
+
+;; ----------------------------------------------------------------
+;; usrp-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 usrp-rx
+ (:include usrp-channel)
+ (:include usrp-low-level-cs)
+
+ (:outgoing
+
+ (cmd-start-recv-raw-samples invocation-handle channel)
+
+ ;; The argument channel must be an integer. It specifies the
+ ;; channel from which frames of samples will be be received. The
+ ;; server will return response-recv-raw-samples messages until a
+ ;; cmd-stop-recv-raw-samples message is received.
+
+ (cmd-stop-recv-raw-samples invocation-handle channel)
+
+ ;; The argument channel must be an integer. There is no reply to
+ ;; this message.
+
+ )
+
+ (:incoming
+
+ (response-recv-raw-samples invocation-handle status samples timestamp properties)
+
+ ;; samples is a uniform numeric vector. The contents of the sample
+ ;; vector is treated as opaque and is passed from the FPGA
+ ;; unmodified. It is the responsibility of the receiver to decode
+ ;; the binary format as appropriate for the current FPGA
+ ;; configuration.
+ ;;
+ ;; timestamp is a 32-bit integer that specifies the time at which
+ ;; the first sample in samples was received from the A/D converter.
+ ;; The format and interpretation of time is as specified in the
+ ;; file inband-signaling-usb.
+ ;;
+ ;; properties is a dictionary containing additional (key, value)
+ ;; pairs associated with the reception of these samples. In
+ ;; particular, the map may contain the Received Signal Strength
+ ;; Indication (RSSI) reported by the front end at the time the
+ ;; first sample was received from the A/D.
+
+ )
+ )
+
+
+;; ----------------------------------------------------------------
+;; usrp-server-cs
+;;
+;; Control and status port for usrp-server
+;;
+;; 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 usrp-server-cs
+
+ (:outgoing
+ (cmd-open invocation-handle which-usrp)
+ (cmd-close invocation-handle)
+ (cmd-max-capacity invocation-handle)
+ (cmd-ntx-chan invocation-handle)
+ (cmd-nrx-chan invocation-handle)
+ (cmd-current-capacity-allocation invocation-handle)
+ )
+
+ (:incoming
+ (response-open invocation-handle status)
+ (response-close invocation-handle status)
+ (response-max-capacity invocation-handle capacity)
+ (response-ntx-chan invocation-handle ntx-chan)
+ (response-nrx-chan invocation-handle nrx-chan)
+ (response-current-capacity-allocation invocation-handle capacity)
+ )
+ )