aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/common
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/common')
-rw-r--r--host/lib/usrp/common/CMakeLists.txt34
-rw-r--r--host/lib/usrp/common/fx2_ctrl.cpp460
-rw-r--r--host/lib/usrp/common/fx2_ctrl.hpp123
-rw-r--r--host/lib/usrp/common/recv_packet_demuxer.cpp87
-rw-r--r--host/lib/usrp/common/recv_packet_demuxer.hpp41
-rw-r--r--host/lib/usrp/common/validate_subdev_spec.cpp73
-rw-r--r--host/lib/usrp/common/validate_subdev_spec.hpp38
7 files changed, 856 insertions, 0 deletions
diff --git a/host/lib/usrp/common/CMakeLists.txt b/host/lib/usrp/common/CMakeLists.txt
new file mode 100644
index 000000000..ec8b60fec
--- /dev/null
+++ b/host/lib/usrp/common/CMakeLists.txt
@@ -0,0 +1,34 @@
+#
+# Copyright 2011 Ettus Research LLC
+#
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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, see <http://www.gnu.org/licenses/>.
+#
+
+########################################################################
+# This file included, use CMake directory variables
+########################################################################
+IF(ENABLE_USB)
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../firmware/fx2/common)
+
+ LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/fx2_ctrl.cpp
+ )
+ENDIF(ENABLE_USB)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/validate_subdev_spec.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/recv_packet_demuxer.cpp
+)
diff --git a/host/lib/usrp/common/fx2_ctrl.cpp b/host/lib/usrp/common/fx2_ctrl.cpp
new file mode 100644
index 000000000..8f2206221
--- /dev/null
+++ b/host/lib/usrp/common/fx2_ctrl.cpp
@@ -0,0 +1,460 @@
+//
+// Copyright 2010-2011 Ettus Research LLC
+//
+// This program 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 of the License, or
+// (at your option) any later version.
+//
+// This program 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, see <http://www.gnu.org/licenses/>.
+//
+
+#include "fx2_ctrl.hpp"
+#include "usrp_commands.h"
+#include <uhd/utils/msg.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/transport/usb_control.hpp>
+#include <boost/functional/hash.hpp>
+#include <boost/thread/thread.hpp>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <cstring>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+#define FX2_FIRMWARE_LOAD 0xa0
+
+static const bool load_img_msg = true;
+
+/***********************************************************************
+ * Helper Functions
+ **********************************************************************/
+/*!
+ * Create a file hash
+ * The hash will be used to identify the loaded firmware and fpga image
+ * \param filename file used to generate hash value
+ * \return hash value in a size_t type
+ */
+static size_t generate_hash(const char *filename)
+{
+ std::ifstream file(filename);
+ if (not file){
+ throw uhd::io_error(std::string("cannot open input file ") + filename);
+ }
+
+ size_t hash = 0;
+
+ char ch;
+ while (file.get(ch)) {
+ boost::hash_combine(hash, ch);
+ }
+
+ if (not file.eof()){
+ throw uhd::io_error(std::string("file error ") + filename);
+ }
+
+ file.close();
+ return hash;
+}
+
+
+/*!
+ * Verify checksum of a Intel HEX record
+ * \param record a line from an Intel HEX file
+ * \return true if record is valid, false otherwise
+ */
+static bool checksum(std::string *record)
+{
+
+ size_t len = record->length();
+ unsigned int i;
+ unsigned char sum = 0;
+ unsigned int val;
+
+ for (i = 1; i < len; i += 2) {
+ std::istringstream(record->substr(i, 2)) >> std::hex >> val;
+ sum += val;
+ }
+
+ if (sum == 0)
+ return true;
+ else
+ return false;
+}
+
+
+/*!
+ * Parse Intel HEX record
+ *
+ * \param record a line from an Intel HEX file
+ * \param len output length of record
+ * \param addr output address
+ * \param type output type
+ * \param data output data
+ * \return true if record is sucessfully read, false on error
+ */
+bool parse_record(std::string *record, unsigned int &len,
+ unsigned int &addr, unsigned int &type,
+ unsigned char* data)
+{
+ unsigned int i;
+ std::string _data;
+ unsigned int val;
+
+ if (record->substr(0, 1) != ":")
+ return false;
+
+ std::istringstream(record->substr(1, 2)) >> std::hex >> len;
+ std::istringstream(record->substr(3, 4)) >> std::hex >> addr;
+ std::istringstream(record->substr(7, 2)) >> std::hex >> type;
+
+ for (i = 0; i < len; i++) {
+ std::istringstream(record->substr(9 + 2 * i, 2)) >> std::hex >> val;
+ data[i] = (unsigned char) val;
+ }
+
+ return true;
+}
+
+
+/*!
+ * USRP control implementation for device discovery and configuration
+ */
+class fx2_ctrl_impl : public fx2_ctrl {
+public:
+ fx2_ctrl_impl(uhd::transport::usb_control::sptr ctrl_transport)
+ {
+ _ctrl_transport = ctrl_transport;
+ }
+
+ void usrp_load_firmware(std::string filestring, bool force)
+ {
+ const char *filename = filestring.c_str();
+
+ size_t hash = generate_hash(filename);
+
+ size_t loaded_hash; usrp_get_firmware_hash(loaded_hash);
+
+ if (not force and (hash == loaded_hash)) return;
+
+ //FIXME: verify types
+ unsigned int len;
+ unsigned int addr;
+ unsigned int type;
+ unsigned char data[512];
+
+ std::ifstream file;
+ file.open(filename, std::ifstream::in);
+
+ if (!file.good()) {
+ throw uhd::io_error("usrp_load_firmware: cannot open firmware input file");
+ }
+
+ unsigned char reset_y = 1;
+ unsigned char reset_n = 0;
+
+ //hit the reset line
+ if (load_img_msg) UHD_MSG(status) << "Loading firmware image: " << filestring << "..." << std::flush;
+ usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_y, 1);
+
+ while (!file.eof()) {
+ std::string record;
+ file >> record;
+
+ //check for valid record
+ if (not checksum(&record) or not parse_record(&record, len, addr, type, data)) {
+ throw uhd::io_error("usrp_load_firmware: bad record checksum");
+ }
+
+ //type 0x00 is data
+ if (type == 0x00) {
+ int ret = usrp_control_write(FX2_FIRMWARE_LOAD, addr, 0, data, len);
+ if (ret < 0) throw uhd::io_error("usrp_load_firmware: usrp_control_write failed");
+ }
+ //type 0x01 is end
+ else if (type == 0x01) {
+ usrp_set_firmware_hash(hash); //set hash before reset
+ usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_n, 1);
+ file.close();
+
+ //wait for things to settle
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
+ if (load_img_msg) UHD_MSG(status) << " done" << std::endl;
+ return;
+ }
+ //type anything else is unhandled
+ else {
+ throw uhd::io_error("usrp_load_firmware: unsupported record");
+ }
+ }
+
+ //file did not end
+ throw uhd::io_error("usrp_load_firmware: bad record");
+ }
+
+ void usrp_init(void){
+ //disable
+ usrp_rx_enable(false);
+ usrp_tx_enable(false);
+
+ //toggle resets
+ usrp_rx_reset(true);
+ usrp_tx_reset(true);
+ usrp_rx_reset(false);
+ usrp_tx_reset(false);
+ }
+
+ void usrp_load_fpga(std::string filestring)
+ {
+ const char *filename = filestring.c_str();
+
+ size_t hash = generate_hash(filename);
+
+ size_t loaded_hash; usrp_get_fpga_hash(loaded_hash);
+
+ if (hash == loaded_hash) return;
+ const int ep0_size = 64;
+ unsigned char buf[ep0_size];
+
+ if (load_img_msg) UHD_MSG(status) << "Loading FPGA image: " << filestring << "..." << std::flush;
+ std::ifstream file;
+ file.open(filename, std::ios::in | std::ios::binary);
+ if (not file.good()) {
+ throw uhd::io_error("usrp_load_fpga: cannot open fpga input file");
+ }
+
+ usrp_fpga_reset(true); //holding the fpga in reset while loading
+
+ if (usrp_control_write_cmd(VRQ_FPGA_LOAD, 0, FL_BEGIN) < 0) {
+ throw uhd::io_error("usrp_load_fpga: fpga load error");
+ }
+
+ while (not file.eof()) {
+ file.read((char *)buf, sizeof(buf));
+ const std::streamsize n = file.gcount();
+ if(n == 0) continue;
+ int ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER, buf, boost::uint16_t(n));
+ if (ret < 0 or size_t(ret) != n) {
+ throw uhd::io_error("usrp_load_fpga: fpga load error");
+ }
+ }
+
+ if (usrp_control_write_cmd(VRQ_FPGA_LOAD, 0, FL_END) < 0) {
+ throw uhd::io_error("usrp_load_fpga: fpga load error");
+ }
+
+ usrp_set_fpga_hash(hash);
+
+ usrp_fpga_reset(false); //done loading, take fpga out of reset
+
+ file.close();
+ if (load_img_msg) UHD_MSG(status) << " done" << std::endl;
+ }
+
+ void usrp_load_eeprom(std::string filestring)
+ {
+ if (load_img_msg) UHD_MSG(status) << "Loading EEPROM image: " << filestring << "..." << std::flush;
+ const char *filename = filestring.c_str();
+ const boost::uint16_t i2c_addr = 0x50;
+
+ unsigned int addr;
+ unsigned char data[256];
+ unsigned char sendbuf[17];
+
+ std::ifstream file;
+ file.open(filename, std::ifstream::in);
+
+ if (not file.good()) {
+ throw uhd::io_error("usrp_load_eeprom: cannot open EEPROM input file");
+ }
+
+ file.read((char *)data, 256);
+ std::streamsize len = file.gcount();
+
+ if(len == 256) {
+ throw uhd::io_error("usrp_load_eeprom: image size too large");
+ }
+
+ const int pagesize = 16;
+ addr = 0;
+ while(len > 0) {
+ sendbuf[0] = addr;
+ memcpy(sendbuf+1, &data[addr], len > pagesize ? pagesize : size_t(len));
+ int ret = usrp_i2c_write(i2c_addr, sendbuf, (len > pagesize ? pagesize : size_t(len))+1);
+ if (ret < 0) {
+ throw uhd::io_error("usrp_load_eeprom: usrp_i2c_write failed");
+ }
+ addr += pagesize;
+ len -= pagesize;
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+ }
+ file.close();
+ if (load_img_msg) UHD_MSG(status) << " done" << std::endl;
+ }
+
+
+ void usrp_set_led(int led_num, bool on)
+ {
+ UHD_ASSERT_THROW(usrp_control_write_cmd(VRQ_SET_LED, on, led_num) >= 0);
+ }
+
+
+ void usrp_get_firmware_hash(size_t &hash)
+ {
+ UHD_ASSERT_THROW(usrp_control_read(0xa0, USRP_HASH_SLOT_0_ADDR, 0,
+ (unsigned char*) &hash, sizeof(size_t)) >= 0);
+ }
+
+
+ void usrp_set_firmware_hash(size_t hash)
+ {
+ UHD_ASSERT_THROW(usrp_control_write(0xa0, USRP_HASH_SLOT_0_ADDR, 0,
+ (unsigned char*) &hash, sizeof(size_t)) >= 0);
+
+ }
+
+
+ void usrp_get_fpga_hash(size_t &hash)
+ {
+ UHD_ASSERT_THROW(usrp_control_read(0xa0, USRP_HASH_SLOT_1_ADDR, 0,
+ (unsigned char*) &hash, sizeof(size_t)) >= 0);
+ }
+
+
+ void usrp_set_fpga_hash(size_t hash)
+ {
+ UHD_ASSERT_THROW(usrp_control_write(0xa0, USRP_HASH_SLOT_1_ADDR, 0,
+ (unsigned char*) &hash, sizeof(size_t)) >= 0);
+ }
+
+ void usrp_tx_enable(bool on)
+ {
+ UHD_ASSERT_THROW(usrp_control_write_cmd(VRQ_FPGA_SET_TX_ENABLE, on, 0) >= 0);
+ }
+
+
+ void usrp_rx_enable(bool on)
+ {
+ UHD_ASSERT_THROW(usrp_control_write_cmd(VRQ_FPGA_SET_RX_ENABLE, on, 0) >= 0);
+ }
+
+
+ void usrp_tx_reset(bool on)
+ {
+ UHD_ASSERT_THROW(usrp_control_write_cmd(VRQ_FPGA_SET_TX_RESET, on, 0) >= 0);
+ }
+
+
+ void usrp_rx_reset(bool on)
+ {
+ UHD_ASSERT_THROW(usrp_control_write_cmd(VRQ_FPGA_SET_RX_RESET, on, 0) >= 0);
+ }
+
+ void usrp_fpga_reset(bool on)
+ {
+ UHD_ASSERT_THROW(usrp_control_write_cmd(VRQ_FPGA_SET_RESET, on, 0) >= 0);
+ }
+
+ int usrp_control_write(boost::uint8_t request,
+ boost::uint16_t value,
+ boost::uint16_t index,
+ unsigned char *buff,
+ boost::uint16_t length)
+ {
+ return _ctrl_transport->submit(VRT_VENDOR_OUT, // bmReqeustType
+ request, // bRequest
+ value, // wValue
+ index, // wIndex
+ buff, // data
+ length); // wLength
+ }
+
+
+ int usrp_control_read(boost::uint8_t request,
+ boost::uint16_t value,
+ boost::uint16_t index,
+ unsigned char *buff,
+ boost::uint16_t length)
+ {
+ return _ctrl_transport->submit(VRT_VENDOR_IN, // bmReqeustType
+ request, // bRequest
+ value, // wValue
+ index, // wIndex
+ buff, // data
+ length); // wLength
+ }
+
+
+ int usrp_control_write_cmd(boost::uint8_t request, boost::uint16_t value, boost::uint16_t index)
+ {
+ return usrp_control_write(request, value, index, 0, 0);
+ }
+
+ int usrp_i2c_write(boost::uint16_t i2c_addr, unsigned char *buf, boost::uint16_t len)
+ {
+ return usrp_control_write(VRQ_I2C_WRITE, i2c_addr, 0, buf, len);
+ }
+
+ int usrp_i2c_read(boost::uint16_t i2c_addr, unsigned char *buf, boost::uint16_t len)
+ {
+ return usrp_control_read(VRQ_I2C_READ, i2c_addr, 0, buf, len);
+ }
+
+ static const bool iface_debug = false;
+ static const size_t max_i2c_data_bytes = 64;
+
+ void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes)
+ {
+ UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes);
+
+ unsigned char buff[max_i2c_data_bytes];
+ std::copy(bytes.begin(), bytes.end(), buff);
+
+ int ret = this->usrp_i2c_write(addr & 0xff,
+ buff,
+ bytes.size());
+
+ if (iface_debug && (ret < 0))
+ uhd::runtime_error("USRP: failed i2c write");
+ }
+
+ byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes)
+ {
+ UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes);
+
+ unsigned char buff[max_i2c_data_bytes];
+ int ret = this->usrp_i2c_read(addr & 0xff,
+ buff,
+ num_bytes);
+
+ if (iface_debug && ((ret < 0) || (unsigned)ret < (num_bytes)))
+ uhd::runtime_error("USRP: failed i2c read");
+
+ byte_vector_t out_bytes;
+ for (size_t i = 0; i < num_bytes; i++)
+ out_bytes.push_back(buff[i]);
+
+ return out_bytes;
+ }
+
+
+private:
+ uhd::transport::usb_control::sptr _ctrl_transport;
+};
+
+/***********************************************************************
+ * Public make function for fx2_ctrl interface
+ **********************************************************************/
+fx2_ctrl::sptr fx2_ctrl::make(uhd::transport::usb_control::sptr ctrl_transport){
+ return sptr(new fx2_ctrl_impl(ctrl_transport));
+}
+
diff --git a/host/lib/usrp/common/fx2_ctrl.hpp b/host/lib/usrp/common/fx2_ctrl.hpp
new file mode 100644
index 000000000..691d64275
--- /dev/null
+++ b/host/lib/usrp/common/fx2_ctrl.hpp
@@ -0,0 +1,123 @@
+//
+// Copyright 2010-2011 Ettus Research LLC
+//
+// This program 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 of the License, or
+// (at your option) any later version.
+//
+// This program 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, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_USRP_COMMON_FX2_CTRL_HPP
+#define INCLUDED_LIBUHD_USRP_COMMON_FX2_CTRL_HPP
+
+#include <uhd/transport/usb_control.hpp>
+#include <uhd/types/serial.hpp> //i2c iface
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+namespace uhd{ namespace usrp{
+
+class fx2_ctrl : boost::noncopyable, public uhd::i2c_iface{
+public:
+ typedef boost::shared_ptr<fx2_ctrl> sptr;
+
+ /*!
+ * Make a usrp control object from a control transport
+ * \param ctrl_transport a USB control transport
+ * \return a new usrp control object
+ */
+ static sptr make(uhd::transport::usb_control::sptr ctrl_transport);
+
+ //! Call init after the fpga is loaded
+ virtual void usrp_init(void) = 0;
+
+ /*!
+ * Load firmware in Intel HEX Format onto device
+ * \param filename name of firmware file
+ * \param force reload firmware if already loaded
+ */
+ virtual void usrp_load_firmware(std::string filename,
+ bool force = false) = 0;
+
+ /*!
+ * Load fpga file onto usrp
+ * \param filename name of fpga image
+ */
+ virtual void usrp_load_fpga(std::string filename) = 0;
+
+ /*!
+ * Load USB descriptor file in Intel HEX format into EEPROM
+ * \param filename name of EEPROM image
+ */
+ virtual void usrp_load_eeprom(std::string filestring) = 0;
+
+ /*!
+ * Submit an IN transfer
+ * \param request device specific request
+ * \param value device specific field
+ * \param index device specific field
+ * \param buff buffer to place data
+ * \return number of bytes read or error
+ */
+ virtual int usrp_control_read(boost::uint8_t request,
+ boost::uint16_t value,
+ boost::uint16_t index,
+ unsigned char *buff,
+ boost::uint16_t length) = 0;
+
+ /*!
+ * Submit an OUT transfer
+ * \param request device specific request
+ * \param value device specific field
+ * \param index device specific field
+ * \param buff buffer of data to be sent
+ * \return number of bytes written or error
+ */
+ virtual int usrp_control_write(boost::uint8_t request,
+ boost::uint16_t value,
+ boost::uint16_t index,
+ unsigned char *buff,
+ boost::uint16_t length) = 0;
+
+ /*!
+ * Perform an I2C write
+ * \param i2c_addr I2C device address
+ * \param buf data to be written
+ * \param len length of data in bytes
+ * \return number of bytes written or error
+ */
+
+ virtual int usrp_i2c_write(boost::uint16_t i2c_addr,
+ unsigned char *buf,
+ boost::uint16_t len) = 0;
+
+ /*!
+ * Perform an I2C read
+ * \param i2c_addr I2C device address
+ * \param buf data to be read
+ * \param len length of data in bytes
+ * \return number of bytes read or error
+ */
+
+ virtual int usrp_i2c_read(boost::uint16_t i2c_addr,
+ unsigned char *buf,
+ boost::uint16_t len) = 0;
+
+ //! enable/disable the rx path
+ virtual void usrp_rx_enable(bool on) = 0;
+
+ //! enable/disable the tx path
+ virtual void usrp_tx_enable(bool on) = 0;
+};
+
+}} //namespace uhd::usrp
+
+#endif /* INCLUDED_LIBUHD_USRP_COMMON_FX2_CTRL_HPP */
diff --git a/host/lib/usrp/common/recv_packet_demuxer.cpp b/host/lib/usrp/common/recv_packet_demuxer.cpp
new file mode 100644
index 000000000..f2cfe3bb0
--- /dev/null
+++ b/host/lib/usrp/common/recv_packet_demuxer.cpp
@@ -0,0 +1,87 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program 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 of the License, or
+// (at your option) any later version.
+//
+// This program 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, see <http://www.gnu.org/licenses/>.
+//
+
+#include "recv_packet_demuxer.hpp"
+#include <uhd/utils/msg.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <boost/thread/mutex.hpp>
+#include <queue>
+#include <deque>
+#include <vector>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace uhd::transport;
+
+static UHD_INLINE boost::uint32_t extract_sid(managed_recv_buffer::sptr &buff){
+ //ASSUME that the data is in little endian format
+ return uhd::wtohx(buff->cast<const boost::uint32_t *>()[1]);
+}
+
+class recv_packet_demuxer_impl : public uhd::usrp::recv_packet_demuxer{
+public:
+ recv_packet_demuxer_impl(
+ transport::zero_copy_if::sptr transport,
+ const size_t size,
+ const boost::uint32_t sid_base
+ ):
+ _transport(transport), _sid_base(sid_base), _queues(size)
+ {
+ /* NOP */
+ }
+
+ managed_recv_buffer::sptr get_recv_buff(const size_t index, const double timeout){
+ boost::mutex::scoped_lock lock(_mutex);
+ managed_recv_buffer::sptr buff;
+
+ //there is already an entry in the queue, so pop that
+ if (not _queues[index].wrapper.empty()){
+ std::swap(buff, _queues[index].wrapper.front());
+ _queues[index].wrapper.pop();
+ return buff;
+ }
+
+ while (true){
+ //otherwise call into the transport
+ buff = _transport->get_recv_buff(timeout);
+ if (buff.get() == NULL) return buff; //timeout
+
+ //check the stream id to know which channel
+ const size_t rx_index = extract_sid(buff) - _sid_base;
+ if (rx_index == index) return buff; //got expected message
+
+ //otherwise queue and try again
+ if (rx_index < _queues.size()) _queues[rx_index].wrapper.push(buff);
+ else UHD_MSG(error) << "Got a data packet with unknown SID " << extract_sid(buff) << std::endl;
+ }
+ }
+
+private:
+ transport::zero_copy_if::sptr _transport;
+ const boost::uint32_t _sid_base;
+ boost::mutex _mutex;
+ struct channel_guts_type{
+ channel_guts_type(void): wrapper(container){}
+ std::deque<managed_recv_buffer::sptr> container;
+ std::queue<managed_recv_buffer::sptr> wrapper;
+ };
+ std::vector<channel_guts_type> _queues;
+};
+
+recv_packet_demuxer::sptr recv_packet_demuxer::make(transport::zero_copy_if::sptr transport, const size_t size, const boost::uint32_t sid_base){
+ return sptr(new recv_packet_demuxer_impl(transport, size, sid_base));
+}
diff --git a/host/lib/usrp/common/recv_packet_demuxer.hpp b/host/lib/usrp/common/recv_packet_demuxer.hpp
new file mode 100644
index 000000000..fde756d27
--- /dev/null
+++ b/host/lib/usrp/common/recv_packet_demuxer.hpp
@@ -0,0 +1,41 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program 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 of the License, or
+// (at your option) any later version.
+//
+// This program 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, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_USRP_COMMON_RECV_PACKET_DEMUXER_HPP
+#define INCLUDED_LIBUHD_USRP_COMMON_RECV_PACKET_DEMUXER_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/transport/zero_copy.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/cstdint.hpp>
+
+namespace uhd{ namespace usrp{
+
+ class recv_packet_demuxer{
+ public:
+ typedef boost::shared_ptr<recv_packet_demuxer> sptr;
+
+ //! Make a new demuxer from a transport and parameters
+ static sptr make(transport::zero_copy_if::sptr transport, const size_t size, const boost::uint32_t sid_base);
+
+ //! Get a buffer at the given index from the transport
+ virtual transport::managed_recv_buffer::sptr get_recv_buff(const size_t index, const double timeout) = 0;
+ };
+
+}} //namespace uhd::usrp
+
+#endif /* INCLUDED_LIBUHD_USRP_COMMON_RECV_PACKET_DEMUXER_HPP */
diff --git a/host/lib/usrp/common/validate_subdev_spec.cpp b/host/lib/usrp/common/validate_subdev_spec.cpp
new file mode 100644
index 000000000..fab40b204
--- /dev/null
+++ b/host/lib/usrp/common/validate_subdev_spec.cpp
@@ -0,0 +1,73 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program 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 of the License, or
+// (at your option) any later version.
+//
+// This program 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, see <http://www.gnu.org/licenses/>.
+//
+
+#include "validate_subdev_spec.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/assert_has.hpp>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+namespace uhd{ namespace usrp{
+
+ static std::ostream& operator<< (std::ostream &out, const subdev_spec_pair_t &pair){
+ out << pair.db_name << ":" << pair.sd_name;
+ return out;
+ }
+
+}}
+
+void uhd::usrp::validate_subdev_spec(
+ property_tree::sptr tree,
+ const subdev_spec_t &spec,
+ const std::string &type,
+ const std::string &mb
+){
+ const size_t num_dsps = tree->list(str(boost::format("/mboards/%s/%s_dsps") % mb % type)).size();
+
+ //sanity checking on the length
+ if (spec.size() == 0) throw uhd::value_error(str(boost::format(
+ "Empty %s subdevice specification is not supported.\n"
+ ) % type));
+ if (spec.size() > num_dsps) throw uhd::value_error(str(boost::format(
+ "The subdevice specification \"%s\" is too long.\n"
+ "The user specified %u channels, but there are only %u %s dsps on mboard %s.\n"
+ ) % spec.to_string() % spec.size() % num_dsps % type % mb));
+
+ //make a list of all possible specs
+ subdev_spec_t all_specs;
+ BOOST_FOREACH(const std::string &db, tree->list(str(boost::format("/mboards/%s/dboards") % mb))){
+ BOOST_FOREACH(const std::string &sd, tree->list(str(boost::format("/mboards/%s/dboards/%s/%s_frontends") % mb % db % type))){
+ all_specs.push_back(subdev_spec_pair_t(db, sd));
+ }
+ }
+
+ //validate that the spec is possible
+ BOOST_FOREACH(const subdev_spec_pair_t &pair, spec){
+ uhd::assert_has(all_specs, pair, str(boost::format("%s subdevice specification on mboard %s") % type % mb));
+ }
+
+ //enable selected frontends, disable others
+ BOOST_FOREACH(const subdev_spec_pair_t &pair, all_specs){
+ const bool enb = uhd::has(spec, pair);
+ tree->access<bool>(str(boost::format(
+ "/mboards/%s/dboards/%s/%s_frontends/%s/enabled"
+ ) % mb % pair.db_name % type % pair.sd_name)).set(enb);
+ }
+}
diff --git a/host/lib/usrp/common/validate_subdev_spec.hpp b/host/lib/usrp/common/validate_subdev_spec.hpp
new file mode 100644
index 000000000..7d9e2c309
--- /dev/null
+++ b/host/lib/usrp/common/validate_subdev_spec.hpp
@@ -0,0 +1,38 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program 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 of the License, or
+// (at your option) any later version.
+//
+// This program 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, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_USRP_COMMON_VALIDATE_SUBDEV_SPEC_HPP
+#define INCLUDED_LIBUHD_USRP_COMMON_VALIDATE_SUBDEV_SPEC_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/usrp/subdev_spec.hpp>
+#include <uhd/property_tree.hpp>
+#include <string>
+
+namespace uhd{ namespace usrp{
+
+ //! Validate a subdev spec against a property tree
+ void validate_subdev_spec(
+ property_tree::sptr tree,
+ const subdev_spec_t &spec,
+ const std::string &type, //rx or tx
+ const std::string &mb = "0"
+ );
+
+}} //namespace uhd::usrp
+
+#endif /* INCLUDED_LIBUHD_USRP_COMMON_VALIDATE_SUBDEV_SPEC_HPP */