diff options
Diffstat (limited to 'host/lib/usrp/common')
| -rw-r--r-- | host/lib/usrp/common/CMakeLists.txt | 35 | ||||
| -rw-r--r-- | host/lib/usrp/common/apply_corrections.cpp | 180 | ||||
| -rw-r--r-- | host/lib/usrp/common/apply_corrections.hpp | 41 | ||||
| -rw-r--r-- | host/lib/usrp/common/async_packet_handler.hpp | 71 | ||||
| -rw-r--r-- | host/lib/usrp/common/fx2_ctrl.cpp | 472 | ||||
| -rw-r--r-- | host/lib/usrp/common/fx2_ctrl.hpp | 129 | ||||
| -rw-r--r-- | host/lib/usrp/common/recv_packet_demuxer.cpp | 87 | ||||
| -rw-r--r-- | host/lib/usrp/common/recv_packet_demuxer.hpp | 41 | ||||
| -rw-r--r-- | host/lib/usrp/common/validate_subdev_spec.cpp | 73 | ||||
| -rw-r--r-- | host/lib/usrp/common/validate_subdev_spec.hpp | 38 | 
10 files changed, 1167 insertions, 0 deletions
| diff --git a/host/lib/usrp/common/CMakeLists.txt b/host/lib/usrp/common/CMakeLists.txt new file mode 100644 index 000000000..9abd34afa --- /dev/null +++ b/host/lib/usrp/common/CMakeLists.txt @@ -0,0 +1,35 @@ +# +# Copyright 2011 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +######################################################################## +# This file included, use CMake directory variables +######################################################################## +IF(ENABLE_USB) +    INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../firmware/fx2/common) + +    LIBUHD_APPEND_SOURCES( +        ${CMAKE_CURRENT_SOURCE_DIR}/fx2_ctrl.cpp +    ) +ENDIF(ENABLE_USB) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +LIBUHD_APPEND_SOURCES( +    ${CMAKE_CURRENT_SOURCE_DIR}/apply_corrections.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/validate_subdev_spec.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/recv_packet_demuxer.cpp +) diff --git a/host/lib/usrp/common/apply_corrections.cpp b/host/lib/usrp/common/apply_corrections.cpp new file mode 100644 index 000000000..b889266f2 --- /dev/null +++ b/host/lib/usrp/common/apply_corrections.cpp @@ -0,0 +1,180 @@ +// +// 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 "apply_corrections.hpp" +#include <uhd/usrp/dboard_eeprom.hpp> +#include <uhd/utils/paths.hpp> +#include <uhd/utils/msg.hpp> +#include <uhd/utils/csv.hpp> +#include <uhd/types/dict.hpp> +#include <boost/filesystem.hpp> +#include <boost/foreach.hpp> +#include <boost/thread/mutex.hpp> +#include <cstdio> +#include <complex> +#include <fstream> + +namespace fs = boost::filesystem; + +boost::mutex corrections_mutex; + +/*********************************************************************** + * Helper routines + **********************************************************************/ +static double linear_interp(double x, double x0, double y0, double x1, double y1){ +    return y0 + (x - x0)*(y1 - y0)/(x1 - x0); +} + +/*********************************************************************** + * FE apply corrections implementation + **********************************************************************/ +struct fe_cal_t{ +    double lo_freq; +    double iq_corr_real; +    double iq_corr_imag; +}; + +static bool fe_cal_comp(fe_cal_t a, fe_cal_t b){ +    return (a.lo_freq < b.lo_freq); +} + +static uhd::dict<std::string, std::vector<fe_cal_t> > fe_cal_cache; + +static std::complex<double> get_fe_correction( +    const std::string &key, const double lo_freq +){ +    const std::vector<fe_cal_t> &datas = fe_cal_cache[key]; +    if (datas.empty()) throw uhd::runtime_error("empty calibration table " + key); + +    //search for lo freq +    size_t lo_index = 0; +    size_t hi_index = datas.size()-1; +    for (size_t i = 0; i < datas.size(); i++){ +        if (datas[i].lo_freq > lo_freq){ +            hi_index = i; +            break; +        } +        lo_index = i; +    } + +    if (lo_index == 0) return std::complex<double>(datas[lo_index].iq_corr_real, datas[lo_index].iq_corr_imag); +    if (hi_index == lo_index) return std::complex<double>(datas[hi_index].iq_corr_real, datas[hi_index].iq_corr_imag); + +    //interpolation time +    return std::complex<double>( +        linear_interp(lo_freq, datas[lo_index].lo_freq, datas[lo_index].iq_corr_real, datas[hi_index].lo_freq, datas[hi_index].iq_corr_real), +        linear_interp(lo_freq, datas[lo_index].lo_freq, datas[lo_index].iq_corr_imag, datas[hi_index].lo_freq, datas[hi_index].iq_corr_imag) +    ); +} + +static void apply_fe_corrections( +    uhd::property_tree::sptr sub_tree, +    const uhd::fs_path &db_path, +    const uhd::fs_path &fe_path, +    const std::string &file_prefix, +    const double lo_freq +){ +    //extract eeprom serial +    const uhd::usrp::dboard_eeprom_t db_eeprom = sub_tree->access<uhd::usrp::dboard_eeprom_t>(db_path).get(); + +    //make the calibration file path +    const fs::path cal_data_path = fs::path(uhd::get_app_path()) / ".uhd" / "cal" / (file_prefix + db_eeprom.serial + ".csv"); +    if (not fs::exists(cal_data_path)) return; + +    //parse csv file or get from cache +    if (not fe_cal_cache.has_key(cal_data_path.string())){ +        std::ifstream cal_data(cal_data_path.string().c_str()); +        const uhd::csv::rows_type rows = uhd::csv::to_rows(cal_data); + +        bool read_data = false, skip_next = false;; +        std::vector<fe_cal_t> datas; +        BOOST_FOREACH(const uhd::csv::row_type &row, rows){ +            if (not read_data and not row.empty() and row[0] == "DATA STARTS HERE"){ +                read_data = true; +                skip_next = true; +                continue; +            } +            if (not read_data) continue; +            if (skip_next){ +                skip_next = false; +                continue; +            } +            fe_cal_t data; +            std::sscanf(row[0].c_str(), "%lf" , &data.lo_freq); +            std::sscanf(row[1].c_str(), "%lf" , &data.iq_corr_real); +            std::sscanf(row[2].c_str(), "%lf" , &data.iq_corr_imag); +            datas.push_back(data); +        } +        std::sort(datas.begin(), datas.end(), fe_cal_comp); +        fe_cal_cache[cal_data_path.string()] = datas; +        UHD_MSG(status) << "Loaded " << cal_data_path.string() << std::endl; + +    } + +    sub_tree->access<std::complex<double> >(fe_path) +        .set(get_fe_correction(cal_data_path.string(), lo_freq)); +} + +/*********************************************************************** + * Wrapper routines with nice try/catch + print + **********************************************************************/ +void uhd::usrp::apply_tx_fe_corrections( +    property_tree::sptr sub_tree, //starts at mboards/x +    const std::string &slot, //name of dboard slot +    const double lo_freq //actual lo freq +){ +    boost::mutex::scoped_lock l(corrections_mutex); +    try{ +        apply_fe_corrections( +            sub_tree, +            "dboards/" + slot + "/tx_eeprom", +            "tx_frontends/" + slot + "/iq_balance/value", +            "tx_iq_cal_v0.2_", +            lo_freq +        ); +        apply_fe_corrections( +            sub_tree, +            "dboards/" + slot + "/tx_eeprom", +            "tx_frontends/" + slot + "/dc_offset/value", +            "tx_dc_cal_v0.2_", +            lo_freq +        ); +    } +    catch(const std::exception &e){ +        UHD_MSG(error) << "Failure in apply_tx_fe_corrections: " << e.what() << std::endl; +    } +} + +void uhd::usrp::apply_rx_fe_corrections( +    property_tree::sptr sub_tree, //starts at mboards/x +    const std::string &slot, //name of dboard slot +    const double lo_freq //actual lo freq +){ +    boost::mutex::scoped_lock l(corrections_mutex); +    try{ +        apply_fe_corrections( +            sub_tree, +            "dboards/" + slot + "/rx_eeprom", +            "rx_frontends/" + slot + "/iq_balance/value", +            "rx_iq_cal_v0.2_", +            lo_freq +        ); +    } +    catch(const std::exception &e){ +        UHD_MSG(error) << "Failure in apply_rx_fe_corrections: " << e.what() << std::endl; +    } +} diff --git a/host/lib/usrp/common/apply_corrections.hpp b/host/lib/usrp/common/apply_corrections.hpp new file mode 100644 index 000000000..c516862d1 --- /dev/null +++ b/host/lib/usrp/common/apply_corrections.hpp @@ -0,0 +1,41 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_COMMON_APPLY_CORRECTIONS_HPP +#define INCLUDED_LIBUHD_USRP_COMMON_APPLY_CORRECTIONS_HPP + +#include <uhd/config.hpp> +#include <uhd/property_tree.hpp> +#include <string> + +namespace uhd{ namespace usrp{ + +    void apply_tx_fe_corrections( +        property_tree::sptr sub_tree, //starts at mboards/x +        const std::string &slot, //name of dboard slot +        const double tx_lo_freq //actual lo freq +    ); + +    void apply_rx_fe_corrections( +        property_tree::sptr sub_tree, //starts at mboards/x +        const std::string &slot, //name of dboard slot +        const double rx_lo_freq //actual lo freq +    ); + +}} //namespace uhd::usrp + +#endif /* INCLUDED_LIBUHD_USRP_COMMON_APPLY_CORRECTIONS_HPP */ diff --git a/host/lib/usrp/common/async_packet_handler.hpp b/host/lib/usrp/common/async_packet_handler.hpp new file mode 100644 index 000000000..fef03483f --- /dev/null +++ b/host/lib/usrp/common/async_packet_handler.hpp @@ -0,0 +1,71 @@ +// +// Copyright 2012 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_COMMON_ASYNC_PACKET_HANDLER_HPP +#define INCLUDED_LIBUHD_USRP_COMMON_ASYNC_PACKET_HANDLER_HPP + +#include <uhd/config.hpp> +#include <uhd/transport/vrt_if_packet.hpp> +#include <uhd/types/metadata.hpp> +#include <uhd/utils/byteswap.hpp> +#include <uhd/utils/msg.hpp> + +namespace uhd{ namespace usrp{ + +    template <typename to_host_type> +    void load_metadata_from_buff( +        const to_host_type &to_host, +        async_metadata_t &metadata, +        const transport::vrt::if_packet_info_t &if_packet_info, +        const boost::uint32_t *vrt_hdr, +        const double tick_rate, +        const size_t channel = 0 +    ){ +        const boost::uint32_t *payload = vrt_hdr + if_packet_info.num_header_words32; + +        //load into metadata +        metadata.channel = channel; +        metadata.has_time_spec = if_packet_info.has_tsf; +        metadata.time_spec = time_spec_t::from_ticks(if_packet_info.tsf, tick_rate); +        metadata.event_code = async_metadata_t::event_code_t(to_host(payload[0]) & 0xff); + +        //load user payload +        for (size_t i = 1; i < if_packet_info.num_payload_words32; i++){ +            if (i-1 == 4) break; //limit of 4 words32 +            metadata.user_payload[i-1] = to_host(payload[i]); +        } +    } + +    UHD_INLINE void standard_async_msg_prints(const async_metadata_t &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 if (metadata.event_code & +            async_metadata_t::EVENT_CODE_TIME_ERROR +        ) UHD_MSG(fastpath) << "L"; +    } + + +}} //namespace uhd::usrp + +#endif /* INCLUDED_LIBUHD_USRP_COMMON_ASYNC_PACKET_HANDLER_HPP */ diff --git a/host/lib/usrp/common/fx2_ctrl.cpp b/host/lib/usrp/common/fx2_ctrl.cpp new file mode 100644 index 000000000..7b8920eb1 --- /dev/null +++ b/host/lib/usrp/common/fx2_ctrl.cpp @@ -0,0 +1,472 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "fx2_ctrl.hpp" +#include "usrp_commands.h" +#include <uhd/utils/msg.hpp> +#include <uhd/exception.hpp> +#include <uhd/transport/usb_control.hpp> +#include <boost/functional/hash.hpp> +#include <boost/thread/thread.hpp> +#include <boost/cstdint.hpp> +#include <fstream> +#include <sstream> +#include <string> +#include <vector> +#include <cstring> + +using namespace uhd; +using namespace uhd::usrp; + +#define FX2_FIRMWARE_LOAD 0xa0 + +static const bool load_img_msg = true; + +typedef boost::uint32_t hash_type; + +/*********************************************************************** + * Helper Functions + **********************************************************************/ +/*! + * Create a file hash + * The hash will be used to identify the loaded firmware and fpga image + * \param filename file used to generate hash value + * \return hash value in a size_t type + */ +static hash_type generate_hash(const char *filename) +{ +    std::ifstream file(filename); +    if (not file){ +        throw uhd::io_error(std::string("cannot open input file ") + filename); +    } + +    size_t hash = 0; + +    char ch; +    while (file.get(ch)) { +        boost::hash_combine(hash, ch); +    } + +    if (not file.eof()){ +        throw uhd::io_error(std::string("file error ") + filename); +    } + +    file.close(); +    return hash_type(hash); +} + + +/*! + * Verify checksum of a Intel HEX record + * \param record a line from an Intel HEX file + * \return true if record is valid, false otherwise + */ +static bool checksum(std::string *record) +{ + +    size_t len = record->length(); +    unsigned int i; +    unsigned char sum = 0; +    unsigned int val; + +    for (i = 1; i < len; i += 2) { +        std::istringstream(record->substr(i, 2)) >> std::hex >> val; +        sum += val; +    } + +    if (sum == 0) +       return true; +    else +       return false; +} + + +/*! + * Parse Intel HEX record + * + * \param record a line from an Intel HEX file + * \param len output length of record + * \param addr output address + * \param type output type + * \param data output data + * \return true if record is sucessfully read, false on error + */ +bool parse_record(std::string *record, unsigned int &len, +                  unsigned int &addr, unsigned int &type, +                  unsigned char* data) +{ +    unsigned int i; +    std::string _data; +    unsigned int val; + +    if (record->substr(0, 1) != ":") +        return false; + +    std::istringstream(record->substr(1, 2)) >> std::hex >> len; +    std::istringstream(record->substr(3, 4)) >> std::hex >> addr; +    std::istringstream(record->substr(7, 2)) >> std::hex >> type; + +    for (i = 0; i < len; i++) { +        std::istringstream(record->substr(9 + 2 * i, 2)) >> std::hex >> val; +        data[i] = (unsigned char) val; +    } + +    return true; +} + + +/*! + * USRP control implementation for device discovery and configuration + */ +class fx2_ctrl_impl : public fx2_ctrl { +public: +    fx2_ctrl_impl(uhd::transport::usb_control::sptr ctrl_transport) +    { +        _ctrl_transport = ctrl_transport; +    } + +    void usrp_fx2_reset(void){ +        unsigned char reset_y = 1; +        unsigned char reset_n = 0; +        usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_y, 1); +        usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_n, 1); +        //wait for things to settle +        boost::this_thread::sleep(boost::posix_time::milliseconds(2000)); +    } + +    void usrp_load_firmware(std::string filestring, bool force) +    { +        const char *filename = filestring.c_str(); + +        hash_type hash = generate_hash(filename); + +        hash_type loaded_hash; usrp_get_firmware_hash(loaded_hash); + +        if (not force and (hash == loaded_hash)) return; + +        //FIXME: verify types +        unsigned int len; +        unsigned int addr; +        unsigned int type; +        unsigned char data[512]; + +        std::ifstream file; +        file.open(filename, std::ifstream::in); + +        if (!file.good()) { +            throw uhd::io_error("usrp_load_firmware: cannot open firmware input file"); +        } + +        unsigned char reset_y = 1; +        unsigned char reset_n = 0; + +        //hit the reset line +        if (load_img_msg) UHD_MSG(status) << "Loading firmware image: " << filestring << "..." << std::flush; +        usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_y, 1); + +        while (!file.eof()) { +           std::string record; +           file >> record; + +            //check for valid record +            if (not checksum(&record) or not parse_record(&record, len, addr, type, data)) { +                throw uhd::io_error("usrp_load_firmware: bad record checksum"); +            } + +            //type 0x00 is data +            if (type == 0x00) { +                int ret = usrp_control_write(FX2_FIRMWARE_LOAD, addr, 0, data, len); +                if (ret < 0) throw uhd::io_error("usrp_load_firmware: usrp_control_write failed"); +            } +            //type 0x01 is end +            else if (type == 0x01) { +                usrp_set_firmware_hash(hash); //set hash before reset +                usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_n, 1); +                file.close(); + +                //wait for things to settle +                boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); +                if (load_img_msg) UHD_MSG(status) << " done" << std::endl; +                return; +            } +            //type anything else is unhandled +            else { +                throw uhd::io_error("usrp_load_firmware: unsupported record"); +            } +        } + +        //file did not end +        throw uhd::io_error("usrp_load_firmware: bad record"); +    } + +    void usrp_init(void){ +        //disable +        usrp_rx_enable(false); +        usrp_tx_enable(false); + +        //toggle resets +        usrp_rx_reset(true); +        usrp_tx_reset(true); +        usrp_rx_reset(false); +        usrp_tx_reset(false); +    } + +    void usrp_load_fpga(std::string filestring) +    { +        const char *filename = filestring.c_str(); + +        hash_type hash = generate_hash(filename); + +        hash_type loaded_hash; usrp_get_fpga_hash(loaded_hash); + +        if (hash == loaded_hash) return; +        const int ep0_size = 64; +        unsigned char buf[ep0_size]; + +        if (load_img_msg) UHD_MSG(status) << "Loading FPGA image: " << filestring << "..." << std::flush; +        std::ifstream file; +        file.open(filename, std::ios::in | std::ios::binary); +        if (not file.good()) { +            throw uhd::io_error("usrp_load_fpga: cannot open fpga input file"); +        } + +        usrp_fpga_reset(true); //holding the fpga in reset while loading + +        if (usrp_control_write_cmd(VRQ_FPGA_LOAD, 0, FL_BEGIN) < 0) { +            throw uhd::io_error("usrp_load_fpga: fpga load error"); +        } + +        while (not file.eof()) { +            file.read((char *)buf, sizeof(buf)); +            const std::streamsize n = file.gcount(); +            if(n == 0) continue; +            int ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER, buf, boost::uint16_t(n)); +            if (ret < 0 or std::streamsize(ret) != n) { +                throw uhd::io_error("usrp_load_fpga: fpga load error"); +            } +        } + +        if (usrp_control_write_cmd(VRQ_FPGA_LOAD, 0, FL_END) < 0) { +            throw uhd::io_error("usrp_load_fpga: fpga load error"); +        } + +        usrp_set_fpga_hash(hash); + +        usrp_fpga_reset(false); //done loading, take fpga out of reset + +        file.close(); +        if (load_img_msg) UHD_MSG(status) << " done" << std::endl; +    } + +    void usrp_load_eeprom(std::string filestring) +    { +        if (load_img_msg) UHD_MSG(status) << "Loading EEPROM image: " << filestring << "..." << std::flush; +        const char *filename = filestring.c_str(); +        const boost::uint16_t i2c_addr = 0x50; + +        unsigned int addr; +        unsigned char data[256]; +        unsigned char sendbuf[17]; + +        std::ifstream file; +        file.open(filename, std::ifstream::in); + +        if (not file.good()) { +            throw uhd::io_error("usrp_load_eeprom: cannot open EEPROM input file"); +        } + +        file.read((char *)data, 256); +        std::streamsize len = file.gcount(); + +        if(len == 256) { +            throw uhd::io_error("usrp_load_eeprom: image size too large"); +        } + +        const int pagesize = 16; +        addr = 0; +        while(len > 0) { +            sendbuf[0] = addr; +            memcpy(sendbuf+1, &data[addr], len > pagesize ? pagesize : size_t(len)); +            int ret = usrp_i2c_write(i2c_addr, sendbuf, (len > pagesize ? pagesize : size_t(len))+1); +            if (ret < 0) { +                throw uhd::io_error("usrp_load_eeprom: usrp_i2c_write failed"); +            } +            addr += pagesize; +            len -= pagesize; +            boost::this_thread::sleep(boost::posix_time::milliseconds(100)); +        } +        file.close(); +        if (load_img_msg) UHD_MSG(status) << " done" << std::endl; +    } + + +    void usrp_set_led(int led_num, bool on) +    { +        UHD_ASSERT_THROW(usrp_control_write_cmd(VRQ_SET_LED, on, led_num) >= 0); +    } + + +    void usrp_get_firmware_hash(hash_type &hash) +    { +        UHD_ASSERT_THROW(usrp_control_read(0xa0, USRP_HASH_SLOT_0_ADDR, 0, +                                 (unsigned char*) &hash, sizeof(hash)) >= 0); +    } + + +    void usrp_set_firmware_hash(hash_type hash) +    { +        UHD_ASSERT_THROW(usrp_control_write(0xa0, USRP_HASH_SLOT_0_ADDR, 0, +                                  (unsigned char*) &hash, sizeof(hash)) >= 0); + +    } + + +    void usrp_get_fpga_hash(hash_type &hash) +    { +        UHD_ASSERT_THROW(usrp_control_read(0xa0, USRP_HASH_SLOT_1_ADDR, 0, +                                 (unsigned char*) &hash, sizeof(hash)) >= 0); +    } + + +    void usrp_set_fpga_hash(hash_type hash) +    { +        UHD_ASSERT_THROW(usrp_control_write(0xa0, USRP_HASH_SLOT_1_ADDR, 0, +                                  (unsigned char*) &hash, sizeof(hash)) >= 0); +    } + +    void usrp_tx_enable(bool on) +    { +        UHD_ASSERT_THROW(usrp_control_write_cmd(VRQ_FPGA_SET_TX_ENABLE, on, 0) >= 0); +    } + + +    void usrp_rx_enable(bool on) +    { +        UHD_ASSERT_THROW(usrp_control_write_cmd(VRQ_FPGA_SET_RX_ENABLE, on, 0) >= 0); +    } + + +    void usrp_tx_reset(bool on) +    { +        UHD_ASSERT_THROW(usrp_control_write_cmd(VRQ_FPGA_SET_TX_RESET, on, 0) >= 0); +    } + + +    void usrp_rx_reset(bool on) +    { +        UHD_ASSERT_THROW(usrp_control_write_cmd(VRQ_FPGA_SET_RX_RESET, on, 0) >= 0); +    } + +    void usrp_fpga_reset(bool on) +    { +        UHD_ASSERT_THROW(usrp_control_write_cmd(VRQ_FPGA_SET_RESET, on, 0) >= 0); +    } + +    int usrp_control_write(boost::uint8_t request, +                           boost::uint16_t value, +                           boost::uint16_t index, +                           unsigned char *buff, +                           boost::uint16_t length) +    { +        return _ctrl_transport->submit(VRT_VENDOR_OUT,     // bmReqeustType +                                       request,            // bRequest +                                       value,              // wValue +                                       index,              // wIndex +                                       buff,               // data +                                       length);            // wLength +    } + + +    int usrp_control_read(boost::uint8_t request, +                          boost::uint16_t value, +                          boost::uint16_t index, +                          unsigned char *buff, +                          boost::uint16_t length) +    { +        return _ctrl_transport->submit(VRT_VENDOR_IN,      // bmReqeustType +                                       request,            // bRequest +                                       value,              // wValue +                                       index,              // wIndex +                                       buff,               // data +                                       length);            // wLength +    } + + +    int usrp_control_write_cmd(boost::uint8_t request, boost::uint16_t value, boost::uint16_t index) +    { +        return usrp_control_write(request, value, index, 0, 0); +    } + +    int usrp_i2c_write(boost::uint16_t i2c_addr, unsigned char *buf, boost::uint16_t len) +    { +        return usrp_control_write(VRQ_I2C_WRITE, i2c_addr, 0, buf, len); +    } + +    int usrp_i2c_read(boost::uint16_t i2c_addr, unsigned char *buf, boost::uint16_t len) +    { +        return usrp_control_read(VRQ_I2C_READ, i2c_addr, 0, buf, len); +    } + +    static const bool iface_debug = false; +    static const size_t max_i2c_data_bytes = 64; + +    void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes) +    { +        UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes); + +        unsigned char buff[max_i2c_data_bytes] = {}; +        std::copy(bytes.begin(), bytes.end(), buff); + +        int ret = this->usrp_i2c_write(addr & 0xff, +                                             buff, +                                             bytes.size()); + +        if (iface_debug && (ret < 0)) +            uhd::runtime_error("USRP: failed i2c write"); +    } + +    byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes) +    { +      UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes); + +      unsigned char buff[max_i2c_data_bytes] = {}; +      int ret = this->usrp_i2c_read(addr & 0xff, +                                            buff, +                                            num_bytes); + +      if (iface_debug && ((ret < 0) || (unsigned)ret < (num_bytes))) +          uhd::runtime_error("USRP: failed i2c read"); + +      byte_vector_t out_bytes; +      for (size_t i = 0; i < num_bytes; i++) +          out_bytes.push_back(buff[i]); + +      return out_bytes; +    } + + +private: +    uhd::transport::usb_control::sptr _ctrl_transport; +}; + +/*********************************************************************** + * Public make function for fx2_ctrl interface + **********************************************************************/ +fx2_ctrl::sptr fx2_ctrl::make(uhd::transport::usb_control::sptr ctrl_transport){ +    return sptr(new fx2_ctrl_impl(ctrl_transport)); +} + diff --git a/host/lib/usrp/common/fx2_ctrl.hpp b/host/lib/usrp/common/fx2_ctrl.hpp new file mode 100644 index 000000000..f2e060862 --- /dev/null +++ b/host/lib/usrp/common/fx2_ctrl.hpp @@ -0,0 +1,129 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_COMMON_FX2_CTRL_HPP +#define INCLUDED_LIBUHD_USRP_COMMON_FX2_CTRL_HPP + +#include <uhd/transport/usb_control.hpp> +#include <uhd/types/serial.hpp> //i2c iface +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> + +namespace uhd{ namespace usrp{ + +class fx2_ctrl : boost::noncopyable, public uhd::i2c_iface{ +public: +    typedef boost::shared_ptr<fx2_ctrl> sptr; + +    /*! +     * Make a usrp control object from a control transport +     * \param ctrl_transport a USB control transport +     * \return a new usrp control object +     */ +    static sptr make(uhd::transport::usb_control::sptr ctrl_transport); + +    //! Call init after the fpga is loaded +    virtual void usrp_init(void) = 0; + +    //! For emergency situations +    virtual void usrp_fx2_reset(void) = 0; + +    /*! +     * Load firmware in Intel HEX Format onto device  +     * \param filename name of firmware file +     * \param force reload firmware if already loaded +     */ +    virtual void usrp_load_firmware(std::string filename, +                                   bool force = false) = 0; + +    /*! +     * Load fpga file onto usrp  +     * \param filename name of fpga image  +     */ +    virtual void usrp_load_fpga(std::string filename) = 0; + +    /*! +     * Load USB descriptor file in Intel HEX format into EEPROM +     * \param filename name of EEPROM image +     */ +    virtual void usrp_load_eeprom(std::string filestring) = 0; +     +    /*! +     * Submit an IN transfer  +     * \param request device specific request  +     * \param value device specific field +     * \param index device specific field +     * \param buff buffer to place data +     * \return number of bytes read or error  +     */ +    virtual int usrp_control_read(boost::uint8_t request, +                                  boost::uint16_t value, +                                  boost::uint16_t index, +                                  unsigned char *buff, +                                  boost::uint16_t length) = 0; + +    /*! +     * Submit an OUT transfer  +     * \param request device specific request  +     * \param value device specific field +     * \param index device specific field +     * \param buff buffer of data to be sent  +     * \return number of bytes written or error  +     */ +    virtual int usrp_control_write(boost::uint8_t request, +                                   boost::uint16_t value, +                                   boost::uint16_t index, +                                   unsigned char *buff, +                                   boost::uint16_t length) = 0; + +    /*! +     * Perform an I2C write +     * \param i2c_addr I2C device address +     * \param buf data to be written  +     * \param len length of data in bytes +     * \return number of bytes written or error  +     */ + +    virtual int usrp_i2c_write(boost::uint16_t i2c_addr, +                               unsigned char *buf,  +                               boost::uint16_t len) = 0; + +    /*! +     * Perform an I2C read +     * \param i2c_addr I2C device address +     * \param buf data to be read  +     * \param len length of data in bytes +     * \return number of bytes read or error  +     */ + +    virtual int usrp_i2c_read(boost::uint16_t i2c_addr, +                               unsigned char *buf,  +                               boost::uint16_t len) = 0; + +    //! enable/disable the rx path +    virtual void usrp_rx_enable(bool on) = 0; + +    //! enable/disable the tx path +    virtual void usrp_tx_enable(bool on) = 0; + +    //! reset the fpga +    virtual void usrp_fpga_reset(bool on) = 0; +}; + +}} //namespace uhd::usrp + +#endif /* INCLUDED_LIBUHD_USRP_COMMON_FX2_CTRL_HPP */ diff --git a/host/lib/usrp/common/recv_packet_demuxer.cpp b/host/lib/usrp/common/recv_packet_demuxer.cpp new file mode 100644 index 000000000..f2cfe3bb0 --- /dev/null +++ b/host/lib/usrp/common/recv_packet_demuxer.cpp @@ -0,0 +1,87 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "recv_packet_demuxer.hpp" +#include <uhd/utils/msg.hpp> +#include <uhd/utils/byteswap.hpp> +#include <boost/thread/mutex.hpp> +#include <queue> +#include <deque> +#include <vector> + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::transport; + +static UHD_INLINE boost::uint32_t extract_sid(managed_recv_buffer::sptr &buff){ +    //ASSUME that the data is in little endian format +    return uhd::wtohx(buff->cast<const boost::uint32_t *>()[1]); +} + +class recv_packet_demuxer_impl : public uhd::usrp::recv_packet_demuxer{ +public: +    recv_packet_demuxer_impl( +        transport::zero_copy_if::sptr transport, +        const size_t size, +        const boost::uint32_t sid_base +    ): +        _transport(transport), _sid_base(sid_base), _queues(size) +    { +        /* NOP */ +    } + +    managed_recv_buffer::sptr get_recv_buff(const size_t index, const double timeout){ +        boost::mutex::scoped_lock lock(_mutex); +        managed_recv_buffer::sptr buff; + +        //there is already an entry in the queue, so pop that +        if (not _queues[index].wrapper.empty()){ +            std::swap(buff, _queues[index].wrapper.front()); +            _queues[index].wrapper.pop(); +            return buff; +        } + +        while (true){ +            //otherwise call into the transport +            buff = _transport->get_recv_buff(timeout); +            if (buff.get() == NULL) return buff; //timeout + +            //check the stream id to know which channel +            const size_t rx_index = extract_sid(buff) - _sid_base; +            if (rx_index == index) return buff; //got expected message + +            //otherwise queue and try again +            if (rx_index < _queues.size()) _queues[rx_index].wrapper.push(buff); +            else UHD_MSG(error) << "Got a data packet with unknown SID " << extract_sid(buff) << std::endl; +        } +    } + +private: +    transport::zero_copy_if::sptr _transport; +    const boost::uint32_t _sid_base; +    boost::mutex _mutex; +    struct channel_guts_type{ +        channel_guts_type(void): wrapper(container){} +        std::deque<managed_recv_buffer::sptr> container; +        std::queue<managed_recv_buffer::sptr> wrapper; +    }; +    std::vector<channel_guts_type> _queues; +}; + +recv_packet_demuxer::sptr recv_packet_demuxer::make(transport::zero_copy_if::sptr transport, const size_t size, const boost::uint32_t sid_base){ +    return sptr(new recv_packet_demuxer_impl(transport, size, sid_base)); +} diff --git a/host/lib/usrp/common/recv_packet_demuxer.hpp b/host/lib/usrp/common/recv_packet_demuxer.hpp new file mode 100644 index 000000000..fde756d27 --- /dev/null +++ b/host/lib/usrp/common/recv_packet_demuxer.hpp @@ -0,0 +1,41 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_COMMON_RECV_PACKET_DEMUXER_HPP +#define INCLUDED_LIBUHD_USRP_COMMON_RECV_PACKET_DEMUXER_HPP + +#include <uhd/config.hpp> +#include <uhd/transport/zero_copy.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/cstdint.hpp> + +namespace uhd{ namespace usrp{ + +    class recv_packet_demuxer{ +    public: +        typedef boost::shared_ptr<recv_packet_demuxer> sptr; + +        //! Make a new demuxer from a transport and parameters +        static sptr make(transport::zero_copy_if::sptr transport, const size_t size, const boost::uint32_t sid_base); + +        //! Get a buffer at the given index from the transport +        virtual transport::managed_recv_buffer::sptr get_recv_buff(const size_t index, const double timeout) = 0; +    }; + +}} //namespace uhd::usrp + +#endif /* INCLUDED_LIBUHD_USRP_COMMON_RECV_PACKET_DEMUXER_HPP */ diff --git a/host/lib/usrp/common/validate_subdev_spec.cpp b/host/lib/usrp/common/validate_subdev_spec.cpp new file mode 100644 index 000000000..fab40b204 --- /dev/null +++ b/host/lib/usrp/common/validate_subdev_spec.cpp @@ -0,0 +1,73 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "validate_subdev_spec.hpp" +#include <uhd/exception.hpp> +#include <uhd/utils/assert_has.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> + +using namespace uhd; +using namespace uhd::usrp; + +namespace uhd{ namespace usrp{ + +    static std::ostream& operator<< (std::ostream &out, const subdev_spec_pair_t &pair){ +        out << pair.db_name << ":" << pair.sd_name; +        return out; +    } + +}} + +void uhd::usrp::validate_subdev_spec( +    property_tree::sptr tree, +    const subdev_spec_t &spec, +    const std::string &type, +    const std::string &mb +){ +    const size_t num_dsps = tree->list(str(boost::format("/mboards/%s/%s_dsps") % mb % type)).size(); + +    //sanity checking on the length +    if (spec.size() == 0) throw uhd::value_error(str(boost::format( +        "Empty %s subdevice specification is not supported.\n" +    ) % type)); +    if (spec.size() > num_dsps) throw uhd::value_error(str(boost::format( +        "The subdevice specification \"%s\" is too long.\n" +        "The user specified %u channels, but there are only %u %s dsps on mboard %s.\n" +    ) % spec.to_string() % spec.size() % num_dsps % type % mb)); + +    //make a list of all possible specs +    subdev_spec_t all_specs; +    BOOST_FOREACH(const std::string &db, tree->list(str(boost::format("/mboards/%s/dboards") % mb))){ +        BOOST_FOREACH(const std::string &sd, tree->list(str(boost::format("/mboards/%s/dboards/%s/%s_frontends") % mb % db % type))){ +            all_specs.push_back(subdev_spec_pair_t(db, sd)); +        } +    } + +    //validate that the spec is possible +    BOOST_FOREACH(const subdev_spec_pair_t &pair, spec){ +        uhd::assert_has(all_specs, pair, str(boost::format("%s subdevice specification on mboard %s") % type % mb)); +    } + +    //enable selected frontends, disable others +    BOOST_FOREACH(const subdev_spec_pair_t &pair, all_specs){ +        const bool enb = uhd::has(spec, pair); +        tree->access<bool>(str(boost::format( +            "/mboards/%s/dboards/%s/%s_frontends/%s/enabled" +        ) % mb % pair.db_name % type % pair.sd_name)).set(enb); +    } +} diff --git a/host/lib/usrp/common/validate_subdev_spec.hpp b/host/lib/usrp/common/validate_subdev_spec.hpp new file mode 100644 index 000000000..7d9e2c309 --- /dev/null +++ b/host/lib/usrp/common/validate_subdev_spec.hpp @@ -0,0 +1,38 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_COMMON_VALIDATE_SUBDEV_SPEC_HPP +#define INCLUDED_LIBUHD_USRP_COMMON_VALIDATE_SUBDEV_SPEC_HPP + +#include <uhd/config.hpp> +#include <uhd/usrp/subdev_spec.hpp> +#include <uhd/property_tree.hpp> +#include <string> + +namespace uhd{ namespace usrp{ + +    //! Validate a subdev spec against a property tree +    void validate_subdev_spec( +        property_tree::sptr tree, +        const subdev_spec_t &spec, +        const std::string &type, //rx or tx +        const std::string &mb = "0" +    ); + +}} //namespace uhd::usrp + +#endif /* INCLUDED_LIBUHD_USRP_COMMON_VALIDATE_SUBDEV_SPEC_HPP */ | 
