summaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/usrp2
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/usrp2')
-rw-r--r--host/lib/usrp/usrp2/CMakeLists.txt1
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.cpp4
-rw-r--r--host/lib/usrp/usrp2/codec_impl.cpp96
-rw-r--r--host/lib/usrp/usrp2/dboard_iface.cpp2
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp63
-rw-r--r--host/lib/usrp/usrp2/fw_common.h22
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp71
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp72
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp38
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp16
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp7
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp22
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp15
13 files changed, 326 insertions, 103 deletions
diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt
index 99d0b8bdd..796126d07 100644
--- a/host/lib/usrp/usrp2/CMakeLists.txt
+++ b/host/lib/usrp/usrp2/CMakeLists.txt
@@ -22,6 +22,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.hpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.hpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_impl.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp
diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp
index b9be037c0..02227afad 100644
--- a/host/lib/usrp/usrp2/clock_ctrl.cpp
+++ b/host/lib/usrp/usrp2/clock_ctrl.cpp
@@ -86,7 +86,7 @@ public:
void set_rate_rx_dboard_clock(double rate){
assert_has(get_rates_rx_dboard_clock(), rate, "rx dboard clock rate");
- size_t divider = size_t(rate/get_master_clock_rate());
+ size_t divider = size_t(get_master_clock_rate()/rate);
//bypass when the divider ratio is one
_ad9510_regs.bypass_divider_out7 = (divider == 1)? 1 : 0;
//calculate the low and high dividers
@@ -118,7 +118,7 @@ public:
void set_rate_tx_dboard_clock(double rate){
assert_has(get_rates_tx_dboard_clock(), rate, "tx dboard clock rate");
- size_t divider = size_t(rate/get_master_clock_rate());
+ size_t divider = size_t(get_master_clock_rate()/rate);
//bypass when the divider ratio is one
_ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0;
//calculate the low and high dividers
diff --git a/host/lib/usrp/usrp2/codec_impl.cpp b/host/lib/usrp/usrp2/codec_impl.cpp
new file mode 100644
index 000000000..b9d51abf5
--- /dev/null
+++ b/host/lib/usrp/usrp2/codec_impl.cpp
@@ -0,0 +1,96 @@
+//
+// Copyright 2010 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 "usrp2_impl.hpp"
+#include <uhd/usrp/codec_props.hpp>
+#include <boost/bind.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+/***********************************************************************
+ * Helper Methods
+ **********************************************************************/
+void usrp2_mboard_impl::codec_init(void){
+ //make proxies
+ _rx_codec_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp2_mboard_impl::rx_codec_get, this, _1, _2),
+ boost::bind(&usrp2_mboard_impl::rx_codec_set, this, _1, _2)
+ );
+ _tx_codec_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp2_mboard_impl::tx_codec_get, this, _1, _2),
+ boost::bind(&usrp2_mboard_impl::tx_codec_set, this, _1, _2)
+ );
+}
+
+/***********************************************************************
+ * RX Codec Properties
+ **********************************************************************/
+void usrp2_mboard_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<codec_prop_t>()){
+ case CODEC_PROP_NAME:
+ val = std::string("usrp2 adc");
+ return;
+
+ case CODEC_PROP_OTHERS:
+ val = prop_names_t();
+ return;
+
+ case CODEC_PROP_GAIN_NAMES:
+ val = prop_names_t(); //no gain elements to be controlled
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void usrp2_mboard_impl::rx_codec_set(const wax::obj &, const wax::obj &){
+ UHD_THROW_PROP_SET_ERROR();
+}
+
+/***********************************************************************
+ * TX Codec Properties
+ **********************************************************************/
+void usrp2_mboard_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<codec_prop_t>()){
+ case CODEC_PROP_NAME:
+ val = std::string("usrp2 dac - ad9777");
+ return;
+
+ case CODEC_PROP_OTHERS:
+ val = prop_names_t();
+ return;
+
+ case CODEC_PROP_GAIN_NAMES:
+ val = prop_names_t(); //no gain elements to be controlled
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void usrp2_mboard_impl::tx_codec_set(const wax::obj &, const wax::obj &){
+ UHD_THROW_PROP_SET_ERROR();
+}
diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp
index 6f2fb9396..1b9a4bb97 100644
--- a/host/lib/usrp/usrp2/dboard_iface.cpp
+++ b/host/lib/usrp/usrp2/dboard_iface.cpp
@@ -37,6 +37,8 @@ public:
usrp2_dboard_iface(usrp2_iface::sptr iface, usrp2_clock_ctrl::sptr clock_ctrl);
~usrp2_dboard_iface(void);
+ std::string get_mboard_name(void){return "usrp2";}
+
void write_aux_dac(unit_t, aux_dac_t, float);
float read_aux_adc(unit_t, aux_adc_t);
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
index fa8d1a674..075f22388 100644
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ b/host/lib/usrp/usrp2/dboard_impl.cpp
@@ -15,10 +15,10 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-
#include "usrp2_impl.hpp"
#include "usrp2_regs.hpp"
#include "../dsp_utils.hpp"
+#include "../misc_utils.hpp"
#include <uhd/usrp/subdev_props.hpp>
#include <uhd/usrp/dboard_props.hpp>
#include <uhd/utils/assert.hpp>
@@ -35,8 +35,8 @@ using namespace uhd::usrp;
**********************************************************************/
void usrp2_mboard_impl::dboard_init(void){
//read the dboard eeprom to extract the dboard ids
- _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes()));
- _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes()));
+ _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(USRP2_I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes()));
+ _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(USRP2_I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes()));
//create a new dboard interface and manager
_dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl);
@@ -53,10 +53,6 @@ void usrp2_mboard_impl::dboard_init(void){
boost::bind(&usrp2_mboard_impl::tx_dboard_get, this, _1, _2),
boost::bind(&usrp2_mboard_impl::tx_dboard_set, this, _1, _2)
);
-
- //init the subdevs in use (use the first subdevice)
- rx_dboard_set(DBOARD_PROP_USED_SUBDEVS, prop_names_t(1, _dboard_manager->get_rx_subdev_names().at(0)));
- tx_dboard_set(DBOARD_PROP_USED_SUBDEVS, prop_names_t(1, _dboard_manager->get_tx_subdev_names().at(0)));
}
/***********************************************************************
@@ -80,10 +76,6 @@ void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_manager->get_rx_subdev_names();
return;
- case DBOARD_PROP_USED_SUBDEVS:
- val = _rx_subdevs_in_use;
- return;
-
case DBOARD_PROP_DBOARD_ID:
val = _rx_db_eeprom.id;
return;
@@ -92,27 +84,26 @@ void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_iface;
return;
+ case DBOARD_PROP_CODEC:
+ val = _rx_codec_proxy->get_link();
+ return;
+
+ case DBOARD_PROP_GAIN_GROUP:
+ val = make_gain_group(
+ _dboard_manager->get_rx_subdev(name), _rx_codec_proxy->get_link()
+ );
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){
switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_USED_SUBDEVS:{
- _rx_subdevs_in_use = val.as<prop_names_t>();
- UHD_ASSERT_THROW(_rx_subdevs_in_use.size() == 1);
- wax::obj rx_subdev = _dboard_manager->get_rx_subdev(_rx_subdevs_in_use.at(0));
- std::cout << "Using: " << rx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl;
- _iface->poke32(U2_REG_DSP_RX_MUX, dsp_type1::calc_rx_mux_word(
- rx_subdev[SUBDEV_PROP_QUADRATURE].as<bool>(),
- rx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>()
- ));
- }
- return;
case DBOARD_PROP_DBOARD_ID:
_rx_db_eeprom.id = val.as<dboard_id_t>();
- _iface->write_eeprom(I2C_ADDR_RX_DB, 0, _rx_db_eeprom.get_eeprom_bytes());
+ _iface->write_eeprom(USRP2_I2C_ADDR_RX_DB, 0, _rx_db_eeprom.get_eeprom_bytes());
return;
default: UHD_THROW_PROP_SET_ERROR();
@@ -140,10 +131,6 @@ void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_manager->get_tx_subdev_names();
return;
- case DBOARD_PROP_USED_SUBDEVS:
- val = _tx_subdevs_in_use;
- return;
-
case DBOARD_PROP_DBOARD_ID:
val = _tx_db_eeprom.id;
return;
@@ -152,26 +139,26 @@ void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_iface;
return;
+ case DBOARD_PROP_CODEC:
+ val = _tx_codec_proxy->get_link();
+ return;
+
+ case DBOARD_PROP_GAIN_GROUP:
+ val = make_gain_group(
+ _dboard_manager->get_tx_subdev(name), _tx_codec_proxy->get_link()
+ );
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){
switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_USED_SUBDEVS:{
- _tx_subdevs_in_use = val.as<prop_names_t>();
- UHD_ASSERT_THROW(_tx_subdevs_in_use.size() == 1);
- wax::obj tx_subdev = _dboard_manager->get_tx_subdev(_tx_subdevs_in_use.at(0));
- std::cout << "Using: " << tx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl;
- _iface->poke32(U2_REG_DSP_TX_MUX, dsp_type1::calc_tx_mux_word(
- tx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>()
- ));
- }
- return;
case DBOARD_PROP_DBOARD_ID:
_tx_db_eeprom.id = val.as<dboard_id_t>();
- _iface->write_eeprom(I2C_ADDR_TX_DB, 0, _tx_db_eeprom.get_eeprom_bytes());
+ _iface->write_eeprom(USRP2_I2C_ADDR_TX_DB, 0, _tx_db_eeprom.get_eeprom_bytes());
return;
default: UHD_THROW_PROP_SET_ERROR();
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index fd728e393..a781c1a21 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -32,9 +32,9 @@ extern "C" {
#define __stdint(type) type
#endif
-//defines the protocol version in this shared header
-//increment this value when the protocol is changed
-#define USRP2_PROTO_VERSION 5
+//fpga and firmware compatibility numbers
+#define USRP2_FPGA_COMPAT_NUM 1
+#define USRP2_FW_COMPAT_NUM 5
//used to differentiate control packets over data port
#define USRP2_INVALID_VRT_HEADER 0
@@ -44,6 +44,22 @@ extern "C" {
#define USRP2_UDP_CTRL_PORT 49152
#define USRP2_UDP_DATA_PORT 49153
+////////////////////////////////////////////////////////////////////////
+// I2C addresses
+////////////////////////////////////////////////////////////////////////
+#define USRP2_I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx
+#define USRP2_I2C_ADDR_MBOARD (USRP2_I2C_DEV_EEPROM | 0x0)
+#define USRP2_I2C_ADDR_TX_DB (USRP2_I2C_DEV_EEPROM | 0x4)
+#define USRP2_I2C_ADDR_RX_DB (USRP2_I2C_DEV_EEPROM | 0x5)
+
+////////////////////////////////////////////////////////////////////////
+// EEPROM Layout
+////////////////////////////////////////////////////////////////////////
+#define USRP2_EE_MBOARD_REV_LSB 0x00 //1 byte
+#define USRP2_EE_MBOARD_REV_MSB 0x01 //1 byte
+#define USRP2_EE_MBOARD_MAC_ADDR 0x02 //6 bytes
+#define USRP2_EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian
+
typedef enum{
USRP2_CTRL_ID_HUH_WHAT = ' ',
//USRP2_CTRL_ID_FOR_SURE, //TODO error condition enums
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 430f28390..9e29edd82 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -32,6 +32,8 @@ using namespace uhd::usrp;
using namespace uhd::transport;
namespace asio = boost::asio;
+static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET;
+
/***********************************************************************
* io impl details (internal to this file)
* - pirate crew
@@ -44,7 +46,8 @@ struct usrp2_impl::io_impl{
io_impl(size_t num_frames, size_t width):
packet_handler_recv_state(width),
- recv_pirate_booty(alignment_buffer_type::make(num_frames, width))
+ recv_pirate_booty(alignment_buffer_type::make(num_frames, width)),
+ async_msg_fifo(bounded_buffer<async_metadata_t>::make(100/*messages deep*/))
{
/* NOP */
}
@@ -55,9 +58,9 @@ struct usrp2_impl::io_impl{
recv_pirate_crew.join_all();
}
- bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){
+ bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, size_t timeout_ms){
boost::this_thread::disable_interruption di; //disable because the wait can throw
- return recv_pirate_booty->pop_elems_with_timed_wait(buffs, boost::posix_time::milliseconds(100));
+ return recv_pirate_booty->pop_elems_with_timed_wait(buffs, boost::posix_time::milliseconds(timeout_ms));
}
//state management for the vrt packet handler code
@@ -69,6 +72,7 @@ struct usrp2_impl::io_impl{
boost::thread_group recv_pirate_crew;
bool recv_pirate_crew_raiding;
alignment_buffer_type::sptr recv_pirate_booty;
+ bounded_buffer<async_metadata_t>::sptr async_msg_fifo;
};
/***********************************************************************
@@ -93,12 +97,31 @@ void usrp2_impl::io_impl::recv_pirate_loop(
//extract the vrt header packet info
vrt::if_packet_info_t if_packet_info;
if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t);
- vrt::if_hdr_unpack_be(buff->cast<const boost::uint32_t *>(), if_packet_info);
+ const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>();
+ vrt::if_hdr_unpack_be(vrt_hdr, if_packet_info);
+
+ //handle a tx async report message
+ if (if_packet_info.sid == 1 and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
+
+ //fill in the async metadata
+ async_metadata_t metadata;
+ metadata.channel = index;
+ metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf;
+ metadata.time_spec = time_spec_t(
+ time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), mboard->get_master_clock_freq()
+ );
+ metadata.event_code = vrt_packet_handler::get_context_code<async_metadata_t::event_code_t>(vrt_hdr, if_packet_info);
+
+ //print the famous U, and push the metadata into the message queue
+ if (metadata.event_code & underflow_flags) std::cerr << "U";
+ async_msg_fifo->push_with_pop_on_full(metadata);
+ continue;
+ }
//handle the packet count / sequence number
if (if_packet_info.packet_count != next_packet_seq){
//std::cerr << "S" << (if_packet_info.packet_count - next_packet_seq)%16;
- std::cerr << "O"; //report overrun (drops in the kernel)
+ std::cerr << "O"; //report overflow (drops in the kernel)
}
next_packet_seq = (if_packet_info.packet_count+1)%16;
@@ -121,11 +144,13 @@ void usrp2_impl::io_impl::recv_pirate_loop(
**********************************************************************/
void usrp2_impl::io_init(void){
//send a small data packet so the usrp2 knows the udp source port
- for(size_t i = 0; i < _data_transports.size(); i++){
- managed_send_buffer::sptr send_buff = _data_transports[i]->get_send_buff();
- boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER);
- memcpy(send_buff->cast<void*>(), &data, sizeof(data));
+ BOOST_FOREACH(zero_copy_if::sptr data_transport, _data_transports){
+ managed_send_buffer::sptr send_buff = data_transport->get_send_buff();
+ static const boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER);
+ std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));
send_buff->commit(sizeof(data));
+ //drain the recv buffers (may have junk)
+ while (data_transport->get_recv_buff().get());
}
//the number of recv frames is the number for the first transport
@@ -150,6 +175,18 @@ void usrp2_impl::io_init(void){
}
/***********************************************************************
+ * Async Data
+ **********************************************************************/
+bool usrp2_impl::recv_async_msg(
+ async_metadata_t &async_metadata, size_t timeout_ms
+){
+ boost::this_thread::disable_interruption di; //disable because the wait can throw
+ return _io_impl->async_msg_fifo->pop_with_timed_wait(
+ async_metadata, boost::posix_time::milliseconds(timeout_ms)
+ );
+}
+
+/***********************************************************************
* Send Data
**********************************************************************/
bool get_send_buffs(
@@ -164,10 +201,8 @@ bool get_send_buffs(
}
size_t usrp2_impl::send(
- const std::vector<const void *> &buffs,
- size_t num_samps,
- const tx_metadata_t &metadata,
- const io_type_t &io_type,
+ const std::vector<const void *> &buffs, size_t num_samps,
+ const tx_metadata_t &metadata, const io_type_t &io_type,
send_mode_t send_mode
){
return vrt_packet_handler::send(
@@ -186,11 +221,9 @@ size_t usrp2_impl::send(
* Receive Data
**********************************************************************/
size_t usrp2_impl::recv(
- const std::vector<void *> &buffs,
- size_t num_samps,
- rx_metadata_t &metadata,
- const io_type_t &io_type,
- recv_mode_t recv_mode
+ const std::vector<void *> &buffs, size_t num_samps,
+ rx_metadata_t &metadata, const io_type_t &io_type,
+ recv_mode_t recv_mode, size_t timeout_ms
){
return vrt_packet_handler::recv(
_io_impl->packet_handler_recv_state, //last state of the recv handler
@@ -199,6 +232,6 @@ size_t usrp2_impl::recv(
io_type, _io_helper.get_rx_otw_type(), //input and output types to convert
_mboards.front()->get_master_clock_freq(), //master clock tick rate
uhd::transport::vrt::if_hdr_unpack_be,
- boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1)
+ boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout_ms)
);
}
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 7518d3114..610aade14 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -45,8 +45,8 @@ usrp2_mboard_impl::usrp2_mboard_impl(
_iface = usrp2_iface::make(ctrl_transport);
//extract the mboard rev numbers
- _rev_lo = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_REV_LSB, 1).at(0);
- _rev_hi = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_REV_MSB, 1).at(0);
+ _rev_lo = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_LSB, 1).at(0);
+ _rev_hi = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_MSB, 1).at(0);
//contruct the interfaces to mboard perifs
_clock_ctrl = usrp2_clock_ctrl::make(_iface);
@@ -67,7 +67,7 @@ usrp2_mboard_impl::usrp2_mboard_impl(
_allowed_decim_and_interp_rates.push_back(i);
}
- //setup the vrt rx registers
+ //init the rx control registers
_iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _io_helper.get_max_recv_samps_per_packet());
_iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1);
_iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset
@@ -81,6 +81,12 @@ usrp2_mboard_impl::usrp2_mboard_impl(
_iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0);
_iface->poke32(U2_REG_TIME64_TPS, size_t(get_master_clock_freq()));
+ //init the tx control registers
+ _iface->poke32(U2_REG_TX_CTRL_NUM_CHAN, 0); //1 channel
+ _iface->poke32(U2_REG_TX_CTRL_CLEAR_STATE, 1); //reset
+ _iface->poke32(U2_REG_TX_CTRL_REPORT_SID, 1); //sid 1 (different from rx)
+ _iface->poke32(U2_REG_TX_CTRL_POLICY, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET);
+
//init the ddc
init_ddc_config();
@@ -90,8 +96,20 @@ usrp2_mboard_impl::usrp2_mboard_impl(
//initialize the clock configuration
init_clock_config();
+ //init the codec before the dboard
+ codec_init();
+
//init the tx and rx dboards (do last)
dboard_init();
+
+ //set default subdev specs
+ (*this)[MBOARD_PROP_RX_SUBDEV_SPEC] = subdev_spec_t();
+ (*this)[MBOARD_PROP_TX_SUBDEV_SPEC] = subdev_spec_t();
+
+ //Issue a stop streaming command (in case it was left running).
+ //Since this command is issued before the networking is setup,
+ //most if not all junk packets will never make it to the socket.
+ this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
}
usrp2_mboard_impl::~usrp2_mboard_impl(void){
@@ -174,14 +192,14 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){
//handle the other props
if (key.type() == typeid(std::string)){
if (key.as<std::string>() == "mac-addr"){
- byte_vector_t bytes = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, 6);
+ byte_vector_t bytes = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, 6);
val = mac_addr_t::from_bytes(bytes).to_string();
return;
}
if (key.as<std::string>() == "ip-addr"){
boost::asio::ip::address_v4::bytes_type bytes;
- std::copy(_iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, 4), bytes);
+ std::copy(_iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, 4), bytes);
val = boost::asio::ip::address_v4(bytes).to_string();
return;
}
@@ -252,6 +270,14 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){
}
return;
+ case MBOARD_PROP_RX_SUBDEV_SPEC:
+ val = _rx_subdev_spec;
+ return;
+
+ case MBOARD_PROP_TX_SUBDEV_SPEC:
+ val = _tx_subdev_spec;
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -264,14 +290,14 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){
if (key.type() == typeid(std::string)){
if (key.as<std::string>() == "mac-addr"){
byte_vector_t bytes = mac_addr_t::from_string(val.as<std::string>()).to_bytes();
- _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, bytes);
+ _iface->write_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, bytes);
return;
}
if (key.as<std::string>() == "ip-addr"){
byte_vector_t bytes(4);
std::copy(boost::asio::ip::address_v4::from_string(val.as<std::string>()).to_bytes(), bytes);
- _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, bytes);
+ _iface->write_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, bytes);
return;
}
}
@@ -296,6 +322,38 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){
issue_ddc_stream_cmd(val.as<stream_cmd_t>());
return;
+ case MBOARD_PROP_RX_SUBDEV_SPEC:
+ _rx_subdev_spec = val.as<subdev_spec_t>();
+ //handle automatic
+ if (_rx_subdev_spec.empty()) _rx_subdev_spec.push_back(
+ subdev_spec_pair_t("", _dboard_manager->get_rx_subdev_names().front())
+ );
+ //sanity check
+ UHD_ASSERT_THROW(_rx_subdev_spec.size() == 1);
+ uhd::assert_has((*this)[MBOARD_PROP_RX_DBOARD_NAMES].as<prop_names_t>(), _rx_subdev_spec.front().db_name, "rx dboard names");
+ uhd::assert_has(_dboard_manager->get_rx_subdev_names(), _rx_subdev_spec.front().sd_name, "rx subdev names");
+ //set the mux
+ _iface->poke32(U2_REG_DSP_RX_MUX, dsp_type1::calc_rx_mux_word(
+ _dboard_manager->get_rx_subdev(_rx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
+ ));
+ return;
+
+ case MBOARD_PROP_TX_SUBDEV_SPEC:
+ _tx_subdev_spec = val.as<subdev_spec_t>();
+ //handle automatic
+ if (_tx_subdev_spec.empty()) _tx_subdev_spec.push_back(
+ subdev_spec_pair_t("", _dboard_manager->get_tx_subdev_names().front())
+ );
+ //sanity check
+ UHD_ASSERT_THROW(_tx_subdev_spec.size() == 1);
+ uhd::assert_has((*this)[MBOARD_PROP_TX_DBOARD_NAMES].as<prop_names_t>(), _tx_subdev_spec.front().db_name, "tx dboard names");
+ uhd::assert_has(_dboard_manager->get_tx_subdev_names(), _tx_subdev_spec.front().sd_name, "tx subdev names");
+ //set the mux
+ _iface->poke32(U2_REG_DSP_TX_MUX, dsp_type1::calc_tx_mux_word(
+ _dboard_manager->get_tx_subdev(_tx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
+ ));
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index eaaa722ac..4124221ef 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "usrp2_regs.hpp"
#include "usrp2_iface.hpp"
#include <uhd/utils/assert.hpp>
#include <uhd/types/dict.hpp>
@@ -22,12 +23,25 @@
#include <boost/foreach.hpp>
#include <boost/asio.hpp> //used for htonl and ntohl
#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
#include <stdexcept>
#include <algorithm>
using namespace uhd;
using namespace uhd::transport;
+/*!
+ * FIXME: large timeout, ethernet pause frames...
+ *
+ * Use a large timeout to work-around the fact that
+ * flow-control may throttle outgoing control packets
+ * due to its use of ethernet pause frames.
+ *
+ * This will be fixed when host-based flow control is implemented,
+ * along with larger incoming send buffers using the on-board SRAM.
+ */
+static const size_t CONTROL_TIMEOUT_MS = 3000; //3 seconds
+
class usrp2_iface_impl : public usrp2_iface{
public:
/***********************************************************************
@@ -35,6 +49,15 @@ public:
**********************************************************************/
usrp2_iface_impl(udp_simple::sptr ctrl_transport){
_ctrl_transport = ctrl_transport;
+
+ //check the fpga compatibility number
+ const boost::uint32_t fpga_compat_num = this->peek32(U2_REG_COMPAT_NUM_RB);
+ if (fpga_compat_num != USRP2_FPGA_COMPAT_NUM){
+ throw std::runtime_error(str(boost::format(
+ "Expected fpga compatibility number %d, but got %d:\n"
+ "The fpga build is not compatible with the host code build."
+ ) % int(USRP2_FPGA_COMPAT_NUM) % fpga_compat_num));
+ }
}
~usrp2_iface_impl(void){
@@ -156,7 +179,7 @@ public:
//fill in the seq number and send
usrp2_ctrl_data_t out_copy = out_data;
- out_copy.proto_ver = htonl(USRP2_PROTO_VERSION);
+ out_copy.proto_ver = htonl(USRP2_FW_COMPAT_NUM);
out_copy.seq = htonl(++_ctrl_seq_num);
_ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t)));
@@ -164,13 +187,12 @@ public:
boost::uint8_t usrp2_ctrl_data_in_mem[udp_simple::mtu]; //allocate max bytes for recv
const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<const usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem);
while(true){
- size_t len = _ctrl_transport->recv(boost::asio::buffer(usrp2_ctrl_data_in_mem));
- if(len >= sizeof(boost::uint32_t) and ntohl(ctrl_data_in->proto_ver) != USRP2_PROTO_VERSION){
- throw std::runtime_error(str(
- boost::format("Expected protocol version %d, but got %d\n"
- "The firmware build does not match the host code build."
- ) % int(USRP2_PROTO_VERSION) % ntohl(ctrl_data_in->proto_ver)
- ));
+ size_t len = _ctrl_transport->recv(boost::asio::buffer(usrp2_ctrl_data_in_mem), CONTROL_TIMEOUT_MS);
+ if(len >= sizeof(boost::uint32_t) and ntohl(ctrl_data_in->proto_ver) != USRP2_FW_COMPAT_NUM){
+ throw std::runtime_error(str(boost::format(
+ "Expected protocol compatibility number %d, but got %d:\n"
+ "The firmware build is not compatible with the host code build."
+ ) % int(USRP2_FW_COMPAT_NUM) % ntohl(ctrl_data_in->proto_ver)));
}
if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(ctrl_data_in->seq) == _ctrl_seq_num){
return *ctrl_data_in;
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
index 9cc32104e..12fd4730a 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.hpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.hpp
@@ -26,22 +26,6 @@
#include <utility>
#include "fw_common.h"
-////////////////////////////////////////////////////////////////////////
-// I2C addresses
-////////////////////////////////////////////////////////////////////////
-#define I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx
-#define I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0)
-#define I2C_ADDR_TX_DB (I2C_DEV_EEPROM | 0x4)
-#define I2C_ADDR_RX_DB (I2C_DEV_EEPROM | 0x5)
-
-////////////////////////////////////////////////////////////////////////
-// EEPROM Layout
-////////////////////////////////////////////////////////////////////////
-#define EE_MBOARD_REV_LSB 0x00 //1 byte
-#define EE_MBOARD_REV_MSB 0x01 //1 byte
-#define EE_MBOARD_MAC_ADDR 0x02 //6 bytes
-#define EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian
-
/*!
* The usrp2 interface class:
* Provides a set of functions to implementation layer.
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 02f53bc69..21f411afe 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -35,6 +35,9 @@ using namespace uhd::usrp;
using namespace uhd::transport;
namespace asio = boost::asio;
+//! wait this long for a control response when discovering devices
+static const size_t DISCOVERY_TIMEOUT_MS = 100;
+
/***********************************************************************
* Helper Functions
**********************************************************************/
@@ -94,7 +97,7 @@ static uhd::device_addrs_t usrp2_find(const device_addr_t &hint){
//send a hello control packet
usrp2_ctrl_data_t ctrl_data_out;
- ctrl_data_out.proto_ver = htonl(USRP2_PROTO_VERSION);
+ ctrl_data_out.proto_ver = htonl(USRP2_FW_COMPAT_NUM);
ctrl_data_out.id = htonl(USRP2_CTRL_ID_WAZZUP_BRO);
udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out)));
@@ -102,7 +105,7 @@ static uhd::device_addrs_t usrp2_find(const device_addr_t &hint){
boost::uint8_t usrp2_ctrl_data_in_mem[udp_simple::mtu]; //allocate max bytes for recv
const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<const usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem);
while(true){
- size_t len = udp_transport->recv(asio::buffer(usrp2_ctrl_data_in_mem));
+ size_t len = udp_transport->recv(asio::buffer(usrp2_ctrl_data_in_mem), DISCOVERY_TIMEOUT_MS);
//std::cout << len << "\n";
if (len > offsetof(usrp2_ctrl_data_t, data)){
//handle the received data
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index ab23830c0..157d17057 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -35,6 +35,7 @@
#include <uhd/transport/udp_simple.hpp> //mtu
#include <uhd/transport/udp_zero_copy.hpp>
#include <uhd/usrp/dboard_manager.hpp>
+#include <uhd/usrp/subdev_spec.hpp>
/*!
* Make a usrp2 dboard interface.
@@ -143,6 +144,7 @@ private:
//properties for this mboard
void get(const wax::obj &, wax::obj &);
void set(const wax::obj &, const wax::obj &);
+ uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec;
//interfaces
usrp2_iface::sptr _iface;
@@ -161,18 +163,25 @@ private:
void update_clock_config(void);
void set_time_spec(const uhd::time_spec_t &time_spec, bool now);
+ //properties interface for the codec
+ void codec_init(void);
+ void rx_codec_get(const wax::obj &, wax::obj &);
+ void rx_codec_set(const wax::obj &, const wax::obj &);
+ void tx_codec_get(const wax::obj &, wax::obj &);
+ void tx_codec_set(const wax::obj &, const wax::obj &);
+ wax_obj_proxy::sptr _rx_codec_proxy;
+ wax_obj_proxy::sptr _tx_codec_proxy;
+
//properties interface for rx dboard
void rx_dboard_get(const wax::obj &, wax::obj &);
void rx_dboard_set(const wax::obj &, const wax::obj &);
wax_obj_proxy::sptr _rx_dboard_proxy;
- uhd::prop_names_t _rx_subdevs_in_use;
uhd::usrp::dboard_eeprom_t _rx_db_eeprom;
//properties interface for tx dboard
void tx_dboard_get(const wax::obj &, wax::obj &);
void tx_dboard_set(const wax::obj &, const wax::obj &);
wax_obj_proxy::sptr _tx_dboard_proxy;
- uhd::prop_names_t _tx_subdevs_in_use;
uhd::usrp::dboard_eeprom_t _tx_db_eeprom;
//methods and shadows for the ddc dsp
@@ -224,8 +233,7 @@ public:
}
size_t send(
const std::vector<const void *> &, size_t,
- const uhd::tx_metadata_t &,
- const uhd::io_type_t &,
+ const uhd::tx_metadata_t &, const uhd::io_type_t &,
uhd::device::send_mode_t
);
size_t get_max_recv_samps_per_packet(void) const{
@@ -233,10 +241,10 @@ public:
}
size_t recv(
const std::vector<void *> &, size_t,
- uhd::rx_metadata_t &,
- const uhd::io_type_t &,
- uhd::device::recv_mode_t
+ uhd::rx_metadata_t &, const uhd::io_type_t &,
+ uhd::device::recv_mode_t, size_t
);
+ bool recv_async_msg(uhd::async_metadata_t &, size_t);
private:
//device properties interface
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index 1a5864c85..9d306090b 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -107,6 +107,7 @@
#define U2_REG_TIME64_SECS_RB (0xCC00 + 4*10)
#define U2_REG_TIME64_TICKS_RB (0xCC00 + 4*11)
+#define U2_REG_COMPAT_NUM_RB (0xCC00 + 4*12)
//pps flags (see above)
#define U2_FLAG_TIME64_PPS_NEGEDGE (0 << 0)
@@ -226,7 +227,7 @@
#define U2_REG_ATR_FULL_RXSIDE U2_REG_ATR_BASE + 14
///////////////////////////////////////////////////
-// VITA RX CTRL regs
+// RX CTRL regs
///////////////////////////////////////////////////
// The following 3 are logically a single command register.
// They are clocked into the underlying fifo when time_ticks is written.
@@ -241,4 +242,16 @@
#define U2_REG_RX_CTRL_NSAMPS_PER_PKT _SR_ADDR(SR_RX_CTRL + 7)
#define U2_REG_RX_CTRL_NCHANNELS _SR_ADDR(SR_RX_CTRL + 8) // 1 in basic case, up to 4 for vector sources
+///////////////////////////////////////////////////
+// TX CTRL regs
+///////////////////////////////////////////////////
+#define U2_REG_TX_CTRL_NUM_CHAN _SR_ADDR(SR_TX_CTRL + 0)
+#define U2_REG_TX_CTRL_CLEAR_STATE _SR_ADDR(SR_TX_CTRL + 1)
+#define U2_REG_TX_CTRL_REPORT_SID _SR_ADDR(SR_TX_CTRL + 2)
+#define U2_REG_TX_CTRL_POLICY _SR_ADDR(SR_TX_CTRL + 3)
+
+#define U2_FLAG_TX_CTRL_POLICY_WAIT (0x1 << 0)
+#define U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET (0x1 << 1)
+#define U2_FLAG_TX_CTRL_POLICY_NEXT_BURST (0x1 << 2)
+
#endif /* INCLUDED_USRP2_REGS_HPP */