diff options
Diffstat (limited to 'host/lib/usrp/b100')
-rw-r--r-- | host/lib/usrp/b100/CMakeLists.txt | 15 | ||||
-rw-r--r-- | host/lib/usrp/b100/b100_ctrl.cpp | 147 | ||||
-rw-r--r-- | host/lib/usrp/b100/b100_ctrl.hpp | 17 | ||||
-rw-r--r-- | host/lib/usrp/b100/b100_iface.cpp | 335 | ||||
-rw-r--r-- | host/lib/usrp/b100/b100_iface.hpp | 78 | ||||
-rw-r--r-- | host/lib/usrp/b100/b100_impl.cpp | 363 | ||||
-rw-r--r-- | host/lib/usrp/b100/b100_impl.hpp | 203 | ||||
-rw-r--r-- | host/lib/usrp/b100/b100_regs.hpp | 141 | ||||
-rw-r--r-- | host/lib/usrp/b100/clock_ctrl.cpp | 19 | ||||
-rw-r--r-- | host/lib/usrp/b100/clock_ctrl.hpp | 6 | ||||
-rw-r--r-- | host/lib/usrp/b100/codec_ctrl.cpp | 8 | ||||
-rw-r--r-- | host/lib/usrp/b100/codec_ctrl.hpp | 4 | ||||
-rw-r--r-- | host/lib/usrp/b100/codec_impl.cpp | 149 | ||||
-rw-r--r-- | host/lib/usrp/b100/dboard_iface.cpp | 59 | ||||
-rw-r--r-- | host/lib/usrp/b100/dboard_impl.cpp | 185 | ||||
-rw-r--r-- | host/lib/usrp/b100/dsp_impl.cpp | 217 | ||||
-rw-r--r-- | host/lib/usrp/b100/io_impl.cpp | 240 | ||||
-rw-r--r-- | host/lib/usrp/b100/mboard_impl.cpp | 282 |
18 files changed, 624 insertions, 1844 deletions
diff --git a/host/lib/usrp/b100/CMakeLists.txt b/host/lib/usrp/b100/CMakeLists.txt index 28429c186..1237f52d1 100644 --- a/host/lib/usrp/b100/CMakeLists.txt +++ b/host/lib/usrp/b100/CMakeLists.txt @@ -26,22 +26,11 @@ LIBUHD_REGISTER_COMPONENT("B100" ENABLE_B100 ON "ENABLE_LIBUHD;ENABLE_USB" OFF) IF(ENABLE_B100) LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/b100_ctrl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/b100_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.hpp ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/ctrl_packet.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/b100_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/b100_ctrl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/b100_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/b100_iface.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/b100_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/b100_impl.hpp ) ENDIF(ENABLE_B100) diff --git a/host/lib/usrp/b100/b100_ctrl.cpp b/host/lib/usrp/b100/b100_ctrl.cpp index 6d415facc..5b03fd591 100644 --- a/host/lib/usrp/b100/b100_ctrl.cpp +++ b/host/lib/usrp/b100/b100_ctrl.cpp @@ -15,9 +15,8 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include "../../transport/super_recv_packet_handler.hpp" #include "b100_ctrl.hpp" -#include "b100_impl.hpp" +#include <uhd/transport/bounded_buffer.hpp> #include <uhd/transport/usb_zero_copy.hpp> #include <uhd/transport/zero_copy.hpp> #include <uhd/transport/vrt_if_packet.hpp> @@ -36,9 +35,8 @@ bool b100_ctrl_debug = false; class b100_ctrl_impl : public b100_ctrl { public: - b100_ctrl_impl(uhd::transport::usb_zero_copy::sptr ctrl_transport) : + b100_ctrl_impl(uhd::transport::zero_copy_if::sptr ctrl_transport): sync_ctrl_fifo(2), - async_msg_fifo(100), _ctrl_transport(ctrl_transport), _seq(0) { @@ -46,29 +44,65 @@ public: viking_marauders.create_thread(boost::bind(&b100_ctrl_impl::viking_marauder_loop, this, boost::ref(spawn_barrier))); spawn_barrier.wait(); } - + int write(boost::uint32_t addr, const ctrl_data_t &data); ctrl_data_t read(boost::uint32_t addr, size_t len); - + ~b100_ctrl_impl(void) { viking_marauders.interrupt_all(); viking_marauders.join_all(); } - + bool get_ctrl_data(ctrl_data_t &pkt_data, double timeout); - bool recv_async_msg(uhd::async_metadata_t &async_metadata, double timeout); - + + void poke32(wb_addr_type addr, boost::uint32_t data){ + boost::mutex::scoped_lock lock(_ctrl_mutex); + + ctrl_data_t words(2); + words[0] = data & 0x0000FFFF; + words[1] = data >> 16; + this->write(addr, words); + } + + boost::uint32_t peek32(wb_addr_type addr){ + boost::mutex::scoped_lock lock(_ctrl_mutex); + + ctrl_data_t words = this->read(addr, 2); + return boost::uint32_t((boost::uint32_t(words[1]) << 16) | words[0]); + } + + void poke16(wb_addr_type addr, boost::uint16_t data){ + boost::mutex::scoped_lock lock(_ctrl_mutex); + + ctrl_data_t words(1); + words[0] = data; + this->write(addr, words); + } + + boost::uint16_t peek16(wb_addr_type addr){ + boost::mutex::scoped_lock lock(_ctrl_mutex); + + ctrl_data_t words = this->read(addr, 1); + return boost::uint16_t(words[0]); + } + + void set_async_cb(const async_cb_type &async_cb){ + boost::mutex::scoped_lock lock(_async_mutex); + _async_cb = async_cb; + } + private: int send_pkt(boost::uint16_t *cmd); - + //änd hërë wë gö ä-Vïkïng för äsynchronous control packets void viking_marauder_loop(boost::barrier &); bounded_buffer<ctrl_data_t> sync_ctrl_fifo; - bounded_buffer<async_metadata_t> async_msg_fifo; + async_cb_type _async_cb; boost::thread_group viking_marauders; - - uhd::transport::usb_zero_copy::sptr _ctrl_transport; + + uhd::transport::zero_copy_if::sptr _ctrl_transport; boost::uint8_t _seq; + boost::mutex _ctrl_mutex, _async_mutex; }; /*********************************************************************** @@ -86,7 +120,7 @@ void pack_ctrl_pkt(boost::uint16_t *pkt_buff, pkt_buff[1] = pkt.pkt_meta.len; pkt_buff[2] = (pkt.pkt_meta.addr & 0x00000FFF); pkt_buff[3] = 0x0000; //address high bits always 0 on this device - + for(size_t i = 0; i < pkt.data.size(); i++) { pkt_buff[4+i] = pkt.data[i]; } @@ -99,7 +133,7 @@ void unpack_ctrl_pkt(const boost::uint16_t *pkt_buff, pkt.pkt_meta.len = pkt_buff[1]; pkt.pkt_meta.callbacks = 0; //callbacks aren't implemented yet pkt.pkt_meta.addr = pkt_buff[2] | boost::uint32_t(pkt_buff[3] << 16); - + //let's check this so we don't go pushing 64K of crap onto the pkt if(pkt.pkt_meta.len > CTRL_PACKET_DATA_LENGTH) { throw uhd::runtime_error("Received control packet too long"); @@ -113,7 +147,7 @@ int b100_ctrl_impl::send_pkt(boost::uint16_t *cmd) { if(!sbuf.get()) { throw uhd::runtime_error("Control channel send error"); } - + //FIXME there's a better way to do this for(size_t i = 0; i < (CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)); i++) { sbuf->cast<boost::uint16_t *>()[i] = cmd[i]; @@ -132,7 +166,7 @@ int b100_ctrl_impl::write(boost::uint32_t addr, const ctrl_data_t &data) { pkt.pkt_meta.len = pkt.data.size(); pkt.pkt_meta.addr = addr; boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)]; - + pack_ctrl_pkt(pkt_buff, pkt); size_t result = send_pkt(pkt_buff); return result; @@ -149,11 +183,18 @@ ctrl_data_t b100_ctrl_impl::read(boost::uint32_t addr, size_t len) { pkt.pkt_meta.addr = addr; boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)]; + //flush anything that might be in the queue + while (get_ctrl_data(pkt.data, 0.0)){ + UHD_MSG(error) << "B100: control read found unexpected packet." << std::endl; + } + pack_ctrl_pkt(pkt_buff, pkt); send_pkt(pkt_buff); - - //loop around waiting for the response to appear - while(!get_ctrl_data(pkt.data, 0.05)); + + //block with timeout waiting for the response to appear + if (not get_ctrl_data(pkt.data, 0.1)) throw uhd::runtime_error( + "B100: timeout waiting for control response packet." + ); return pkt.data; } @@ -168,55 +209,38 @@ ctrl_data_t b100_ctrl_impl::read(boost::uint32_t addr, size_t len) { void b100_ctrl_impl::viking_marauder_loop(boost::barrier &spawn_barrier) { spawn_barrier.wait(); set_thread_priority_safe(); - + while (not boost::this_thread::interruption_requested()){ - managed_recv_buffer::sptr rbuf = _ctrl_transport->get_recv_buff(); - if(!rbuf.get()) continue; //that's ok, there are plenty of villages to pillage! + managed_recv_buffer::sptr rbuf = _ctrl_transport->get_recv_buff(1.0); + if(rbuf.get() == NULL) continue; //that's ok, there are plenty of villages to pillage! const boost::uint16_t *pkt_buf = rbuf->cast<const boost::uint16_t *>(); - + if(pkt_buf[0] >> 8 == CTRL_PACKET_HEADER_MAGIC) { //so it's got a control packet header, let's parse it. ctrl_pkt_t pkt; unpack_ctrl_pkt(pkt_buf, pkt); - + if(pkt.pkt_meta.seq != boost::uint8_t(_seq - 1)) { - throw uhd::runtime_error("Sequence error on control channel"); + UHD_MSG(error) + << "Sequence error on control channel." << std::endl + << "Exiting control loop." << std::endl + ; + return; } if(pkt.pkt_meta.len > (CTRL_PACKET_LENGTH - CTRL_PACKET_HEADER_LENGTH)) { - throw uhd::runtime_error("Control channel packet length too long"); + UHD_MSG(error) + << "Control channel packet length too long" << std::endl + << "Exiting control loop." << std::endl + ; + return; } - + //push it onto the queue - sync_ctrl_fifo.push_with_wait(pkt.data); - } else { //it's an async status pkt - //extract the vrt header packet info - vrt::if_packet_info_t if_packet_info; - if_packet_info.num_packet_words32 = rbuf->size()/sizeof(boost::uint32_t); - const boost::uint32_t *vrt_hdr = rbuf->cast<const boost::uint32_t *>(); - vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info); - - if( if_packet_info.sid == B100_ASYNC_SID - 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 = 0; - 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), 64e6 //FIXME get from clock_ctrl - ); - metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info)); - async_msg_fifo.push_with_pop_on_full(metadata); - if (metadata.event_code & - ( async_metadata_t::EVENT_CODE_UNDERFLOW - | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) - ) UHD_MSG(fastpath) << "U"; - else if (metadata.event_code & - ( async_metadata_t::EVENT_CODE_SEQ_ERROR - | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) - ) UHD_MSG(fastpath) << "S"; - continue; - } - UHD_MSG(error) << "Control: unknown async response" << std::endl; + sync_ctrl_fifo.push_with_pop_on_full(pkt.data); + } + else{ //otherwise let the async callback handle it + boost::mutex::scoped_lock lock(_async_mutex); + if (not _async_cb.empty()) _async_cb(rbuf); } } } @@ -226,14 +250,9 @@ bool b100_ctrl_impl::get_ctrl_data(ctrl_data_t &pkt_data, double timeout){ return sync_ctrl_fifo.pop_with_timed_wait(pkt_data, timeout); } -bool b100_ctrl_impl::recv_async_msg(uhd::async_metadata_t &async_metadata, double timeout) { - boost::this_thread::disable_interruption di; //disable because the wait can throw - return async_msg_fifo.pop_with_timed_wait(async_metadata, timeout); -} - /*********************************************************************** * Public make function for b100_ctrl interface **********************************************************************/ -b100_ctrl::sptr b100_ctrl::make(uhd::transport::usb_zero_copy::sptr ctrl_transport){ +b100_ctrl::sptr b100_ctrl::make(uhd::transport::zero_copy_if::sptr ctrl_transport){ return sptr(new b100_ctrl_impl(ctrl_transport)); } diff --git a/host/lib/usrp/b100/b100_ctrl.hpp b/host/lib/usrp/b100/b100_ctrl.hpp index 17887181d..74884d525 100644 --- a/host/lib/usrp/b100/b100_ctrl.hpp +++ b/host/lib/usrp/b100/b100_ctrl.hpp @@ -18,25 +18,28 @@ #ifndef INCLUDED_B100_CTRL_HPP #define INCLUDED_B100_CTRL_HPP -#include <uhd/transport/bounded_buffer.hpp> +#include "wb_iface.hpp" #include <uhd/transport/usb_zero_copy.hpp> -#include <uhd/types/metadata.hpp> #include <uhd/types/serial.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> #include "ctrl_packet.hpp" -#include <boost/thread.hpp> +#include <boost/function.hpp> -class b100_ctrl : boost::noncopyable{ +class b100_ctrl : boost::noncopyable, public wb_iface{ public: typedef boost::shared_ptr<b100_ctrl> sptr; + typedef boost::function<void(uhd::transport::managed_recv_buffer::sptr)> async_cb_type; /*! * Make a USRP control object from a data transport * \param ctrl_transport a USB data transport * \return a new b100 control object */ - static sptr make(uhd::transport::usb_zero_copy::sptr ctrl_transport); + static sptr make(uhd::transport::zero_copy_if::sptr ctrl_transport); + + //! set an async callback for messages + virtual void set_async_cb(const async_cb_type &async_cb) = 0; /*! * Write a byte vector to an FPGA register @@ -61,9 +64,7 @@ public: * \return true if it got something */ virtual bool get_ctrl_data(ctrl_data_t &pkt_data, double timeout) = 0; - - virtual bool recv_async_msg(uhd::async_metadata_t &async_metadata, double timeout) = 0; - + }; #endif /* INCLUDED_B100_CTRL_HPP */ diff --git a/host/lib/usrp/b100/b100_iface.cpp b/host/lib/usrp/b100/b100_iface.cpp deleted file mode 100644 index f0e241541..000000000 --- a/host/lib/usrp/b100/b100_iface.cpp +++ /dev/null @@ -1,335 +0,0 @@ -// -// 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 "b100_impl.hpp" -#include "usrp_commands.h" -#include <uhd/exception.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/safe_call.hpp> -#include <uhd/utils/msg.hpp> -#include <boost/format.hpp> -#include <iomanip> -#include <iostream> - -//FOR TESTING ONLY -#include "b100_regs.hpp" -#include <boost/thread/thread.hpp> -#include "usrp_i2c_addr.h" - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::transport; - -/*********************************************************************** - * Constants - **********************************************************************/ -static const bool iface_debug = true; - -/*********************************************************************** - * I2C + FX2 implementation wrapper - **********************************************************************/ -class b100_i2c_fx2_iface : public i2c_iface{ -public: - b100_i2c_fx2_iface(uhd::usrp::fx2_ctrl::sptr fx2_ctrl){ - _fx2_ctrl = fx2_ctrl; - } - - 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 = _fx2_ctrl->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 = _fx2_ctrl->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: - static const size_t max_i2c_data_bytes = 64; - uhd::usrp::fx2_ctrl::sptr _fx2_ctrl; -}; - -/*********************************************************************** - * USRP-E100 interface implementation - **********************************************************************/ -class b100_iface_impl : public b100_iface{ -public: - /******************************************************************* - * Structors - ******************************************************************/ - b100_iface_impl(uhd::usrp::fx2_ctrl::sptr fx2_ctrl, - b100_ctrl::sptr fpga_ctrl) : - _fx2_i2c_iface(fx2_ctrl), - _fx2_ctrl(fx2_ctrl), - _fpga_ctrl(fpga_ctrl) - { - this->check_fw_compat(); - if (fpga_ctrl.get() != NULL){ - enable_gpif(1); - i2c_init(); - this->check_fpga_compat(); - } - mb_eeprom = mboard_eeprom_t(get_fx2_i2c_iface(), mboard_eeprom_t::MAP_B000); - } - - void check_fw_compat(void){ - unsigned char data[4]; //useless data buffer - const boost::uint16_t fw_compat_num = _fx2_ctrl->usrp_control_read( - VRQ_FW_COMPAT, 0, 0, data, sizeof(data) - ); - if (fw_compat_num != B100_FW_COMPAT_NUM){ - throw uhd::runtime_error(str(boost::format( - "Expected firmware compatibility number 0x%x, but got 0x%x:\n" - "The firmware build is not compatible with the host code build." - ) % B100_FW_COMPAT_NUM % fw_compat_num)); - } - } - - void check_fpga_compat(void){ - const boost::uint16_t fpga_compat_num = this->peek16(B100_REG_MISC_COMPAT); - if (fpga_compat_num != B100_FPGA_COMPAT_NUM){ - throw uhd::runtime_error(str(boost::format( - "Expected FPGA compatibility number 0x%x, but got 0x%x:\n" - "The FPGA build is not compatible with the host code build." - ) % B100_FPGA_COMPAT_NUM % fpga_compat_num)); - } - } - - ~b100_iface_impl(void) - { - /* NOP */ - } - - /******************************************************************* - * Peek and Poke - ******************************************************************/ - - void poke(boost::uint32_t addr, const ctrl_data_t &data) { - boost::mutex::scoped_lock lock(_ctrl_mutex); - _fpga_ctrl->write(addr, data); - } - - ctrl_data_t peek(boost::uint32_t addr, size_t len) { - boost::mutex::scoped_lock lock(_ctrl_mutex); - return _fpga_ctrl->read(addr, len); - } - - void poke16(boost::uint32_t addr, boost::uint16_t value) - { - ctrl_data_t words(1); - words[0] = value; - poke(addr, words); - } - - void poke32(boost::uint32_t addr, boost::uint32_t value) - { - //just a subset of poke() to maintain compatibility - ctrl_data_t words(2); - words[0] = value & 0x0000FFFF; - words[1] = value >> 16; - poke(addr, words); - } - - boost::uint32_t peek32(boost::uint32_t addr) - { - ctrl_data_t words = peek(addr, 2); - return boost::uint32_t((boost::uint32_t(words[1]) << 16) | words[0]); - } - - boost::uint16_t peek16(boost::uint32_t addr) - { - ctrl_data_t words = peek(addr, 1); - return boost::uint16_t(words[0]); - } - - /******************************************************************* - * I2C - ******************************************************************/ - static const boost::uint32_t i2c_datarate = 400000; - static const boost::uint32_t wishbone_clk = 64000000; //FIXME should go somewhere else - - void i2c_init(void) { - //init I2C FPGA interface. - poke16(B100_REG_I2C_CTRL, 0x0000); - //set prescalers to operate at 400kHz: WB_CLK is 64MHz... - boost::uint16_t prescaler = wishbone_clk / (i2c_datarate*5) - 1; - poke16(B100_REG_I2C_PRESCALER_LO, prescaler & 0xFF); - poke16(B100_REG_I2C_PRESCALER_HI, (prescaler >> 8) & 0xFF); - poke16(B100_REG_I2C_CTRL, I2C_CTRL_EN); //enable I2C core - } - - static const size_t max_i2c_data_bytes = 64; - - void i2c_wait_for_xfer(void) - { - while(this->peek16(B100_REG_I2C_CMD_STATUS) & I2C_ST_TIP) - boost::this_thread::sleep(boost::posix_time::milliseconds(10)); - } - - bool wait_chk_ack(void) { - i2c_wait_for_xfer(); - return (this->peek16(B100_REG_I2C_CMD_STATUS) & I2C_ST_RXACK) == 0; - } - - void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes) - { - poke16(B100_REG_I2C_DATA, (addr << 1) | 0); //addr and read bit (0) - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START | (bytes.size() == 0 ? I2C_CMD_STOP : 0)); - - //wait for previous transfer to complete - if(!wait_chk_ack()) { - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_STOP); - return; - } - - for(size_t i = 0; i < bytes.size(); i++) { - poke16(B100_REG_I2C_DATA, bytes[i]); - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_WR | ((i == (bytes.size() - 1)) ? I2C_CMD_STOP : 0)); - if(!wait_chk_ack()) { - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_STOP); - return; - } - } - } - - byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes) - { - byte_vector_t bytes; - if(num_bytes == 0) return bytes; - - while (peek16(B100_REG_I2C_CMD_STATUS) & I2C_ST_BUSY); - - poke16(B100_REG_I2C_DATA, (addr << 1) | 1); //addr and read bit (1) - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START); - //wait for previous transfer to complete - if(!wait_chk_ack()) { - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_STOP); - } - - for(; num_bytes > 0; num_bytes--) { - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_RD | ((num_bytes == 1) ? (I2C_CMD_STOP | I2C_CMD_NACK) : 0)); - i2c_wait_for_xfer(); - boost::uint8_t readback = peek16(B100_REG_I2C_DATA) & 0xFF; - bytes.push_back(readback); - } - return bytes; - } - - i2c_iface &get_fx2_i2c_iface(void){ - return _fx2_i2c_iface; - } - - /******************************************************************* - * SPI interface - * Eventually this will be replaced with a control-channel system - * to let the firmware do the actual write/readback cycles. - * This keeps the bandwidth on the control channel down. - ******************************************************************/ - - void spi_wait(void) { - while(peek32(B100_REG_SPI_CTRL) & SPI_CTRL_GO_BSY); - } - - boost::uint32_t transact_spi(int which_slave, - const spi_config_t &config, - boost::uint32_t bits, - size_t num_bits, - bool readback) - { - UHD_ASSERT_THROW((num_bits <= 32) && !(num_bits % 8)); - - int edge_flags = ((config.miso_edge==spi_config_t::EDGE_FALL) ? SPI_CTRL_RXNEG : 0) | - ((config.mosi_edge==spi_config_t::EDGE_FALL) ? 0 : SPI_CTRL_TXNEG) - ; - - boost::uint16_t ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & num_bits) | edge_flags; - - spi_wait(); - poke16(B100_REG_SPI_DIV, 0x0001); // = fpga_clk / 4 - poke32(B100_REG_SPI_SS, which_slave & 0xFFFF); - poke32(B100_REG_SPI_TXRX0, bits); - poke16(B100_REG_SPI_CTRL, ctrl); - - poke16(B100_REG_SPI_CTRL, ctrl | SPI_CTRL_GO_BSY); - if(readback) { - spi_wait(); - return peek32(B100_REG_SPI_TXRX0); - } - else { - return 0; - } - } - - void reset_gpif(boost::uint16_t ep) { - _fx2_ctrl->usrp_control_write(VRQ_RESET_GPIF, ep, ep, 0, 0); - } - - void enable_gpif(bool en) { - _fx2_ctrl->usrp_control_write(VRQ_ENABLE_GPIF, en ? 1 : 0, 0, 0, 0); - } - - void clear_fpga_fifo(void) { - _fx2_ctrl->usrp_control_write(VRQ_CLEAR_FPGA_FIFO, 0, 0, 0, 0); - } - - void write_uart(boost::uint8_t, const std::string &) { - throw uhd::not_implemented_error("Unhandled command write_uart()"); - } - - std::string read_uart(boost::uint8_t) { - throw uhd::not_implemented_error("Unhandled command read_uart()"); - } - -private: - b100_i2c_fx2_iface _fx2_i2c_iface; - uhd::usrp::fx2_ctrl::sptr _fx2_ctrl; - b100_ctrl::sptr _fpga_ctrl; - boost::mutex _ctrl_mutex; -}; - -/*********************************************************************** - * Public Make Function - **********************************************************************/ -b100_iface::sptr b100_iface::make(uhd::usrp::fx2_ctrl::sptr fx2_ctrl, - b100_ctrl::sptr fpga_ctrl) -{ - return b100_iface::sptr(new b100_iface_impl(fx2_ctrl, fpga_ctrl)); -} diff --git a/host/lib/usrp/b100/b100_iface.hpp b/host/lib/usrp/b100/b100_iface.hpp deleted file mode 100644 index a98db98dc..000000000 --- a/host/lib/usrp/b100/b100_iface.hpp +++ /dev/null @@ -1,78 +0,0 @@ -// -// 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_B100_IFACE_HPP -#define INCLUDED_B100_IFACE_HPP - -#include <uhd/usrp/mboard_iface.hpp> -#include <uhd/usrp/mboard_eeprom.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/utility.hpp> -#include <uhd/transport/usb_zero_copy.hpp> -#include "../fx2/fx2_ctrl.hpp" -#include "b100_ctrl.hpp" - -/*! - * The usrp1 interface class: - * Provides a set of functions to implementation layer. - * Including spi, peek, poke, control... - */ -class b100_iface : boost::noncopyable, public uhd::usrp::mboard_iface{ -public: - typedef boost::shared_ptr<b100_iface> sptr; - - /*! - * Make a new b100 interface with the control transport. - * \param fx2_ctrl the usrp control object - * \param fpga_ctrl the FPGA interface control object - * \return a new usrp1 interface object - */ - static sptr make(uhd::usrp::fx2_ctrl::sptr fx2_ctrl, - b100_ctrl::sptr fpga_ctrl = b100_ctrl::sptr() - ); - - //! TODO implement this for multiple hardwares revs in the future - std::string get_cname(void){ - return "USRP-B100"; - } - - /*! - * Reset the GPIF interface on the FX2 - * \param which endpoint to reset - * \return - */ - virtual void reset_gpif(boost::uint16_t ep) = 0; - - /*! - * Clear the GPIF FIFOs on the FPGA - * \return - */ - virtual void clear_fpga_fifo(void) = 0; - - /*! - * Enable/disable the GPIF interfaces on the FX2 - * \return - */ - virtual void enable_gpif(bool en) = 0; - - //! Get access to the FX2 I2C interface - virtual uhd::i2c_iface &get_fx2_i2c_iface(void) = 0; - - uhd::usrp::mboard_eeprom_t mb_eeprom; -}; - -#endif /* INCLUDED_USRP1_IFACE_HPP */ diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp index d8c5e72ce..b58e70694 100644 --- a/host/lib/usrp/b100/b100_impl.cpp +++ b/host/lib/usrp/b100/b100_impl.cpp @@ -18,11 +18,10 @@ #include "b100_impl.hpp" #include "b100_ctrl.hpp" #include "fpga_regs_standard.h" -#include "usrp_spi_defs.h" +#include "usrp_i2c_addr.h" +#include "usrp_commands.h" #include <uhd/transport/usb_control.hpp> #include "ctrl_packet.hpp" -#include <uhd/usrp/device_props.hpp> -#include <uhd/usrp/mboard_props.hpp> #include <uhd/utils/msg.hpp> #include <uhd/exception.hpp> #include <uhd/utils/static.hpp> @@ -100,11 +99,11 @@ static device_addrs_t b100_find(const device_addr_t &hint) new_addr["serial"] = handle->get_serial(); //Attempt to read the name from the EEPROM and perform filtering. - //This operation can throw due to compatibility mismatch. try{ usb_control::sptr control = usb_control::make(handle); - b100_iface::sptr iface = b100_iface::make(fx2_ctrl::make(control)); - new_addr["name"] = iface->mb_eeprom["name"]; + fx2_ctrl::sptr fx2_ctrl = fx2_ctrl::make(control); + const mboard_eeprom_t mb_eeprom = mboard_eeprom_t(*fx2_ctrl, mboard_eeprom_t::MAP_B000); + new_addr["name"] = mb_eeprom["name"]; } catch(const uhd::exception &){ //set these values as empty string so the device may still be found @@ -128,6 +127,17 @@ static device_addrs_t b100_find(const device_addr_t &hint) * Make **********************************************************************/ static device::sptr b100_make(const device_addr_t &device_addr){ + return device::sptr(new b100_impl(device_addr)); +} + +UHD_STATIC_BLOCK(register_b100_device){ + device::register_device(&b100_find, &b100_make); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +b100_impl::b100_impl(const device_addr_t &device_addr){ //extract the FPGA path for the B100 std::string b100_fpga_image = find_image_path( @@ -150,8 +160,11 @@ static device::sptr b100_make(const device_addr_t &device_addr){ //create control objects and a data transport usb_control::sptr fx2_transport = usb_control::make(handle); - fx2_ctrl::sptr fx2_ctrl = fx2_ctrl::make(fx2_transport); - fx2_ctrl->usrp_load_fpga(b100_fpga_image); + _fx2_ctrl = fx2_ctrl::make(fx2_transport); + this->check_fw_compat(); //check after making fx2 + //-- setup clock after making fx2 and before loading fpga --// + _clock_ctrl = b100_clock_ctrl::make(_fx2_ctrl, device_addr.cast<double>("master_clock_rate", B100_DEFAULT_TICK_RATE)); + _fx2_ctrl->usrp_load_fpga(b100_fpga_image); device_addr_t data_xport_args; data_xport_args["recv_frame_size"] = device_addr.get("recv_frame_size", "16384"); @@ -159,7 +172,7 @@ static device::sptr b100_make(const device_addr_t &device_addr){ data_xport_args["send_frame_size"] = device_addr.get("send_frame_size", "16384"); data_xport_args["num_send_frames"] = device_addr.get("num_send_frames", "16"); - usb_zero_copy::sptr data_transport = usb_zero_copy::make_wrapper( + _data_transport = usb_zero_copy::make_wrapper( usb_zero_copy::make( handle, // identifier 6, // IN endpoint @@ -175,110 +188,280 @@ static device::sptr b100_make(const device_addr_t &device_addr){ ctrl_xport_args["send_frame_size"] = boost::lexical_cast<std::string>(CTRL_PACKET_LENGTH); ctrl_xport_args["num_send_frames"] = "4"; - usb_zero_copy::sptr ctrl_transport = usb_zero_copy::make( + _ctrl_transport = usb_zero_copy::make( handle, 8, 4, ctrl_xport_args ); - const double master_clock_rate = device_addr.cast<double>("master_clock_rate", 64e6); - - - //create the b100 implementation guts - return device::sptr(new b100_impl(data_transport, ctrl_transport, fx2_ctrl, master_clock_rate)); -} - -UHD_STATIC_BLOCK(register_b100_device){ - device::register_device(&b100_find, &b100_make); -} - -/*********************************************************************** - * Structors - **********************************************************************/ -b100_impl::b100_impl(uhd::transport::usb_zero_copy::sptr data_transport, - uhd::transport::usb_zero_copy::sptr ctrl_transport, - uhd::usrp::fx2_ctrl::sptr fx2_ctrl, - const double master_clock_rate) - : _data_transport(data_transport), _fx2_ctrl(fx2_ctrl) -{ - _recv_otw_type.width = 16; - _recv_otw_type.shift = 0; - _recv_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - - _send_otw_type.width = 16; - _send_otw_type.shift = 0; - _send_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - - //this is the handler object for FPGA control packets - _fpga_ctrl = b100_ctrl::make(ctrl_transport); - - _iface = b100_iface::make(_fx2_ctrl, _fpga_ctrl); - - //create clock interface - _clock_ctrl = b100_clock_ctrl::make(_iface, master_clock_rate); + //////////////////////////////////////////////////////////////////// + // Create controller objects + //////////////////////////////////////////////////////////////////// + _fpga_ctrl = b100_ctrl::make(_ctrl_transport); + this->enable_gpif(true); //TODO best place to put this? + this->check_fpga_compat(); //check after making control + _fpga_i2c_ctrl = i2c_core_100::make(_fpga_ctrl, B100_REG_SLAVE(3)); + _fpga_spi_ctrl = spi_core_100::make(_fpga_ctrl, B100_REG_SLAVE(2)); + + //////////////////////////////////////////////////////////////////// + // Initialize the properties tree + //////////////////////////////////////////////////////////////////// + _tree = property_tree::make(); + _tree->create<std::string>("/name").set("B-Series Device"); + const property_tree::path_type mb_path = "/mboards/0"; + _tree->create<std::string>(mb_path / "name").set("B100 (B-Hundo)"); + _tree->create<std::string>(mb_path / "load_eeprom") + .subscribe(boost::bind(&fx2_ctrl::usrp_load_eeprom, _fx2_ctrl, _1)); + + //////////////////////////////////////////////////////////////////// + // setup the mboard eeprom + //////////////////////////////////////////////////////////////////// + const mboard_eeprom_t mb_eeprom(*_fx2_ctrl, mboard_eeprom_t::MAP_B000); + _tree->create<mboard_eeprom_t>(mb_path / "eeprom") + .set(mb_eeprom) + .subscribe(boost::bind(&b100_impl::set_mb_eeprom, this, _1)); + + //////////////////////////////////////////////////////////////////// + // create clock control objects + //////////////////////////////////////////////////////////////////// + //^^^ clock created up top, just reg props here... ^^^ + _tree->create<double>(mb_path / "tick_rate") + .publish(boost::bind(&b100_clock_ctrl::get_fpga_clock_rate, _clock_ctrl)) + .subscribe(boost::bind(&b100_impl::update_tick_rate, this, _1)); + + //////////////////////////////////////////////////////////////////// + // create codec control objects + //////////////////////////////////////////////////////////////////// + _codec_ctrl = b100_codec_ctrl::make(_fpga_spi_ctrl); + const property_tree::path_type rx_codec_path = mb_path / "rx_codecs/A"; + const property_tree::path_type tx_codec_path = mb_path / "tx_codecs/A"; + _tree->create<std::string>(rx_codec_path / "name").set("ad9522"); + _tree->create<meta_range_t>(rx_codec_path / "gains/pga/range").set(b100_codec_ctrl::rx_pga_gain_range); + _tree->create<double>(rx_codec_path / "gains/pga/value") + .coerce(boost::bind(&b100_impl::update_rx_codec_gain, this, _1)); + _tree->create<std::string>(tx_codec_path / "name").set("ad9522"); + _tree->create<meta_range_t>(tx_codec_path / "gains/pga/range").set(b100_codec_ctrl::tx_pga_gain_range); + _tree->create<double>(tx_codec_path / "gains/pga/value") + .subscribe(boost::bind(&b100_codec_ctrl::set_tx_pga_gain, _codec_ctrl, _1)) + .publish(boost::bind(&b100_codec_ctrl::get_tx_pga_gain, _codec_ctrl)); + + //////////////////////////////////////////////////////////////////// + // and do the misc mboard sensors + //////////////////////////////////////////////////////////////////// + //none for now... + _tree->create<int>(mb_path / "sensors"); //phony property so this dir exists + + //////////////////////////////////////////////////////////////////// + // create frontend control objects + //////////////////////////////////////////////////////////////////// + _rx_fe = rx_frontend_core_200::make(_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_RX_FRONT)); + _tx_fe = tx_frontend_core_200::make(_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TX_FRONT)); + //TODO lots of properties to expose here for frontends + _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec") + .subscribe(boost::bind(&b100_impl::update_rx_subdev_spec, this, _1)); + _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec") + .subscribe(boost::bind(&b100_impl::update_tx_subdev_spec, this, _1)); + + //////////////////////////////////////////////////////////////////// + // create rx dsp control objects + //////////////////////////////////////////////////////////////////// + _rx_dsps.push_back(rx_dsp_core_200::make( + _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_RX_DSP0), B100_REG_SR_ADDR(B100_SR_RX_CTRL0), B100_RX_SID_BASE + 0 + )); + _rx_dsps.push_back(rx_dsp_core_200::make( + _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_RX_DSP1), B100_REG_SR_ADDR(B100_SR_RX_CTRL1), B100_RX_SID_BASE + 1 + )); + for (size_t dspno = 0; dspno < _rx_dsps.size(); dspno++){ + _rx_dsps[dspno]->set_link_rate(B100_LINK_RATE_BPS); + _tree->access<double>(mb_path / "tick_rate") + .subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _rx_dsps[dspno], _1)); + property_tree::path_type rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno); + _tree->create<double>(rx_dsp_path / "rate/value") + .coerce(boost::bind(&rx_dsp_core_200::set_host_rate, _rx_dsps[dspno], _1)) + .subscribe(boost::bind(&b100_impl::update_rx_samp_rate, this, _1)); + _tree->create<double>(rx_dsp_path / "freq/value") + .coerce(boost::bind(&rx_dsp_core_200::set_freq, _rx_dsps[dspno], _1)); + _tree->create<meta_range_t>(rx_dsp_path / "freq/range") + .publish(boost::bind(&rx_dsp_core_200::get_freq_range, _rx_dsps[dspno])); + _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd") + .subscribe(boost::bind(&rx_dsp_core_200::issue_stream_command, _rx_dsps[dspno], _1)); + } - //create codec interface - _codec_ctrl = b100_codec_ctrl::make(_iface); + //////////////////////////////////////////////////////////////////// + // create tx dsp control objects + //////////////////////////////////////////////////////////////////// + _tx_dsp = tx_dsp_core_200::make( + _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TX_DSP), B100_REG_SR_ADDR(B100_SR_TX_CTRL), B100_TX_ASYNC_SID + ); + _tx_dsp->set_link_rate(B100_LINK_RATE_BPS); + _tree->access<double>(mb_path / "tick_rate") + .subscribe(boost::bind(&tx_dsp_core_200::set_tick_rate, _tx_dsp, _1)); + _tree->create<double>(mb_path / "tx_dsps/0/rate/value") + .coerce(boost::bind(&tx_dsp_core_200::set_host_rate, _tx_dsp, _1)) + .subscribe(boost::bind(&b100_impl::update_tx_samp_rate, this, _1)); + _tree->create<double>(mb_path / "tx_dsps/0/freq/value") + .coerce(boost::bind(&tx_dsp_core_200::set_freq, _tx_dsp, _1)); + _tree->create<meta_range_t>(mb_path / "tx_dsps/0/freq/range") + .publish(boost::bind(&tx_dsp_core_200::get_freq_range, _tx_dsp)); + + //////////////////////////////////////////////////////////////////// + // create time control objects + //////////////////////////////////////////////////////////////////// + time64_core_200::readback_bases_type time64_rb_bases; + time64_rb_bases.rb_secs_now = B100_REG_RB_TIME_NOW_SECS; + time64_rb_bases.rb_ticks_now = B100_REG_RB_TIME_NOW_TICKS; + time64_rb_bases.rb_secs_pps = B100_REG_RB_TIME_PPS_SECS; + time64_rb_bases.rb_ticks_pps = B100_REG_RB_TIME_PPS_TICKS; + _time64 = time64_core_200::make( + _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TIME64), time64_rb_bases + ); + _tree->access<double>(mb_path / "tick_rate") + .subscribe(boost::bind(&time64_core_200::set_tick_rate, _time64, _1)); + _tree->create<time_spec_t>(mb_path / "time/now") + .publish(boost::bind(&time64_core_200::get_time_now, _time64)) + .subscribe(boost::bind(&time64_core_200::set_time_now, _time64, _1)); + _tree->create<time_spec_t>(mb_path / "time/pps") + .publish(boost::bind(&time64_core_200::get_time_last_pps, _time64)) + .subscribe(boost::bind(&time64_core_200::set_time_next_pps, _time64, _1)); + //setup time source props + _tree->create<std::string>(mb_path / "time_source/value") + .subscribe(boost::bind(&time64_core_200::set_time_source, _time64, _1)); + _tree->create<std::vector<std::string> >(mb_path / "time_source/options") + .publish(boost::bind(&time64_core_200::get_time_sources, _time64)); + //setup reference source props + _tree->create<std::string>(mb_path / "clock_source/value") + .subscribe(boost::bind(&b100_impl::update_clock_source, this, _1)); + static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("auto"); + _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources); + + //////////////////////////////////////////////////////////////////// + // create dboard control objects + //////////////////////////////////////////////////////////////////// + + //read the dboard eeprom to extract the dboard ids + dboard_eeprom_t rx_db_eeprom, tx_db_eeprom, gdb_eeprom; + rx_db_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_RX_A); + tx_db_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_TX_A); + gdb_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_TX_A ^ 5); + + //create the properties and register subscribers + _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/rx_eeprom") + .set(rx_db_eeprom) + .subscribe(boost::bind(&b100_impl::set_db_eeprom, this, "rx", _1)); + _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/tx_eeprom") + .set(tx_db_eeprom) + .subscribe(boost::bind(&b100_impl::set_db_eeprom, this, "tx", _1)); + _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/gdb_eeprom") + .set(gdb_eeprom) + .subscribe(boost::bind(&b100_impl::set_db_eeprom, this, "gdb", _1)); + + //create a new dboard interface and manager + _dboard_iface = make_b100_dboard_iface(_fpga_ctrl, _fpga_i2c_ctrl, _fpga_spi_ctrl, _clock_ctrl, _codec_ctrl); + _tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_dboard_iface); + _dboard_manager = dboard_manager::make( + rx_db_eeprom.id, + ((gdb_eeprom.id == dboard_id_t::none())? tx_db_eeprom : gdb_eeprom).id, + _dboard_iface + ); + BOOST_FOREACH(const std::string &name, _dboard_manager->get_rx_subdev_names()){ + dboard_manager::populate_prop_tree_from_subdev( + _tree, mb_path / "dboards/A/rx_frontends" / name, + _dboard_manager->get_rx_subdev(name) + ); + } + BOOST_FOREACH(const std::string &name, _dboard_manager->get_tx_subdev_names()){ + dboard_manager::populate_prop_tree_from_subdev( + _tree, mb_path / "dboards/A/tx_frontends" / name, + _dboard_manager->get_tx_subdev(name) + ); + } - //initialize the codecs - codec_init(); + //initialize io handling + this->io_init(); - //initialize the mboard - mboard_init(); + //////////////////////////////////////////////////////////////////// + // do some post-init tasks + //////////////////////////////////////////////////////////////////// + _tree->access<double>(mb_path / "tick_rate").update() //update and then subscribe the clock callback + .subscribe(boost::bind(&b100_clock_ctrl::set_fpga_clock_rate, _clock_ctrl, _1)); - //initialize the dboards - dboard_init(); + //and now that the tick rate is set, init the host rates to something + BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "rx_dsps")){ + _tree->access<double>(mb_path / "rx_dsps" / name / "rate" / "value").set(1e6); + } + BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "tx_dsps")){ + _tree->access<double>(mb_path / "tx_dsps" / name / "rate" / "value").set(1e6); + } - //initialize the dsps - dsp_init(); + _tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(subdev_spec_t("A:"+_dboard_manager->get_rx_subdev_names()[0])); + _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(subdev_spec_t("A:"+_dboard_manager->get_tx_subdev_names()[0])); + _tree->access<std::string>(mb_path / "clock_source/value").set("internal"); + _tree->access<std::string>(mb_path / "time_source/value").set("none"); +} - //init the subdev specs - this->mboard_set(MBOARD_PROP_RX_SUBDEV_SPEC, subdev_spec_t()); - this->mboard_set(MBOARD_PROP_TX_SUBDEV_SPEC, subdev_spec_t()); +b100_impl::~b100_impl(void){ + //set an empty async callback now that we deconstruct + _fpga_ctrl->set_async_cb(b100_ctrl::async_cb_type()); +} - //initialize the send/recv buffs - io_init(); +void b100_impl::check_fw_compat(void){ + unsigned char data[4]; //useless data buffer + const boost::uint16_t fw_compat_num = _fx2_ctrl->usrp_control_read( + VRQ_FW_COMPAT, 0, 0, data, sizeof(data) + ); + if (fw_compat_num != B100_FW_COMPAT_NUM){ + throw uhd::runtime_error(str(boost::format( + "Expected firmware compatibility number 0x%x, but got 0x%x:\n" + "The firmware build is not compatible with the host code build." + ) % B100_FW_COMPAT_NUM % fw_compat_num)); + } } -b100_impl::~b100_impl(void){ - /* NOP */ +void b100_impl::check_fpga_compat(void){ + const boost::uint16_t fpga_compat_num = _fpga_ctrl->peek16(B100_REG_MISC_COMPAT); + if (fpga_compat_num != B100_FPGA_COMPAT_NUM){ + throw uhd::runtime_error(str(boost::format( + "Expected FPGA compatibility number 0x%x, but got 0x%x:\n" + "The FPGA build is not compatible with the host code build." + ) % B100_FPGA_COMPAT_NUM % fpga_compat_num)); + } } -bool b100_impl::recv_async_msg(uhd::async_metadata_t &md, double timeout){ - return _fpga_ctrl->recv_async_msg(md, timeout); +double b100_impl::update_rx_codec_gain(const double gain){ + //set gain on both I and Q, readback on one + //TODO in the future, gains should have individual control + _codec_ctrl->set_rx_pga_gain(gain, 'A'); + _codec_ctrl->set_rx_pga_gain(gain, 'B'); + return _codec_ctrl->get_rx_pga_gain('A'); } -/*********************************************************************** - * Device Get - **********************************************************************/ -void b100_impl::get(const wax::obj &key_, wax::obj &val) -{ - named_prop_t key = named_prop_t::extract(key_); +void b100_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){ + mb_eeprom.commit(*_fx2_ctrl, mboard_eeprom_t::MAP_B000); +} - //handle the get request conditioned on the key - switch(key.as<device_prop_t>()){ - case DEVICE_PROP_NAME: - val = std::string("USRP-B100 device"); - return; +void b100_impl::set_db_eeprom(const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){ + if (type == "rx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_RX_A); + if (type == "tx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_TX_A); + if (type == "gdb") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_TX_A ^ 5); +} - case DEVICE_PROP_MBOARD: - UHD_ASSERT_THROW(key.name == ""); - val = _mboard_proxy->get_link(); - return; +void b100_impl::update_clock_source(const std::string &source){ + if (source == "auto") _clock_ctrl->use_auto_ref(); + else if (source == "internal") _clock_ctrl->use_internal_ref(); + else if (source == "external") _clock_ctrl->use_external_ref(); + else throw uhd::runtime_error("unhandled clock configuration reference source: " + source); +} - case DEVICE_PROP_MBOARD_NAMES: - val = prop_names_t(1, ""); //vector of size 1 with empty string - return; +////////////////// some GPIF preparation related stuff ///////////////// +void b100_impl::reset_gpif(const boost::uint16_t ep) { + _fx2_ctrl->usrp_control_write(VRQ_RESET_GPIF, ep, ep, 0, 0); +} - default: UHD_THROW_PROP_GET_ERROR(); - } +void b100_impl::enable_gpif(const bool en) { + _fx2_ctrl->usrp_control_write(VRQ_ENABLE_GPIF, en ? 1 : 0, 0, 0, 0); } -/*********************************************************************** - * Device Set - **********************************************************************/ -void b100_impl::set(const wax::obj &, const wax::obj &) -{ - UHD_THROW_PROP_SET_ERROR(); +void b100_impl::clear_fpga_fifo(void) { + _fx2_ctrl->usrp_control_write(VRQ_CLEAR_FPGA_FIFO, 0, 0, 0, 0); } diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp index 2cea57eb5..62a22674e 100644 --- a/host/lib/usrp/b100/b100_impl.hpp +++ b/host/lib/usrp/b100/b100_impl.hpp @@ -15,83 +15,56 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include "b100_iface.hpp" +#ifndef INCLUDED_B100_IMPL_HPP +#define INCLUDED_B100_IMPL_HPP + +#include "fx2_ctrl.hpp" #include "b100_ctrl.hpp" #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" +#include "spi_core_100.hpp" +#include "i2c_core_100.hpp" +#include "rx_frontend_core_200.hpp" +#include "tx_frontend_core_200.hpp" +#include "rx_dsp_core_200.hpp" +#include "tx_dsp_core_200.hpp" +#include "time64_core_200.hpp" #include <uhd/device.hpp> +#include <uhd/property_tree.hpp> #include <uhd/utils/pimpl.hpp> #include <uhd/types/dict.hpp> #include <uhd/types/otw_type.hpp> #include <uhd/types/clock_config.hpp> #include <uhd/types/stream_cmd.hpp> -#include <uhd/usrp/dboard_id.hpp> +#include <uhd/usrp/mboard_eeprom.hpp> #include <uhd/usrp/subdev_spec.hpp> #include <uhd/usrp/dboard_eeprom.hpp> #include <uhd/usrp/dboard_manager.hpp> #include <uhd/transport/usb_zero_copy.hpp> -#ifndef INCLUDED_B100_IMPL_HPP -#define INCLUDED_B100_IMPL_HPP - -static const std::string B100_FW_FILE_NAME = "usrp_b100_fw.bin"; +static const double B100_LINK_RATE_BPS = 256e6/8; //pratical link rate (< 480 Mbps) +static const std::string B100_FW_FILE_NAME = "usrp_b100_fw.ihx"; static const std::string B100_FPGA_FILE_NAME = "usrp_b100_fpga.bin"; static const boost::uint16_t B100_FW_COMPAT_NUM = 0x02; static const boost::uint16_t B100_FPGA_COMPAT_NUM = 0x05; -static const size_t B100_NUM_RX_DSPS = 2; -static const size_t B100_NUM_TX_DSPS = 1; -static const boost::uint32_t B100_DSP_SID_BASE = 2; //leave room for other dsp (increments by 1) -static const boost::uint32_t B100_ASYNC_SID = 1; +static const boost::uint32_t B100_RX_SID_BASE = 2; +static const boost::uint32_t B100_TX_ASYNC_SID = 1; +static const double B100_DEFAULT_TICK_RATE = 64e6; -/*! - * Make a b100 dboard interface. - * \param iface the b100 interface object - * \param clock the clock control interface - * \param codec the codec control interface - * \return a sptr to a new dboard interface - */ +//! Make a b100 dboard interface uhd::usrp::dboard_iface::sptr make_b100_dboard_iface( - b100_iface::sptr iface, + wb_iface::sptr wb_iface, + uhd::i2c_iface::sptr i2c_iface, + uhd::spi_iface::sptr spi_iface, b100_clock_ctrl::sptr clock, b100_codec_ctrl::sptr codec ); -/*! - * Simple wax obj proxy class: - * Provides a wax obj interface for a set and a get function. - * This allows us to create nested properties structures - * while maintaining flattened code within the implementation. - */ -class wax_obj_proxy : public wax::obj { -public: - typedef boost::function<void(const wax::obj &, wax::obj &)> get_t; - typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t; - typedef boost::shared_ptr<wax_obj_proxy> sptr; - - static sptr make(const get_t &get, const set_t &set){ - return sptr(new wax_obj_proxy(get, set)); - } - -private: - get_t _get; set_t _set; - wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set) {}; - void get(const wax::obj &key, wax::obj &val) {return _get(key, val);} - void set(const wax::obj &key, const wax::obj &val) {return _set(key, val);} -}; - -/*! - * USRP1 implementation guts: - * The implementation details are encapsulated here. - * Handles properties on the mboard, dboard, dsps... - */ +//! Implementation guts class b100_impl : public uhd::device { public: //structors - b100_impl(uhd::transport::usb_zero_copy::sptr data_transport, - uhd::transport::usb_zero_copy::sptr ctrl_transport, - uhd::usrp::fx2_ctrl::sptr fx2_ctrl, - double master_clock_rate); - + b100_impl(const uhd::device_addr_t &); ~b100_impl(void); //the io interface @@ -100,114 +73,62 @@ public: const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t, double); - size_t recv(const recv_buffs_type &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, double); - size_t get_max_send_samps_per_packet(void) const; - size_t get_max_recv_samps_per_packet(void) const; - bool recv_async_msg(uhd::async_metadata_t &, double); private: - //clock control + uhd::property_tree::sptr _tree; + + //controllers + spi_core_100::sptr _fpga_spi_ctrl; + i2c_core_100::sptr _fpga_i2c_ctrl; + rx_frontend_core_200::sptr _rx_fe; + tx_frontend_core_200::sptr _tx_fe; + std::vector<rx_dsp_core_200::sptr> _rx_dsps; + tx_dsp_core_200::sptr _tx_dsp; + time64_core_200::sptr _time64; b100_clock_ctrl::sptr _clock_ctrl; - - //interface to ioctls and file descriptor - b100_iface::sptr _iface; - - //handle io stuff - uhd::transport::zero_copy_if::sptr _data_transport; - UHD_PIMPL_DECL(io_impl) _io_impl; - void update_xport_channel_mapping(void); - void io_init(void); - void handle_overrun(size_t); - - //otw types - uhd::otw_type_t _recv_otw_type; - uhd::otw_type_t _send_otw_type; - - //configuration shadows - uhd::clock_config_t _clock_config; - uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec; - - //ad9862 codec control interface b100_codec_ctrl::sptr _codec_ctrl; + b100_ctrl::sptr _fpga_ctrl; + uhd::usrp::fx2_ctrl::sptr _fx2_ctrl; - //codec properties interfaces - 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, _tx_codec_proxy; - - //device functions and settings - void get(const wax::obj &, wax::obj &); - void set(const wax::obj &, const wax::obj &); - - //mboard functions and settings - void mboard_init(void); - void mboard_get(const wax::obj &, wax::obj &); - void mboard_set(const wax::obj &, const wax::obj &); - void update_clock_config(void); - wax_obj_proxy::sptr _mboard_proxy; - - /*! - * Make a usrp1 dboard interface. - * \param iface the usrp1 interface object - * \param clock the clock control interface - * \param codec the codec control interface - * \param dboard_slot the slot identifier - * \param rx_dboard_id the db id for the rx board (used for evil dbsrx purposes) - * \return a sptr to a new dboard interface - */ - static uhd::usrp::dboard_iface::sptr make_dboard_iface( - b100_iface::sptr iface, - b100_clock_ctrl::sptr clock, - b100_codec_ctrl::sptr codec, - const uhd::usrp::dboard_id_t &rx_dboard_id - ); + //transports + uhd::transport::zero_copy_if::sptr _data_transport, _ctrl_transport; - //xx dboard functions and settings - void dboard_init(void); + //dboard stuff uhd::usrp::dboard_manager::sptr _dboard_manager; uhd::usrp::dboard_iface::sptr _dboard_iface; - //rx dboard functions and settings - uhd::usrp::dboard_eeprom_t _rx_db_eeprom; - 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; - - //tx dboard functions and settings - uhd::usrp::dboard_eeprom_t _tx_db_eeprom, _gdb_eeprom; - 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; - - //methods and shadows for the dsps - UHD_PIMPL_DECL(dsp_impl) _dsp_impl; - void dsp_init(void); - void issue_ddc_stream_cmd(const uhd::stream_cmd_t &, size_t); - - //properties interface for ddc - void ddc_get(const wax::obj &, wax::obj &, size_t); - void ddc_set(const wax::obj &, const wax::obj &, size_t); - uhd::dict<std::string, wax_obj_proxy::sptr> _rx_dsp_proxies; - - //properties interface for duc - void duc_get(const wax::obj &, wax::obj &, size_t); - void duc_set(const wax::obj &, const wax::obj &, size_t); - uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dsp_proxies; + //handle io stuff + uhd::otw_type_t _rx_otw_type, _tx_otw_type; + UHD_PIMPL_DECL(io_impl) _io_impl; + void io_init(void); - //transports - b100_ctrl::sptr _fpga_ctrl; - uhd::usrp::fx2_ctrl::sptr _fx2_ctrl; + //device properties interface + void get(const wax::obj &, wax::obj &val){ + val = _tree; //entry point into property tree + } + void check_fw_compat(void); + void check_fpga_compat(void); + double update_rx_codec_gain(const double); //sets A and B at once + void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &); + void set_db_eeprom(const std::string &, const uhd::usrp::dboard_eeprom_t &); + void update_tick_rate(const double rate); + void update_rx_samp_rate(const double rate); + void update_tx_samp_rate(const double rate); + void update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &); + void update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &); + void update_clock_source(const std::string &); + void reset_gpif(const boost::uint16_t); + void enable_gpif(const bool); + void clear_fpga_fifo(void); + void handle_async_message(uhd::transport::managed_recv_buffer::sptr); }; #endif /* INCLUDED_b100_IMPL_HPP */ diff --git a/host/lib/usrp/b100/b100_regs.hpp b/host/lib/usrp/b100/b100_regs.hpp index 06288e875..5e24f9937 100644 --- a/host/lib/usrp/b100/b100_regs.hpp +++ b/host/lib/usrp/b100/b100_regs.hpp @@ -10,8 +10,8 @@ // This means that address bit 0 is usually 0. // There are 11 bits of address for the control. -#ifndef __B100_REGS_H -#define __B100_REGS_H +#ifndef INCLUDED_B100_REGS_HPP +#define INCLUDED_B100_REGS_HPP ///////////////////////////////////////////////////// // Slave pointers @@ -50,64 +50,16 @@ //these are 32-bit registers mapped onto the 16-bit Wishbone bus. //Using peek32/poke32 should allow transparent use of these registers. #define B100_REG_SPI_BASE B100_REG_SLAVE(2) -#define B100_REG_SPI_TXRX0 B100_REG_SPI_BASE + 0 -#define B100_REG_SPI_TXRX1 B100_REG_SPI_BASE + 4 -#define B100_REG_SPI_TXRX2 B100_REG_SPI_BASE + 8 -#define B100_REG_SPI_TXRX3 B100_REG_SPI_BASE + 12 -#define B100_REG_SPI_CTRL B100_REG_SPI_BASE + 16 -#define B100_REG_SPI_DIV B100_REG_SPI_BASE + 20 -#define B100_REG_SPI_SS B100_REG_SPI_BASE + 24 //spi slave constants #define B100_SPI_SS_AD9862 (1 << 2) #define B100_SPI_SS_TX_DB (1 << 1) #define B100_SPI_SS_RX_DB (1 << 0) -//spi ctrl register bit definitions -#define SPI_CTRL_ASS (1<<13) -#define SPI_CTRL_IE (1<<12) -#define SPI_CTRL_LSB (1<<11) -#define SPI_CTRL_TXNEG (1<<10) //mosi edge, push on falling edge when 1 -#define SPI_CTRL_RXNEG (1<< 9) //miso edge, latch on falling edge when 1 -#define SPI_CTRL_GO_BSY (1<< 8) -#define SPI_CTRL_CHAR_LEN_MASK 0x7F - //////////////////////////////////////////////// // Slave 3 -- I2C Core #define B100_REG_I2C_BASE B100_REG_SLAVE(3) -#define B100_REG_I2C_PRESCALER_LO B100_REG_I2C_BASE + 0 -#define B100_REG_I2C_PRESCALER_HI B100_REG_I2C_BASE + 2 -#define B100_REG_I2C_CTRL B100_REG_I2C_BASE + 4 -#define B100_REG_I2C_DATA B100_REG_I2C_BASE + 6 -#define B100_REG_I2C_CMD_STATUS B100_REG_I2C_BASE + 8 - -//and while we're here... - -// -// STA, STO, RD, WR, and IACK bits are cleared automatically -// - -#define I2C_CTRL_EN (1 << 7) // core enable -#define I2C_CTRL_IE (1 << 6) // interrupt enable - -#define I2C_CMD_START (1 << 7) // generate (repeated) start condition -#define I2C_CMD_STOP (1 << 6) // generate stop condition -#define I2C_CMD_RD (1 << 5) // read from slave -#define I2C_CMD_WR (1 << 4) // write to slave -#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1) -#define I2C_CMD_RSVD_2 (1 << 2) // reserved -#define I2C_CMD_RSVD_1 (1 << 1) // reserved -#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt - -#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK) -#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected -#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration -#define I2C_ST_RSVD_4 (1 << 4) // reserved -#define I2C_ST_RSVD_3 (1 << 3) // reserved -#define I2C_ST_RSVD_2 (1 << 2) // reserved -#define I2C_ST_TIP (1 << 1) // Transfer-in-progress -#define I2C_ST_IP (1 << 0) // Interrupt pending //////////////////////////////////////////////// // Slave 4 -- GPIO @@ -191,94 +143,5 @@ #define B100_REG_CLEAR_TX B100_REG_SR_ADDR(B100_SR_CLEAR_RX_FIFO) #define B100_REG_GLOBAL_RESET B100_REG_SR_ADDR(B100_SR_GLOBAL_RESET) -///////////////////////////////////////////////// -// DSP RX Regs -//////////////////////////////////////////////// -#define B100_REG_DSP_RX_HELPER(which, offset) ((which == 0)? \ - (B100_REG_SR_ADDR(B100_SR_RX_DSP0 + offset)) : \ - (B100_REG_SR_ADDR(B100_SR_RX_DSP1 + offset))) - -#define B100_REG_DSP_RX_FREQ(which) B100_REG_DSP_RX_HELPER(which, 0) -#define B100_REG_DSP_RX_DECIM(which) B100_REG_DSP_RX_HELPER(which, 2) -#define B100_REG_DSP_RX_MUX(which) B100_REG_DSP_RX_HELPER(which, 3) - -#define B100_FLAG_DSP_RX_MUX_SWAP_IQ (1 << 0) -#define B100_FLAG_DSP_RX_MUX_REAL_MODE (1 << 1) - -/////////////////////////////////////////////////// -// RX CTRL regs -/////////////////////////////////////////////////// -#define B100_REG_RX_CTRL_HELPER(which, offset) ((which == 0)? \ - (B100_REG_SR_ADDR(B100_SR_RX_CTRL0 + offset)) : \ - (B100_REG_SR_ADDR(B100_SR_RX_CTRL1 + offset))) - -#define B100_REG_RX_CTRL_STREAM_CMD(which) B100_REG_RX_CTRL_HELPER(which, 0) -#define B100_REG_RX_CTRL_TIME_SECS(which) B100_REG_RX_CTRL_HELPER(which, 1) -#define B100_REG_RX_CTRL_TIME_TICKS(which) B100_REG_RX_CTRL_HELPER(which, 2) -#define B100_REG_RX_CTRL_CLEAR(which) B100_REG_RX_CTRL_HELPER(which, 3) -#define B100_REG_RX_CTRL_VRT_HDR(which) B100_REG_RX_CTRL_HELPER(which, 4) -#define B100_REG_RX_CTRL_VRT_SID(which) B100_REG_RX_CTRL_HELPER(which, 5) -#define B100_REG_RX_CTRL_VRT_TLR(which) B100_REG_RX_CTRL_HELPER(which, 6) -#define B100_REG_RX_CTRL_NSAMPS_PP(which) B100_REG_RX_CTRL_HELPER(which, 7) -#define B100_REG_RX_CTRL_NCHANNELS(which) B100_REG_RX_CTRL_HELPER(which, 8) - -///////////////////////////////////////////////// -// RX FE -//////////////////////////////////////////////// -#define B100_REG_RX_FE_SWAP_IQ B100_REG_SR_ADDR(B100_SR_RX_FRONT + 0) //lower bit -#define B100_REG_RX_FE_MAG_CORRECTION B100_REG_SR_ADDR(B100_SR_RX_FRONT + 1) //18 bits -#define B100_REG_RX_FE_PHASE_CORRECTION B100_REG_SR_ADDR(B100_SR_RX_FRONT + 2) //18 bits -#define B100_REG_RX_FE_OFFSET_I B100_REG_SR_ADDR(B100_SR_RX_FRONT + 3) //18 bits -#define B100_REG_RX_FE_OFFSET_Q B100_REG_SR_ADDR(B100_SR_RX_FRONT + 4) //18 bits - -///////////////////////////////////////////////// -// DSP TX Regs -//////////////////////////////////////////////// -#define B100_REG_DSP_TX_FREQ B100_REG_SR_ADDR(B100_SR_TX_DSP + 0) -#define B100_REG_DSP_TX_SCALE_IQ B100_REG_SR_ADDR(B100_SR_TX_DSP + 1) -#define B100_REG_DSP_TX_INTERP_RATE B100_REG_SR_ADDR(B100_SR_TX_DSP + 2) - -/////////////////////////////////////////////////// -// TX CTRL regs -/////////////////////////////////////////////////// -#define B100_REG_TX_CTRL_NUM_CHAN B100_REG_SR_ADDR(B100_SR_TX_CTRL + 0) -#define B100_REG_TX_CTRL_CLEAR_STATE B100_REG_SR_ADDR(B100_SR_TX_CTRL + 1) -#define B100_REG_TX_CTRL_REPORT_SID B100_REG_SR_ADDR(B100_SR_TX_CTRL + 2) -#define B100_REG_TX_CTRL_POLICY B100_REG_SR_ADDR(B100_SR_TX_CTRL + 3) -#define B100_REG_TX_CTRL_CYCLES_PER_UP B100_REG_SR_ADDR(B100_SR_TX_CTRL + 4) -#define B100_REG_TX_CTRL_PACKETS_PER_UP B100_REG_SR_ADDR(B100_SR_TX_CTRL + 5) - -#define B100_FLAG_TX_CTRL_POLICY_WAIT (0x1 << 0) -#define B100_FLAG_TX_CTRL_POLICY_NEXT_PACKET (0x1 << 1) -#define B100_FLAG_TX_CTRL_POLICY_NEXT_BURST (0x1 << 2) - -///////////////////////////////////////////////// -// TX FE -//////////////////////////////////////////////// -#define B100_REG_TX_FE_DC_OFFSET_I B100_REG_SR_ADDR(B100_SR_TX_FRONT + 0) //24 bits -#define B100_REG_TX_FE_DC_OFFSET_Q B100_REG_SR_ADDR(B100_SR_TX_FRONT + 1) //24 bits -#define B100_REG_TX_FE_MAC_CORRECTION B100_REG_SR_ADDR(B100_SR_TX_FRONT + 2) //18 bits -#define B100_REG_TX_FE_PHASE_CORRECTION B100_REG_SR_ADDR(B100_SR_TX_FRONT + 3) //18 bits -#define B100_REG_TX_FE_MUX B100_REG_SR_ADDR(B100_SR_TX_FRONT + 4) //8 bits (std output = 0x10, reversed = 0x01) - -///////////////////////////////////////////////// -// VITA49 64 bit time (write only) -//////////////////////////////////////////////// -#define B100_REG_TIME64_SECS B100_REG_SR_ADDR(B100_SR_TIME64 + 0) -#define B100_REG_TIME64_TICKS B100_REG_SR_ADDR(B100_SR_TIME64 + 1) -#define B100_REG_TIME64_FLAGS B100_REG_SR_ADDR(B100_SR_TIME64 + 2) -#define B100_REG_TIME64_IMM B100_REG_SR_ADDR(B100_SR_TIME64 + 3) -#define B100_REG_TIME64_TPS B100_REG_SR_ADDR(B100_SR_TIME64 + 4) -#define B100_REG_TIME64_MIMO_SYNC B100_REG_SR_ADDR(B100_SR_TIME64 + 5) - -//pps flags (see above) -#define B100_FLAG_TIME64_PPS_NEGEDGE (0 << 0) -#define B100_FLAG_TIME64_PPS_POSEDGE (1 << 0) -#define B100_FLAG_TIME64_PPS_SMA (0 << 1) -#define B100_FLAG_TIME64_PPS_MIMO (1 << 1) - -#define B100_FLAG_TIME64_LATCH_NOW 1 -#define B100_FLAG_TIME64_LATCH_NEXT_PPS 0 - #endif diff --git a/host/lib/usrp/b100/clock_ctrl.cpp b/host/lib/usrp/b100/clock_ctrl.cpp index 02091f00a..c93ff64c7 100644 --- a/host/lib/usrp/b100/clock_ctrl.cpp +++ b/host/lib/usrp/b100/clock_ctrl.cpp @@ -169,11 +169,17 @@ static clock_settings_type get_clock_settings(double rate){ **********************************************************************/ class b100_clock_ctrl_impl : public b100_clock_ctrl{ public: - b100_clock_ctrl_impl(b100_iface::sptr iface, double master_clock_rate){ + b100_clock_ctrl_impl(i2c_iface::sptr iface, double master_clock_rate){ _iface = iface; _chan_rate = 0.0; _out_rate = 0.0; + //perform soft-reset + _ad9522_regs.soft_reset = 1; + this->send_reg(0x000); + this->latch_regs(); + _ad9522_regs.soft_reset = 0; + //init the clock gen registers _ad9522_regs.sdo_active = ad9522_regs_t::SDO_ACTIVE_SDO_SDIO; _ad9522_regs.enb_stat_eeprom_at_stat_pin = 0; //use status pin @@ -294,7 +300,6 @@ public: //clock rate changed! update dboard clocks and FPGA ticks per second set_rx_dboard_clock_rate(rate); set_tx_dboard_clock_rate(rate); - _iface->poke32(B100_REG_TIME64_TPS, boost::uint32_t(get_fpga_clock_rate())); } double get_fpga_clock_rate(void){ @@ -428,7 +433,7 @@ public: } private: - b100_iface::sptr _iface; + i2c_iface::sptr _iface; ad9522_regs_t _ad9522_regs; double _out_rate; //rate at the fpga and codec double _chan_rate; //rate before final dividers @@ -447,16 +452,16 @@ private: buf.push_back(boost::uint8_t(reg >> 8)); buf.push_back(boost::uint8_t(reg & 0xff)); - _iface->get_fx2_i2c_iface().write_i2c(0x5C, buf); + _iface->write_i2c(0x5C, buf); } boost::uint8_t read_reg(boost::uint16_t addr){ byte_vector_t buf; buf.push_back(boost::uint8_t(addr >> 8)); buf.push_back(boost::uint8_t(addr & 0xff)); - _iface->get_fx2_i2c_iface().write_i2c(0x5C, buf); + _iface->write_i2c(0x5C, buf); - buf = _iface->get_fx2_i2c_iface().read_i2c(0x5C, 1); + buf = _iface->read_i2c(0x5C, 1); return boost::uint32_t(buf[0] & 0xFF); } @@ -520,6 +525,6 @@ private: /*********************************************************************** * Clock Control Make **********************************************************************/ -b100_clock_ctrl::sptr b100_clock_ctrl::make(b100_iface::sptr iface, double master_clock_rate){ +b100_clock_ctrl::sptr b100_clock_ctrl::make(i2c_iface::sptr iface, double master_clock_rate){ return sptr(new b100_clock_ctrl_impl(iface, master_clock_rate)); } diff --git a/host/lib/usrp/b100/clock_ctrl.hpp b/host/lib/usrp/b100/clock_ctrl.hpp index 3a24f2a66..5ef231281 100644 --- a/host/lib/usrp/b100/clock_ctrl.hpp +++ b/host/lib/usrp/b100/clock_ctrl.hpp @@ -18,7 +18,7 @@ #ifndef INCLUDED_B100_CLOCK_CTRL_HPP #define INCLUDED_B100_CLOCK_CTRL_HPP -#include "b100_iface.hpp" +#include <uhd/types/serial.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> #include <vector> @@ -34,11 +34,11 @@ public: /*! * Make a new clock control object. - * \param iface the b100 iface object + * \param iface the controller iface object * \param master_clock_rate the master FPGA/sample clock rate * \return the clock control object */ - static sptr make(b100_iface::sptr iface, double master_clock_rate); + static sptr make(uhd::i2c_iface::sptr iface, double master_clock_rate); /*! * Set the rate of the fpga clock line. diff --git a/host/lib/usrp/b100/codec_ctrl.cpp b/host/lib/usrp/b100/codec_ctrl.cpp index 7e9f355d4..4f9036039 100644 --- a/host/lib/usrp/b100/codec_ctrl.cpp +++ b/host/lib/usrp/b100/codec_ctrl.cpp @@ -39,7 +39,7 @@ const gain_range_t b100_codec_ctrl::rx_pga_gain_range(0, 20, 1); class b100_codec_ctrl_impl : public b100_codec_ctrl{ public: //structors - b100_codec_ctrl_impl(b100_iface::sptr iface); + b100_codec_ctrl_impl(spi_iface::sptr iface); ~b100_codec_ctrl_impl(void); //aux adc and dac control @@ -53,7 +53,7 @@ public: double get_rx_pga_gain(char); private: - b100_iface::sptr _iface; + spi_iface::sptr _iface; ad9862_regs_t _ad9862_regs; void send_reg(boost::uint8_t addr); void recv_reg(boost::uint8_t addr); @@ -62,7 +62,7 @@ private: /*********************************************************************** * Codec Control Structors **********************************************************************/ -b100_codec_ctrl_impl::b100_codec_ctrl_impl(b100_iface::sptr iface){ +b100_codec_ctrl_impl::b100_codec_ctrl_impl(spi_iface::sptr iface){ _iface = iface; //soft reset @@ -278,6 +278,6 @@ void b100_codec_ctrl_impl::recv_reg(boost::uint8_t addr){ /*********************************************************************** * Codec Control Make **********************************************************************/ -b100_codec_ctrl::sptr b100_codec_ctrl::make(b100_iface::sptr iface){ +b100_codec_ctrl::sptr b100_codec_ctrl::make(spi_iface::sptr iface){ return sptr(new b100_codec_ctrl_impl(iface)); } diff --git a/host/lib/usrp/b100/codec_ctrl.hpp b/host/lib/usrp/b100/codec_ctrl.hpp index 9ef960592..1f7bdef09 100644 --- a/host/lib/usrp/b100/codec_ctrl.hpp +++ b/host/lib/usrp/b100/codec_ctrl.hpp @@ -18,7 +18,7 @@ #ifndef INCLUDED_B100_CODEC_CTRL_HPP #define INCLUDED_B100_CODEC_CTRL_HPP -#include "b100_iface.hpp" +#include <uhd/types/serial.hpp> #include <uhd/types/ranges.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> @@ -40,7 +40,7 @@ public: * \param iface the usrp_e iface object * \return the codec control object */ - static sptr make(b100_iface::sptr iface); + static sptr make(uhd::spi_iface::sptr iface); //! aux adc identifier constants enum aux_adc_t{ diff --git a/host/lib/usrp/b100/codec_impl.cpp b/host/lib/usrp/b100/codec_impl.cpp deleted file mode 100644 index a959c9d60..000000000 --- a/host/lib/usrp/b100/codec_impl.cpp +++ /dev/null @@ -1,149 +0,0 @@ -// -// 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 "b100_impl.hpp" -#include <uhd/exception.hpp> -#include <uhd/usrp/codec_props.hpp> -#include <boost/bind.hpp> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Helper Methods - **********************************************************************/ -void b100_impl::codec_init(void){ - //make proxies - _rx_codec_proxy = wax_obj_proxy::make( - boost::bind(&b100_impl::rx_codec_get, this, _1, _2), - boost::bind(&b100_impl::rx_codec_set, this, _1, _2) - ); - _tx_codec_proxy = wax_obj_proxy::make( - boost::bind(&b100_impl::tx_codec_get, this, _1, _2), - boost::bind(&b100_impl::tx_codec_set, this, _1, _2) - ); -} - -/*********************************************************************** - * RX Codec Properties - **********************************************************************/ -static const std::string ad9862_pga_gain_name = "ad9862 pga"; - -void b100_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_NAME: - val = std::string("b100 adc - ad9522"); - return; - - case CODEC_PROP_OTHERS: - val = prop_names_t(); - return; - - case CODEC_PROP_GAIN_NAMES: - val = prop_names_t(1, ad9862_pga_gain_name); - return; - - case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = b100_codec_ctrl::rx_pga_gain_range; - return; - - case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_rx_pga_gain('A'); - return; - - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_rx_pga_gain('B'); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void b100_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the set request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'A'); - return; - - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'B'); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX Codec Properties - **********************************************************************/ -void b100_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_NAME: - val = std::string("b100 dac - ad9522"); - return; - - case CODEC_PROP_OTHERS: - val = prop_names_t(); - return; - - case CODEC_PROP_GAIN_NAMES: - val = prop_names_t(1, ad9862_pga_gain_name); - return; - - case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = b100_codec_ctrl::tx_pga_gain_range; - return; - - case CODEC_PROP_GAIN_I: //only one gain for I and Q - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_tx_pga_gain(); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void b100_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the set request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_GAIN_I: //only one gain for I and Q - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_tx_pga_gain(val.as<double>()); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/b100/dboard_iface.cpp b/host/lib/usrp/b100/dboard_iface.cpp index 003d86d48..33c4b355d 100644 --- a/host/lib/usrp/b100/dboard_iface.cpp +++ b/host/lib/usrp/b100/dboard_iface.cpp @@ -15,7 +15,8 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include "b100_iface.hpp" +#include "wb_iface.hpp" +#include <uhd/types/serial.hpp> #include "b100_regs.hpp" #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" @@ -33,11 +34,15 @@ class b100_dboard_iface : public dboard_iface{ public: b100_dboard_iface( - b100_iface::sptr iface, + wb_iface::sptr wb_iface, + i2c_iface::sptr i2c_iface, + spi_iface::sptr spi_iface, b100_clock_ctrl::sptr clock, b100_codec_ctrl::sptr codec ){ - _iface = iface; + _wb_iface = wb_iface; + _i2c_iface = i2c_iface; + _spi_iface = spi_iface; _clock = clock; _codec = codec; @@ -45,8 +50,8 @@ public: this->set_clock_rate(UNIT_RX, _clock->get_fpga_clock_rate()); this->set_clock_rate(UNIT_TX, _clock->get_fpga_clock_rate()); - _iface->poke16(B100_REG_GPIO_RX_DBG, 0); - _iface->poke16(B100_REG_GPIO_TX_DBG, 0); + _wb_iface->poke16(B100_REG_GPIO_RX_DBG, 0); + _wb_iface->poke16(B100_REG_GPIO_TX_DBG, 0); } ~b100_dboard_iface(void){ @@ -94,7 +99,9 @@ public: double get_codec_rate(unit_t); private: - b100_iface::sptr _iface; + wb_iface::sptr _wb_iface; + i2c_iface::sptr _i2c_iface; + spi_iface::sptr _spi_iface; b100_clock_ctrl::sptr _clock; b100_codec_ctrl::sptr _codec; uhd::dict<unit_t, double> _clock_rates; @@ -104,11 +111,13 @@ private: * Make Function **********************************************************************/ dboard_iface::sptr make_b100_dboard_iface( - b100_iface::sptr iface, + wb_iface::sptr wb_iface, + i2c_iface::sptr i2c_iface, + spi_iface::sptr spi_iface, b100_clock_ctrl::sptr clock, b100_codec_ctrl::sptr codec ){ - return dboard_iface::sptr(new b100_dboard_iface(iface, clock, codec)); + return dboard_iface::sptr(new b100_dboard_iface(wb_iface, i2c_iface, spi_iface, clock, codec)); } /*********************************************************************** @@ -151,29 +160,29 @@ double b100_dboard_iface::get_codec_rate(unit_t){ void b100_dboard_iface::_set_pin_ctrl(unit_t unit, boost::uint16_t value){ UHD_ASSERT_THROW(GPIO_SEL_ATR == 1); //make this assumption switch(unit){ - case UNIT_RX: _iface->poke16(B100_REG_GPIO_RX_SEL, value); return; - case UNIT_TX: _iface->poke16(B100_REG_GPIO_TX_SEL, value); return; + case UNIT_RX: _wb_iface->poke16(B100_REG_GPIO_RX_SEL, value); return; + case UNIT_TX: _wb_iface->poke16(B100_REG_GPIO_TX_SEL, value); return; } } void b100_dboard_iface::_set_gpio_ddr(unit_t unit, boost::uint16_t value){ switch(unit){ - case UNIT_RX: _iface->poke16(B100_REG_GPIO_RX_DDR, value); return; - case UNIT_TX: _iface->poke16(B100_REG_GPIO_TX_DDR, value); return; + case UNIT_RX: _wb_iface->poke16(B100_REG_GPIO_RX_DDR, value); return; + case UNIT_TX: _wb_iface->poke16(B100_REG_GPIO_TX_DDR, value); return; } } void b100_dboard_iface::_set_gpio_out(unit_t unit, boost::uint16_t value){ switch(unit){ - case UNIT_RX: _iface->poke16(B100_REG_GPIO_RX_IO, value); return; - case UNIT_TX: _iface->poke16(B100_REG_GPIO_TX_IO, value); return; + case UNIT_RX: _wb_iface->poke16(B100_REG_GPIO_RX_IO, value); return; + case UNIT_TX: _wb_iface->poke16(B100_REG_GPIO_TX_IO, value); return; } } boost::uint16_t b100_dboard_iface::read_gpio(unit_t unit){ switch(unit){ - case UNIT_RX: return _iface->peek16(B100_REG_GPIO_RX_IO); - case UNIT_TX: return _iface->peek16(B100_REG_GPIO_TX_IO); + case UNIT_RX: return _wb_iface->peek16(B100_REG_GPIO_RX_IO); + case UNIT_TX: return _wb_iface->peek16(B100_REG_GPIO_TX_IO); default: UHD_THROW_INVALID_CODE_PATH(); } } @@ -196,7 +205,7 @@ void b100_dboard_iface::_set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t (ATR_REG_FULL_DUPLEX, B100_REG_ATR_FULL_TXSIDE) ) ; - _iface->poke16(unit_to_atr_to_addr[unit][atr], value); + _wb_iface->poke16(unit_to_atr_to_addr[unit][atr], value); } void b100_dboard_iface::set_gpio_debug(unit_t unit, int which){ @@ -211,13 +220,13 @@ void b100_dboard_iface::set_gpio_debug(unit_t unit, int which){ //set the debug on and which debug selection switch(unit){ case UNIT_RX: - _iface->poke16(B100_REG_GPIO_RX_DBG, 0xffff); - _iface->poke16(B100_REG_GPIO_RX_SEL, dbg_sels); + _wb_iface->poke16(B100_REG_GPIO_RX_DBG, 0xffff); + _wb_iface->poke16(B100_REG_GPIO_RX_SEL, dbg_sels); return; case UNIT_TX: - _iface->poke16(B100_REG_GPIO_TX_DBG, 0xffff); - _iface->poke16(B100_REG_GPIO_TX_SEL, dbg_sels); + _wb_iface->poke16(B100_REG_GPIO_TX_DBG, 0xffff); + _wb_iface->poke16(B100_REG_GPIO_TX_SEL, dbg_sels); return; } } @@ -244,7 +253,7 @@ void b100_dboard_iface::write_spi( boost::uint32_t data, size_t num_bits ){ - _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, false /*no rb*/); + _spi_iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, false /*no rb*/); } boost::uint32_t b100_dboard_iface::read_write_spi( @@ -253,18 +262,18 @@ boost::uint32_t b100_dboard_iface::read_write_spi( boost::uint32_t data, size_t num_bits ){ - return _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, true /*rb*/); + return _spi_iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, true /*rb*/); } /*********************************************************************** * I2C **********************************************************************/ void b100_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ - return _iface->write_i2c(addr, bytes); + return _i2c_iface->write_i2c(addr, bytes); } byte_vector_t b100_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){ - return _iface->read_i2c(addr, num_bytes); + return _i2c_iface->read_i2c(addr, num_bytes); } /*********************************************************************** diff --git a/host/lib/usrp/b100/dboard_impl.cpp b/host/lib/usrp/b100/dboard_impl.cpp deleted file mode 100644 index ed1d4bb1d..000000000 --- a/host/lib/usrp/b100/dboard_impl.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// -// 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 "b100_impl.hpp" -#include "b100_regs.hpp" -#include <uhd/exception.hpp> -#include <uhd/usrp/dboard_props.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <uhd/usrp/misc_utils.hpp> -#include <boost/bind.hpp> -#include "usrp_i2c_addr.h" - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Dboard Initialization - **********************************************************************/ -void b100_impl::dboard_init(void){ - //read the tx and rx dboard eeproms - _rx_db_eeprom.load(*_iface, I2C_ADDR_RX_A); - _tx_db_eeprom.load(*_iface, I2C_ADDR_TX_A); - _gdb_eeprom.load(*_iface, I2C_ADDR_TX_A ^ 5); - - //create a new dboard interface and manager - _dboard_iface = make_b100_dboard_iface( - _iface, _clock_ctrl, _codec_ctrl - ); - _dboard_manager = dboard_manager::make( - _rx_db_eeprom.id, - ((_gdb_eeprom.id == dboard_id_t::none())? _tx_db_eeprom : _gdb_eeprom).id, - _dboard_iface - ); - - //setup the dboard proxies - _rx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&b100_impl::rx_dboard_get, this, _1, _2), - boost::bind(&b100_impl::rx_dboard_set, this, _1, _2) - ); - _tx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&b100_impl::tx_dboard_get, this, _1, _2), - boost::bind(&b100_impl::tx_dboard_set, this, _1, _2) - ); -} - -/*********************************************************************** - * RX Dboard Get - **********************************************************************/ -void b100_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_NAME: - val = std::string("b100 dboard (rx unit)"); - return; - - case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_rx_subdev(key.name); - return; - - case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_manager->get_rx_subdev_names(); - return; - - case DBOARD_PROP_DBOARD_EEPROM: - val = _rx_db_eeprom; - return; - - case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_iface; - return; - - case DBOARD_PROP_CODEC: - val = _rx_codec_proxy->get_link(); - return; - - case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group( - _rx_db_eeprom.id, - _dboard_manager->get_rx_subdev(key.name), - _rx_codec_proxy->get_link(), - GAIN_GROUP_POLICY_RX - ); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * RX Dboard Set - **********************************************************************/ -void b100_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_DBOARD_EEPROM: - _rx_db_eeprom = val.as<dboard_eeprom_t>(); - _rx_db_eeprom.store(*_iface, I2C_ADDR_RX_A); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX Dboard Get - **********************************************************************/ -void b100_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_NAME: - val = std::string("b100 dboard (tx unit)"); - return; - - case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_tx_subdev(key.name); - return; - - case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_manager->get_tx_subdev_names(); - return; - - case DBOARD_PROP_DBOARD_EEPROM: - val = _tx_db_eeprom; - return; - - case DBOARD_PROP_GBOARD_EEPROM: - val = _gdb_eeprom; - return; - - case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_iface; - return; - - case DBOARD_PROP_CODEC: - val = _tx_codec_proxy->get_link(); - return; - - case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group( - _tx_db_eeprom.id, - _dboard_manager->get_tx_subdev(key.name), - _tx_codec_proxy->get_link(), - GAIN_GROUP_POLICY_TX - ); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * TX Dboard Set - **********************************************************************/ -void b100_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_DBOARD_EEPROM: - _tx_db_eeprom = val.as<dboard_eeprom_t>(); - _tx_db_eeprom.store(*_iface, I2C_ADDR_TX_A); - return; - - case DBOARD_PROP_GBOARD_EEPROM: - _gdb_eeprom = val.as<dboard_eeprom_t>(); - _gdb_eeprom.store(*_iface, I2C_ADDR_TX_A ^ 5); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/b100/dsp_impl.cpp b/host/lib/usrp/b100/dsp_impl.cpp deleted file mode 100644 index e27894c1a..000000000 --- a/host/lib/usrp/b100/dsp_impl.cpp +++ /dev/null @@ -1,217 +0,0 @@ -// -// 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 "b100_impl.hpp" -#include "b100_regs.hpp" -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/dsp_props.hpp> -#include <boost/math/special_functions/round.hpp> -#include <boost/bind.hpp> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * DSP impl and methods - **********************************************************************/ -struct b100_impl::dsp_impl{ - uhd::dict<size_t, size_t> ddc_decim; - uhd::dict<size_t, double> ddc_freq; - uhd::dict<size_t, size_t> duc_interp; - uhd::dict<size_t, double> duc_freq; -}; - -/*********************************************************************** - * RX DDC Initialization - **********************************************************************/ -void b100_impl::dsp_init(void){ - //create new dsp impl - _dsp_impl = UHD_PIMPL_MAKE(dsp_impl, ()); - - //bind and initialize the rx dsps - for (size_t i = 0; i < B100_NUM_RX_DSPS; i++){ - _rx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( - boost::bind(&b100_impl::ddc_get, this, _1, _2, i), - boost::bind(&b100_impl::ddc_set, this, _1, _2, i) - ); - - //initial config and update - ddc_set(DSP_PROP_FREQ_SHIFT, double(0), i); - ddc_set(DSP_PROP_HOST_RATE, double(_clock_ctrl->get_fpga_clock_rate()/16), i); - - //setup the rx control registers - _iface->poke32(B100_REG_RX_CTRL_CLEAR(i), 1); //reset - _iface->poke32(B100_REG_RX_CTRL_NSAMPS_PP(i), this->get_max_recv_samps_per_packet()); - _iface->poke32(B100_REG_RX_CTRL_NCHANNELS(i), 1); - _iface->poke32(B100_REG_RX_CTRL_VRT_HDR(i), 0 - | (0x1 << 28) //if data with stream id - | (0x1 << 26) //has trailer - | (0x3 << 22) //integer time other - | (0x1 << 20) //fractional time sample count - ); - _iface->poke32(B100_REG_RX_CTRL_VRT_SID(i), B100_DSP_SID_BASE + i); - _iface->poke32(B100_REG_RX_CTRL_VRT_TLR(i), 0); - _iface->poke32(B100_REG_TIME64_TPS, size_t(_clock_ctrl->get_fpga_clock_rate())); - } - - //bind and initialize the tx dsps - for (size_t i = 0; i < B100_NUM_TX_DSPS; i++){ - _tx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( - boost::bind(&b100_impl::duc_get, this, _1, _2, i), - boost::bind(&b100_impl::duc_set, this, _1, _2, i) - ); - - //initial config and update - duc_set(DSP_PROP_FREQ_SHIFT, double(0), i); - duc_set(DSP_PROP_HOST_RATE, double(_clock_ctrl->get_fpga_clock_rate()/16), i); - - //init the tx control registers - _iface->poke32(B100_REG_TX_CTRL_CLEAR_STATE, 1); //reset - _iface->poke32(B100_REG_TX_CTRL_NUM_CHAN, 0); //1 channel - _iface->poke32(B100_REG_TX_CTRL_REPORT_SID, B100_ASYNC_SID); - _iface->poke32(B100_REG_TX_CTRL_POLICY, B100_FLAG_TX_CTRL_POLICY_NEXT_PACKET); - } -} - -/*********************************************************************** - * RX DDC Get - **********************************************************************/ -void b100_impl::ddc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - case DSP_PROP_NAME: - val = str(boost::format("%s ddc%d") % _iface->get_cname() % which_dsp); - return; - - case DSP_PROP_OTHERS: - val = prop_names_t(); //empty - return; - - case DSP_PROP_FREQ_SHIFT: - val = _dsp_impl->ddc_freq[which_dsp]; - return; - - case DSP_PROP_CODEC_RATE: - val = _clock_ctrl->get_fpga_clock_rate(); - return; - - case DSP_PROP_HOST_RATE: - val = _clock_ctrl->get_fpga_clock_rate()/_dsp_impl->ddc_decim[which_dsp]; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * RX DDC Set - **********************************************************************/ -void b100_impl::ddc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - - case DSP_PROP_STREAM_CMD: - issue_ddc_stream_cmd(val.as<stream_cmd_t>(), which_dsp); - return; - - case DSP_PROP_FREQ_SHIFT:{ - double new_freq = val.as<double>(); - _iface->poke32(B100_REG_DSP_RX_FREQ(which_dsp), - dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate()) - ); - _dsp_impl->ddc_freq[which_dsp] = new_freq; //shadow - } - return; - - case DSP_PROP_HOST_RATE:{ - _dsp_impl->ddc_decim[which_dsp] = boost::math::iround(_clock_ctrl->get_fpga_clock_rate()/val.as<double>()); - - //set the decimation - _iface->poke32(B100_REG_DSP_RX_DECIM(which_dsp), dsp_type1::calc_cic_filter_word(_dsp_impl->ddc_decim[which_dsp])); - } - this->update_xport_channel_mapping(); //rate changed -> update - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX DUC Get - **********************************************************************/ -void b100_impl::duc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - case DSP_PROP_NAME: - val = str(boost::format("%s duc%d") % _iface->get_cname() % which_dsp); - return; - - case DSP_PROP_OTHERS: - val = prop_names_t(); //empty - return; - - case DSP_PROP_FREQ_SHIFT: - val = _dsp_impl->duc_freq[which_dsp]; - return; - - case DSP_PROP_CODEC_RATE: - val = _clock_ctrl->get_fpga_clock_rate(); - return; - - case DSP_PROP_HOST_RATE: - val = _clock_ctrl->get_fpga_clock_rate()/_dsp_impl->duc_interp[which_dsp]; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * TX DUC Set - **********************************************************************/ -void b100_impl::duc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - - case DSP_PROP_FREQ_SHIFT:{ - double new_freq = val.as<double>(); - _iface->poke32(B100_REG_DSP_TX_FREQ, - dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate()) - ); - _dsp_impl->duc_freq[which_dsp] = new_freq; //shadow - } - return; - - case DSP_PROP_HOST_RATE:{ - _dsp_impl->duc_interp[which_dsp] = boost::math::iround(_clock_ctrl->get_fpga_clock_rate()/val.as<double>()); - - //set the interpolation - _iface->poke32(B100_REG_DSP_TX_INTERP_RATE, dsp_type1::calc_cic_filter_word(_dsp_impl->duc_interp[which_dsp])); - - //set the scaling - _iface->poke32(B100_REG_DSP_TX_SCALE_IQ, dsp_type1::calc_iq_scale_word(_dsp_impl->duc_interp[which_dsp])); - } - this->update_xport_channel_mapping(); //rate changed -> update - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/b100/io_impl.cpp b/host/lib/usrp/b100/io_impl.cpp index 5377c43d5..d4515bbb5 100644 --- a/host/lib/usrp/b100/io_impl.cpp +++ b/host/lib/usrp/b100/io_impl.cpp @@ -15,133 +15,190 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include "recv_packet_demuxer.hpp" +#include "validate_subdev_spec.hpp" #include "../../transport/super_recv_packet_handler.hpp" #include "../../transport/super_send_packet_handler.hpp" #include "usrp_commands.h" #include "b100_impl.hpp" #include "b100_regs.hpp" -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/dsp_props.hpp> #include <uhd/utils/thread_priority.hpp> #include <uhd/transport/bounded_buffer.hpp> #include <boost/bind.hpp> #include <boost/format.hpp> -#include <boost/asio.hpp> #include <boost/bind.hpp> #include <boost/thread.hpp> #include <uhd/utils/msg.hpp> #include <uhd/utils/log.hpp> -#include <iostream> using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; -namespace asio = boost::asio; /*********************************************************************** * IO Implementation Details **********************************************************************/ struct b100_impl::io_impl{ - io_impl(zero_copy_if::sptr data_transport): - data_transport(data_transport) - { - for (size_t i = 0; i < B100_NUM_RX_DSPS; i++){ - typedef bounded_buffer<managed_recv_buffer::sptr> buffs_queue_type; - _buffs_queue.push_back(new buffs_queue_type(data_transport->get_num_recv_frames())); - } - } - - ~io_impl(void){ - for (size_t i = 0; i < _buffs_queue.size(); i++){ - delete _buffs_queue[i]; - } - } + io_impl(void): + async_msg_fifo(100/*messages deep*/) + { /* NOP */ } zero_copy_if::sptr data_transport; - - std::vector<bounded_buffer<managed_recv_buffer::sptr> *> _buffs_queue; - - //gets buffer, determines if its the requested index, - //and either queues the buffer or returns the buffer - managed_recv_buffer::sptr get_recv_buff(const size_t index, const double timeout){ - while (true){ - managed_recv_buffer::sptr buff; - - //attempt to pop a buffer from the queue - if (_buffs_queue[index]->pop_with_haste(buff)) return buff; - - //otherwise, call into the transport - buff = data_transport->get_recv_buff(timeout); - if (buff.get() == NULL) return buff; //timeout - - //check the stream id to know which channel - const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>(); - const size_t rx_index = uhd::wtohx(vrt_hdr[1]) - B100_DSP_SID_BASE; - if (rx_index == index) return buff; //got expected message - - //otherwise queue and try again - if (rx_index < B100_NUM_RX_DSPS) _buffs_queue[rx_index]->push_with_pop_on_full(buff); - else UHD_MSG(error) << "Got a data packet with known SID " << uhd::wtohx(vrt_hdr[1]) << std::endl; - } - } - + bounded_buffer<async_metadata_t> async_msg_fifo; + recv_packet_demuxer::sptr demuxer; sph::recv_packet_handler recv_handler; sph::send_packet_handler send_handler; - bool continuous_streaming; }; /*********************************************************************** * Initialize internals within this file **********************************************************************/ void b100_impl::io_init(void){ - _iface->reset_gpif(6); - _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport)); + //setup rx otw type + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = uhd::otw_type_t::BO_LITTLE_ENDIAN; + + //setup tx otw type + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = uhd::otw_type_t::BO_LITTLE_ENDIAN; + + //TODO best place to put this? + this->reset_gpif(6); //set the expected packet size in USB frames - _iface->poke32(B100_REG_MISC_RX_LEN, 4); + _fpga_ctrl->poke32(B100_REG_MISC_RX_LEN, 4); + + //create new io impl + _io_impl = UHD_PIMPL_MAKE(io_impl, ()); + _io_impl->demuxer = recv_packet_demuxer::make(_data_transport, _rx_dsps.size(), B100_RX_SID_BASE); + + //now its safe to register the async callback + _fpga_ctrl->set_async_cb(boost::bind(&b100_impl::handle_async_message, this, _1)); - update_xport_channel_mapping(); + //init some handler stuff + _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_le); + _io_impl->recv_handler.set_converter(_rx_otw_type); + _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_le); + _io_impl->send_handler.set_converter(_tx_otw_type); + _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet()); } -void b100_impl::update_xport_channel_mapping(void){ - if (_io_impl.get() == NULL) return; //not inited yet +void b100_impl::handle_async_message(managed_recv_buffer::sptr rbuf){ + vrt::if_packet_info_t if_packet_info; + if_packet_info.num_packet_words32 = rbuf->size()/sizeof(boost::uint32_t); + const boost::uint32_t *vrt_hdr = rbuf->cast<const boost::uint32_t *>(); + try{ + vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info); + } + catch(const std::exception &e){ + UHD_MSG(error) << "Error (handle_async_message): " << e.what() << std::endl; + } + + if (if_packet_info.sid == B100_TX_ASYNC_SID 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 = 0; + 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), _clock_ctrl->get_fpga_clock_rate() + ); + metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info)); + _io_impl->async_msg_fifo.push_with_pop_on_full(metadata); + if (metadata.event_code & + ( async_metadata_t::EVENT_CODE_UNDERFLOW + | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) + ) UHD_MSG(fastpath) << "U"; + else if (metadata.event_code & + ( async_metadata_t::EVENT_CODE_SEQ_ERROR + | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) + ) UHD_MSG(fastpath) << "S"; + } + else UHD_MSG(error) << "Unknown async packet" << std::endl; +} - //set all of the relevant properties on the handler +void b100_impl::update_tick_rate(const double rate){ boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); - _io_impl->recv_handler.resize(_rx_subdev_spec.size()); - _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_le); - _io_impl->recv_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate()); - //FIXME assumes homogeneous rates across all dsp - _io_impl->recv_handler.set_samp_rate(_rx_dsp_proxies[_rx_dsp_proxies.keys().at(0)]->get_link()[DSP_PROP_HOST_RATE].as<double>()); - for (size_t chan = 0; chan < _io_impl->recv_handler.size(); chan++){ - _io_impl->recv_handler.set_xport_chan_get_buff(chan, boost::bind( - &b100_impl::io_impl::get_recv_buff, _io_impl.get(), chan, _1 - )); - _io_impl->recv_handler.set_overflow_handler(chan, boost::bind( - &b100_impl::handle_overrun, this, chan + _io_impl->recv_handler.set_tick_rate(rate); + boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); + _io_impl->send_handler.set_tick_rate(rate); +} + +void b100_impl::update_rx_samp_rate(const double rate){ + boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); + _io_impl->recv_handler.set_samp_rate(rate); +} + +void b100_impl::update_tx_samp_rate(const double rate){ + boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); + _io_impl->send_handler.set_samp_rate(rate); +} + +void b100_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){ + boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); + property_tree::path_type root = "/mboards/0/dboards"; + + //sanity checking + validate_subdev_spec(_tree, spec, "rx"); + + //setup mux for this spec + bool fe_swapped = false; + for (size_t i = 0; i < spec.size(); i++){ + const std::string conn = _tree->access<std::string>(root / spec[i].db_name / "rx_frontends" / spec[i].sd_name / "connection").get(); + if (i == 0 and (conn == "QI" or conn == "Q")) fe_swapped = true; + _rx_dsps[i]->set_mux(conn, fe_swapped); + } + _rx_fe->set_mux(fe_swapped); + + //resize for the new occupancy + _io_impl->recv_handler.resize(spec.size()); + + //bind new callbacks for the handler + for (size_t i = 0; i < _io_impl->recv_handler.size(); i++){ + _rx_dsps[i]->set_nsamps_per_packet(get_max_recv_samps_per_packet()); //seems to be a good place to set this + _io_impl->recv_handler.set_xport_chan_get_buff(i, boost::bind( + &recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, i, _1 )); + _io_impl->recv_handler.set_overflow_handler(i, boost::bind(&rx_dsp_core_200::handle_overflow, _rx_dsps[i])); } - _io_impl->recv_handler.set_converter(_recv_otw_type); +} - //set all of the relevant properties on the handler +void b100_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){ boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); - _io_impl->send_handler.resize(_tx_subdev_spec.size()); - _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_le); - _io_impl->send_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate()); - //FIXME assumes homogeneous rates across all dsp - _io_impl->send_handler.set_samp_rate(_tx_dsp_proxies[_tx_dsp_proxies.keys().at(0)]->get_link()[DSP_PROP_HOST_RATE].as<double>()); - for (size_t chan = 0; chan < _io_impl->send_handler.size(); chan++){ - _io_impl->send_handler.set_xport_chan_get_buff(chan, boost::bind( - &uhd::transport::zero_copy_if::get_send_buff, _io_impl->data_transport, _1 + property_tree::path_type root = "/mboards/0/dboards"; + + //sanity checking + validate_subdev_spec(_tree, spec, "tx"); + + //set the mux for this spec + const std::string conn = _tree->access<std::string>(root / spec[0].db_name / "tx_frontends" / spec[0].sd_name / "connection").get(); + _tx_fe->set_mux(conn); + + //resize for the new occupancy + _io_impl->send_handler.resize(spec.size()); + + //bind new callbacks for the handler + for (size_t i = 0; i < _io_impl->send_handler.size(); i++){ + _io_impl->send_handler.set_xport_chan_get_buff(i, boost::bind( + &zero_copy_if::get_send_buff, _data_transport, _1 )); } - _io_impl->send_handler.set_converter(_send_otw_type); - _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet()); } /*********************************************************************** - * Data send + helper functions + * Async Data + **********************************************************************/ +bool b100_impl::recv_async_msg( + async_metadata_t &async_metadata, double timeout +){ + boost::this_thread::disable_interruption di; //disable because the wait can throw + return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout); +} + +/*********************************************************************** + * Send Data **********************************************************************/ size_t b100_impl::get_max_send_samps_per_packet(void) const { static const size_t hdr_size = 0 @@ -149,7 +206,7 @@ size_t b100_impl::get_max_send_samps_per_packet(void) const { - sizeof(vrt::if_packet_info_t().cid) //no class id ever used ; static const size_t bpp = 2048 - hdr_size; - return bpp / _send_otw_type.get_sample_size(); + return bpp / _tx_otw_type.get_sample_size(); } size_t b100_impl::send( @@ -165,9 +222,8 @@ size_t b100_impl::send( } /*********************************************************************** - * Data recv + helper functions + * Receive Data **********************************************************************/ - size_t b100_impl::get_max_recv_samps_per_packet(void) const { static const size_t hdr_size = 0 + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) @@ -175,7 +231,7 @@ size_t b100_impl::get_max_recv_samps_per_packet(void) const { - sizeof(vrt::if_packet_info_t().cid) //no class id ever used ; size_t bpp = 2048 - hdr_size; //limited by FPGA pkt buffer size - return bpp/_recv_otw_type.get_sample_size(); + return bpp/_rx_otw_type.get_sample_size(); } size_t b100_impl::recv( @@ -189,23 +245,3 @@ size_t b100_impl::recv( recv_mode, timeout ); } - -void b100_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd, size_t index) -{ - _io_impl->continuous_streaming = (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - _iface->poke32(B100_REG_RX_CTRL_STREAM_CMD(index), dsp_type1::calc_stream_cmd_word(stream_cmd)); - _iface->poke32(B100_REG_RX_CTRL_TIME_SECS(index), boost::uint32_t(stream_cmd.time_spec.get_full_secs())); - _iface->poke32(B100_REG_RX_CTRL_TIME_TICKS(index), stream_cmd.time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate())); - - if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS) { - while(_io_impl->data_transport->get_recv_buff().get() != NULL){ - /* NOP */ - } - } -} - -void b100_impl::handle_overrun(size_t index){ - if (_io_impl->continuous_streaming){ - this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS, index); - } -} diff --git a/host/lib/usrp/b100/mboard_impl.cpp b/host/lib/usrp/b100/mboard_impl.cpp deleted file mode 100644 index 4f7dc8fce..000000000 --- a/host/lib/usrp/b100/mboard_impl.cpp +++ /dev/null @@ -1,282 +0,0 @@ -// -// 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 "b100_impl.hpp" -#include "usrp_commands.h" -#include "fpga_regs_standard.h" -#include "fpga_regs_common.h" -#include "b100_regs.hpp" -#include "usrp_i2c_addr.h" -#include <uhd/usrp/misc_utils.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <uhd/usrp/dboard_props.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <uhd/utils/msg.hpp> -#include <uhd/exception.hpp> -#include <uhd/utils/images.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/foreach.hpp> -#include <boost/bind.hpp> -#include <boost/thread/thread.hpp> -#include <uhd/usrp/dsp_utils.hpp> - -using namespace uhd; -using namespace uhd::usrp; - -static const bool b100_mboard_verbose = true; - -/*********************************************************************** - * Mboard Initialization - **********************************************************************/ -void b100_impl::mboard_init(void) -{ - _mboard_proxy = wax_obj_proxy::make( - boost::bind(&b100_impl::mboard_get, this, _1, _2), - boost::bind(&b100_impl::mboard_set, this, _1, _2)); - - //set the ticks per seconds into the vita time control - _iface->poke32(B100_REG_TIME64_TPS, - boost::uint32_t(_clock_ctrl->get_fpga_clock_rate()) - ); - - //init the clock config - _clock_config = clock_config_t::internal(); - update_clock_config(); -} - -void b100_impl::update_clock_config(void){ - boost::uint32_t pps_flags = 0; - - //translate pps polarity enums - switch(_clock_config.pps_polarity){ - case clock_config_t::PPS_POS: pps_flags |= B100_FLAG_TIME64_PPS_POSEDGE; break; - case clock_config_t::PPS_NEG: pps_flags |= B100_FLAG_TIME64_PPS_NEGEDGE; break; - default: throw uhd::runtime_error("unhandled clock configuration pps polarity"); - } - - //set the pps flags - _iface->poke32(B100_REG_TIME64_FLAGS, pps_flags); - - //clock source ref 10mhz - switch(_clock_config.ref_source){ - case clock_config_t::REF_AUTO: _clock_ctrl->use_auto_ref(); break; - case clock_config_t::REF_INT: _clock_ctrl->use_internal_ref(); break; - case clock_config_t::REF_SMA: _clock_ctrl->use_auto_ref(); break; - default: throw uhd::runtime_error("unhandled clock configuration ref source"); - } -} - -/*********************************************************************** - * Mboard Get - **********************************************************************/ -void b100_impl::mboard_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - static const std::string dboard_name = "A"; - - //handle the get request conditioned on the key - switch(key.as<mboard_prop_t>()){ - case MBOARD_PROP_NAME: - val = std::string(_iface->get_cname() + " mboard"); - return; - - case MBOARD_PROP_OTHERS: - val = prop_names_t(); - return; - - case MBOARD_PROP_RX_DBOARD: - UHD_ASSERT_THROW(key.name == dboard_name); - val = _rx_dboard_proxy->get_link(); - return; - - case MBOARD_PROP_RX_DBOARD_NAMES: - val = prop_names_t(1, dboard_name); - return; - - case MBOARD_PROP_TX_DBOARD: - UHD_ASSERT_THROW(key.name == dboard_name); - val = _tx_dboard_proxy->get_link(); - return; - - case MBOARD_PROP_TX_DBOARD_NAMES: - val = prop_names_t(1, dboard_name); - return; - - case MBOARD_PROP_RX_DSP: - val = _rx_dsp_proxies[key.name]->get_link(); - return; - - case MBOARD_PROP_RX_DSP_NAMES: - val = _rx_dsp_proxies.keys(); - return; - - case MBOARD_PROP_TX_DSP: - val = _tx_dsp_proxies[key.name]->get_link(); - return; - - case MBOARD_PROP_TX_DSP_NAMES: - val = _tx_dsp_proxies.keys(); - return; - - case MBOARD_PROP_CLOCK_CONFIG: - val = _clock_config; - return; - - case MBOARD_PROP_RX_SUBDEV_SPEC: - val = _rx_subdev_spec; - return; - - case MBOARD_PROP_TX_SUBDEV_SPEC: - val = _tx_subdev_spec; - return; - - case MBOARD_PROP_EEPROM_MAP: - val = _iface->mb_eeprom; - return; - - case MBOARD_PROP_TIME_NOW:while(true){ - uint32_t secs = _iface->peek32(B100_REG_RB_TIME_NOW_SECS); - uint32_t ticks = _iface->peek32(B100_REG_RB_TIME_NOW_TICKS); - if (secs != _iface->peek32(B100_REG_RB_TIME_NOW_SECS)) continue; - val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate()); - return; - } - - case MBOARD_PROP_TIME_PPS: while(true){ - uint32_t secs = _iface->peek32(B100_REG_RB_TIME_PPS_SECS); - uint32_t ticks = _iface->peek32(B100_REG_RB_TIME_PPS_TICKS); - if (secs != _iface->peek32(B100_REG_RB_TIME_PPS_SECS)) continue; - val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate()); - return; - } - - case MBOARD_PROP_CLOCK_RATE: - val = _clock_ctrl->get_fpga_clock_rate(); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * Mboard Set - **********************************************************************/ -void b100_impl::mboard_set(const wax::obj &key, const wax::obj &val) -{ - if(key.type() == typeid(std::string)) { - if(key.as<std::string>() == "load_eeprom") { - std::string b100_eeprom_image = val.as<std::string>(); - UHD_MSG(status) << "B100 EEPROM image: " << b100_eeprom_image << std::endl; - _fx2_ctrl->usrp_load_eeprom(val.as<std::string>()); - } - return; - } - - //handle the get request conditioned on the key - switch(key.as<mboard_prop_t>()){ - case MBOARD_PROP_TIME_NOW: - case MBOARD_PROP_TIME_PPS:{ - time_spec_t time_spec = val.as<time_spec_t>(); - _iface->poke32(B100_REG_TIME64_TICKS, time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate())); - boost::uint32_t imm_flags = (key.as<mboard_prop_t>() == MBOARD_PROP_TIME_NOW)? 1 : 0; - _iface->poke32(B100_REG_TIME64_IMM, imm_flags); - _iface->poke32(B100_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs())); - } - return; - - case MBOARD_PROP_RX_SUBDEV_SPEC:{ - _rx_subdev_spec = val.as<subdev_spec_t>(); - verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link()); - //sanity check - UHD_ASSERT_THROW(_rx_subdev_spec.size() <= B100_NUM_RX_DSPS); - - //determine frontend swap IQ from the first channel - bool fe_swap_iq = false; - switch(_dboard_manager->get_rx_subdev(_rx_subdev_spec.at(0).sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){ - case SUBDEV_CONN_COMPLEX_QI: - case SUBDEV_CONN_REAL_Q: - fe_swap_iq = true; - break; - default: fe_swap_iq = false; - } - _iface->poke32(B100_REG_RX_FE_SWAP_IQ, fe_swap_iq? 1 : 0); - - //set the dsp mux for each channel - for (size_t i = 0; i < _rx_subdev_spec.size(); i++){ - bool iq_swap = false, real_mode = false; - switch(_dboard_manager->get_rx_subdev(_rx_subdev_spec.at(i).sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){ - case SUBDEV_CONN_COMPLEX_IQ: - iq_swap = fe_swap_iq; - real_mode = false; - break; - case SUBDEV_CONN_COMPLEX_QI: - iq_swap = not fe_swap_iq; - real_mode = false; - break; - case SUBDEV_CONN_REAL_I: - iq_swap = fe_swap_iq; - real_mode = true; - break; - case SUBDEV_CONN_REAL_Q: - iq_swap = not fe_swap_iq; - real_mode = true; - break; - } - _iface->poke32(B100_REG_DSP_RX_MUX(i), - (iq_swap? B100_FLAG_DSP_RX_MUX_SWAP_IQ : 0) | - (real_mode? B100_FLAG_DSP_RX_MUX_REAL_MODE : 0) - ); - } - this->update_xport_channel_mapping(); - }return; - - case MBOARD_PROP_TX_SUBDEV_SPEC: - _tx_subdev_spec = val.as<subdev_spec_t>(); - verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link()); - //sanity check - UHD_ASSERT_THROW(_tx_subdev_spec.size() <= B100_NUM_TX_DSPS); - //set the mux - _iface->poke32(B100_REG_TX_FE_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; - - case MBOARD_PROP_EEPROM_MAP: - // Step1: commit the map, writing only those values set. - // Step2: readback the entire eeprom map into the iface. - val.as<mboard_eeprom_t>().commit(*_iface, mboard_eeprom_t::MAP_B000); - _iface->mb_eeprom = mboard_eeprom_t(*_iface, mboard_eeprom_t::MAP_B000); - return; - - case MBOARD_PROP_CLOCK_CONFIG: - _clock_config = val.as<clock_config_t>(); - update_clock_config(); - return; - - case MBOARD_PROP_CLOCK_RATE: - UHD_MSG(warning) - << "You are setting the master clock rate from the API.\n" - << "You may want to pass this into the device address as master_clock_rate=<rate>.\n" - << "This way, the clock rate is guaranteed to be initialized first.\n" - << "See the application notes for USRP-B100 for further instructions.\n" - ; - _clock_ctrl->set_fpga_clock_rate(val.as<double>()); - update_xport_channel_mapping(); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} |