diff options
Diffstat (limited to 'host/utils')
| -rw-r--r-- | host/utils/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | host/utils/b2xx_fx3_utils.cpp | 747 | ||||
| -rw-r--r-- | host/utils/fx2_init_eeprom.cpp | 8 | ||||
| -rw-r--r-- | host/utils/query_gpsdo_sensors.cpp | 3 | ||||
| -rw-r--r-- | host/utils/uhd-usrp.rules | 6 | ||||
| -rw-r--r-- | host/utils/uhd_cal_rx_iq_balance.cpp | 5 | ||||
| -rw-r--r-- | host/utils/uhd_cal_tx_dc_offset.cpp | 4 | ||||
| -rw-r--r-- | host/utils/uhd_cal_tx_iq_balance.cpp | 5 | ||||
| -rw-r--r-- | host/utils/uhd_find_devices.cpp | 7 | ||||
| -rw-r--r-- | host/utils/uhd_usrp_probe.cpp | 26 | ||||
| -rw-r--r-- | host/utils/usrp_burn_db_eeprom.cpp | 4 | ||||
| -rw-r--r-- | host/utils/usrp_burn_mb_eeprom.cpp | 6 | ||||
| -rw-r--r-- | host/utils/usrp_cal_utils.hpp | 6 | ||||
| -rwxr-xr-x | host/utils/usrp_n2xx_net_burner_gui.py | 38 | 
14 files changed, 824 insertions, 43 deletions
| diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index b04d0e1b9..92df0b7cf 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -47,7 +47,9 @@ SET(util_share_sources  IF(ENABLE_USB)      LIST(APPEND util_share_sources          fx2_init_eeprom.cpp +        b2xx_fx3_utils.cpp      ) +    INCLUDE_DIRECTORIES(${LIBUSB_INCLUDE_DIRS})  ENDIF(ENABLE_USB)  IF(LINUX AND ENABLE_USB) diff --git a/host/utils/b2xx_fx3_utils.cpp b/host/utils/b2xx_fx3_utils.cpp new file mode 100644 index 000000000..36688c6c7 --- /dev/null +++ b/host/utils/b2xx_fx3_utils.cpp @@ -0,0 +1,747 @@ +// +// Copyright 2010-2013 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 <cstdlib> +#include <cstring> +#include <iostream> +#include <iomanip> +#include <fstream> +#include <libusb.h> +#include <sstream> +#include <string> +#include <cmath> +#include <cstring> + +#include <boost/cstdint.hpp> +#include <boost/filesystem.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/format.hpp> +#include <boost/program_options.hpp> +#include <boost/thread/thread.hpp> +#include <boost/functional/hash.hpp> + +#include <uhd/config.hpp> +#include <uhd/utils/msg.hpp> + +const static boost::uint16_t FX3_VID = 0x04b4; +const static boost::uint16_t FX3_DEFAULT_PID = 0x00f3; +const static boost::uint16_t FX3_REENUM_PID = 0x00f0; +const static boost::uint16_t B2XX_VID = 0x2500; +const static boost::uint16_t B2XX_PID = 0x0020; + +const static boost::uint8_t VRT_VENDOR_OUT = (LIBUSB_REQUEST_TYPE_VENDOR +                                              | LIBUSB_ENDPOINT_OUT); +const static boost::uint8_t VRT_VENDOR_IN = (LIBUSB_REQUEST_TYPE_VENDOR +                                             | LIBUSB_ENDPOINT_IN); +const static boost::uint8_t FX3_FIRMWARE_LOAD = 0xA0; + +const static boost::uint8_t B2XX_VREQ_FPGA_START = 0x02; +const static boost::uint8_t B2XX_VREQ_FPGA_DATA = 0x12; +const static boost::uint8_t B2XX_VREQ_SET_FPGA_HASH = 0x1C; +const static boost::uint8_t B2XX_VREQ_GET_FPGA_HASH = 0x1D; +const static boost::uint8_t B2XX_VREQ_FPGA_RESET = 0x62; +const static boost::uint8_t B2XX_VREQ_GET_USB = 0x80; +const static boost::uint8_t B2XX_VREQ_GET_STATUS = 0x83; +const static boost::uint8_t B2XX_VREQ_FX3_RESET = 0x99; +const static boost::uint8_t B2XX_VREQ_EEPROM_WRITE = 0xBA; + +const static boost::uint8_t FX3_STATE_FPGA_READY = 0x00; +const static boost::uint8_t FX3_STATE_CONFIGURING_FPGA = 0x01; +const static boost::uint8_t FX3_STATE_BUSY = 0x02; +const static boost::uint8_t FX3_STATE_RUNNING = 0x03; + +typedef boost::uint32_t hash_type; +typedef std::vector<boost::uint8_t> byte_vector_t; + + +namespace po = boost::program_options; +namespace fs = boost::filesystem; + + +//!used with lexical cast to parse a hex string +template <class T> struct to_hex{ +    T value; +    operator T() const {return value;} +    friend std::istream& operator>>(std::istream& in, to_hex& out){ +        in >> std::hex >> out.value; +        return in; +    } +}; + +//!parse hex-formatted ASCII text into an int +boost::uint16_t atoh(const std::string &string){ +    if (string.substr(0, 2) == "0x"){ +        return boost::lexical_cast<to_hex<boost::uint16_t> >(string); +    } +    return boost::lexical_cast<boost::uint16_t>(string); +} + + +/*! + * 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){ +        std::cerr << std::string("cannot open input file ") + filename +            << std::endl; +    } + +    size_t hash = 0; + +    char ch; +    while (file.get(ch)) { +        boost::hash_combine(hash, ch); +    } + +    if (not file.eof()){ +        std::cerr << std::string("file error ") + filename << std::endl; +    } + +    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 + */ +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, boost::uint16_t &len, boost::uint16_t &addr, +        uint16_t &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; +} + + +/*! + * Write data to the FX3. + * + * \param dev_handle the libusb-1.0 device handle + * \param request the usb transfer request type + * \param value the USB bValue + * \param index the USB bIndex + * \param buff the data to write + * \param length the number of bytes to write + * \return the number of bytes written + */ +libusb_error fx3_control_write(libusb_device_handle *dev_handle, boost::uint8_t request, +            boost::uint16_t value, boost::uint16_t index, unsigned char *buff, +            boost::uint16_t length, boost::uint32_t timeout = 0) { + +#if 0 +    if(DEBUG) { +        std::cout << "Writing: <" << std::hex << std::setw(6) << std::showbase \ +            << std::internal << std::setfill('0') << (int) request \ +            << ", " << std::setw(6) << (int) VRT_VENDOR_OUT \ +            << ", " << std::setw(6) << value \ +            << ", " << std::setw(6) << index \ +            << ", " << std::dec << std::setw(2) << length \ +            << ">" << std::endl; + +        std::cout << "\t\tData: 0x " << std::noshowbase; + +        for(int count = 0; count < length; count++) { +            std::cout << std::hex << std::setw(2) << (int) buff[count] << " "; +        } + +        std::cout << std::showbase << std::endl; +    } +#endif + +    return (libusb_error) libusb_control_transfer(dev_handle, VRT_VENDOR_OUT, request, \ +               value, index, buff, length, timeout); +} + + +/*! + * Read data from the FX3. + * + * \param dev_handle the libusb-1.0 device handle + * \param request the usb transfer request type + * \param value the USB bValue + * \param index the USB bIndex + * \param buff a buffer to store the read bytes to + * \param length the number of bytes to read + * \return the number of bytes read + */ +libusb_error fx3_control_read(libusb_device_handle *dev_handle, boost::uint8_t request, +            boost::uint16_t value, boost::uint16_t index, unsigned char *buff, +            boost::uint16_t length, boost::uint32_t timeout = 0) { + +#if 0 +    if(DEBUG) { +        std::cout << "Reading: <" << std::hex << std::setw(6) << std::showbase \ +            << std::internal << std::setfill('0') << (int) request \ +            << ", " << std::setw(6) << (int) VRT_VENDOR_IN \ +            << ", " << std::setw(6) << value \ +            << ", " << std::setw(6) << index \ +            << ", " << std::dec << std::setw(2) << length \ +            << ">" << std::endl << std::endl; +    } +#endif + +    return (libusb_error) libusb_control_transfer(dev_handle, VRT_VENDOR_IN, request, \ +               value, index, buff, length, timeout); +} + + +void write_eeprom(libusb_device_handle *dev_handle, boost::uint8_t addr, +        boost::uint8_t offset, const byte_vector_t &bytes) { +    fx3_control_write(dev_handle, B2XX_VREQ_EEPROM_WRITE, +                        0, offset | (boost::uint16_t(addr) << 8), +                        (unsigned char *) &bytes[0], +                        bytes.size()); +} + + +boost::uint8_t get_fx3_status(libusb_device_handle *dev_handle) { + +    unsigned char rx_data[1]; + +    fx3_control_read(dev_handle, B2XX_VREQ_GET_STATUS, 0x00, 0x00, rx_data, 1); + +    return boost::lexical_cast<boost::uint8_t>(rx_data[0]); +} + +void usrp_get_fpga_hash(libusb_device_handle *dev_handle, hash_type &hash) { +    fx3_control_read(dev_handle, B2XX_VREQ_GET_FPGA_HASH, 0x00, 0x00, +            (unsigned char*) &hash, 4, 500); +} + +void usrp_set_fpga_hash(libusb_device_handle *dev_handle, hash_type hash) { +    fx3_control_write(dev_handle, B2XX_VREQ_SET_FPGA_HASH, 0x00, 0x00, +            (unsigned char*) &hash, 4); +} + +boost::int32_t load_fpga(libusb_device_handle *dev_handle, +        const std::string filestring) { + +    if (filestring.empty()) +    { +        std::cerr << "load_fpga: input file is empty." << std::endl; +        exit(-1); +    } + +    boost::uint8_t fx3_state = 0; + +    const char *filename = filestring.c_str(); + +    hash_type hash = generate_hash(filename); +    hash_type loaded_hash; usrp_get_fpga_hash(dev_handle, loaded_hash); +    if (hash == loaded_hash) return 0; + +    size_t file_size = 0; +    { +        std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); +        file_size = file.tellg(); +    } + +    std::ifstream file; +    file.open(filename, std::ios::in | std::ios::binary); + +    if(!file.good()) { +        std::cerr << "load_fpga: cannot open FPGA input file." << std::endl; +        exit(-1); +    } + +    do { +        fx3_state = get_fx3_status(dev_handle); +        boost::this_thread::sleep(boost::posix_time::milliseconds(10)); +    } while(fx3_state != FX3_STATE_FPGA_READY); + +    std::cout << "Loading FPGA image: " \ +        << filestring << "..." << std::flush; + +    unsigned char out_buff[64]; +    memset(out_buff, 0x00, sizeof(out_buff)); +    fx3_control_write(dev_handle, B2XX_VREQ_FPGA_START, 0, 0, out_buff, 1, 1000); + +    do { +        fx3_state = get_fx3_status(dev_handle); +        boost::this_thread::sleep(boost::posix_time::milliseconds(10)); +    } while(fx3_state != FX3_STATE_CONFIGURING_FPGA); + + +    size_t bytes_sent = 0; +    while(!file.eof()) { +        file.read((char *) out_buff, sizeof(out_buff)); +        const std::streamsize n = file.gcount(); +        if(n == 0) continue; + +        boost::uint16_t transfer_count = boost::uint16_t(n); + +        /* Send the data to the device. */ +        fx3_control_write(dev_handle, B2XX_VREQ_FPGA_DATA, 0, 0, out_buff, +                transfer_count, 5000); + +        if (bytes_sent == 0) std::cout << "  0%" << std::flush; +        const size_t percent_before = size_t((bytes_sent*100)/file_size); +        bytes_sent += transfer_count; +        const size_t percent_after = size_t((bytes_sent*100)/file_size); +        if (percent_before/10 != percent_after/10) { +            std::cout << "\b\b\b\b" << std::setw(3) << percent_after +                << "%" << std::flush; +        } +    } + +    file.close(); + +    do { +        fx3_state = get_fx3_status(dev_handle); +        boost::this_thread::sleep(boost::posix_time::milliseconds(10)); +    } while(fx3_state != FX3_STATE_RUNNING); + +    usrp_set_fpga_hash(dev_handle, hash); + +    std::cout << "\b\b\b\b done" << std::endl; + +    return 0; +} + + +/*! + * Program the FX3 with a firmware file (Intel HEX format) + * + * \param dev_handle the libusb-1.0 device handle + * \param filestring the filename of the firmware file + * \return 0 for success, otherwise error code + */ +boost::int32_t fx3_load_firmware(libusb_device_handle *dev_handle, \ +        std::string filestring) { + +    if (filestring.empty()) +    { +        std::cerr << "fx3_load_firmware: input file is empty." << std::endl; +        exit(-1); +    } + +    const char *filename = filestring.c_str(); + +    /* Fields used in each USB control transfer. */ +    boost::uint16_t len = 0; +    boost::uint16_t type = 0; +    boost::uint16_t lower_address_bits = 0x0000; +    unsigned char data[512]; + +    /* Can be set by the Intel HEX record 0x04, used for all 0x00 records +        * thereafter. Note this field takes the place of the 'index' parameter in +        * libusb calls, and is necessary for FX3's 32-bit addressing. */ +    boost::uint16_t upper_address_bits = 0x0000; + +    std::ifstream file; +    file.open(filename, std::ifstream::in); + +    if(!file.good()) { +        std::cerr << "fx3_load_firmware: cannot open firmware input file" +            << std::endl; +        exit(-1); +    } + +    std::cout << "Loading firmware image: " \ +        << filestring << "..." << std::flush; + +    while (!file.eof()) { +        boost::int32_t ret = 0; +        std::string record; +        file >> record; + +        /* Check for valid Intel HEX record. */ +        if (!checksum(&record) || !parse_record(&record, len, \ +                    lower_address_bits, type, data)) { +            std::cerr << "fx3_load_firmware: bad intel hex record checksum" +                    << std::endl; +        } + +        /* Type 0x00: Data. */ +        if (type == 0x00) { +            ret = fx3_control_write(dev_handle, FX3_FIRMWARE_LOAD, \ +                    lower_address_bits, upper_address_bits, data, len); + +            if (ret < 0) { +                std::cerr << "usrp_load_firmware: usrp_control_write failed" +                    << std::endl; +            } +        } + +        /* Type 0x01: EOF. */ +        else if (type == 0x01) { +            if (lower_address_bits != 0x0000 || len != 0 ) { +                std::cerr << "fx3_load_firmware: For EOF record, address must be 0, length must be 0." << std::endl; +            } + +            /* Successful termination! */ +            file.close(); + +            /* Let the system settle. */ +            boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); +            return 0; +        } + +        /* Type 0x04: Extended Linear Address Record. */ +        else if (type == 0x04) { +            if (lower_address_bits != 0x0000 || len != 2 ) { +                std::cerr << "fx3_load_firmware: For ELA record, address must be 0, length must be 2." << std::endl; +            } + +            upper_address_bits = ((boost::uint16_t)((data[0] & 0x00FF) << 8))\ +                                    + ((boost::uint16_t)(data[1] & 0x00FF)); +        } + +        /* Type 0x05: Start Linear Address Record. */ +        else if (type == 0x05) { +            if (lower_address_bits != 0x0000 || len != 4 ) { +                std::cerr << "fx3_load_firmware: For SLA record, address must be 0, length must be 4." << std::endl; +            } + +            /* The firmware load is complete.  We now need to tell the CPU +                * to jump to an execution address start point, now contained within +                * the data field.  Parse these address bits out, and then push the +                * instruction. */ +            upper_address_bits = ((boost::uint16_t)((data[0] & 0x00FF) << 8))\ +                                    + ((boost::uint16_t)(data[1] & 0x00FF)); +            lower_address_bits = ((boost::uint16_t)((data[2] & 0x00FF) << 8))\ +                                    + ((boost::uint16_t)(data[3] & 0x00FF)); + +            fx3_control_write(dev_handle, FX3_FIRMWARE_LOAD, lower_address_bits, \ +                    upper_address_bits, 0, 0); + +            std::cout << " done" << std::endl; +        } + +        /* If we receive an unknown record type, error out. */ +        else { +            std::cerr << "fx3_load_firmware: unsupported record type." << std::endl; +        } +    } + +    /* There was no valid EOF. */ +    std::cerr << "fx3_load_firmware: No EOF record found." << std::cout; +    return ~0; +} + + +boost::int32_t main(boost::int32_t argc, char *argv[]) { +    boost::uint16_t vid, pid; +    std::string pid_str, vid_str, fw_file, fpga_file; + +    po::options_description desc("Allowed options"); +    desc.add_options() +        ("help,h", "help message") +        ("vid,v", po::value<std::string>(&vid_str)->default_value("0x2500"), +            "Specify VID of device to use.") +        ("pid,p", po::value<std::string>(&pid_str)->default_value("0x0020"), +            "Specify PID of device to use.") +        ("speed,S", "Read back the USB mode currently in use.") +        ("reset-device,D", "Reset the B2xx Device.") +        ("reset-fpga,F", "Reset the FPGA (does not require re-programming.") +        ("reset-usb,U", "Reset the USB subsystem on your host computer.") +        ("init-device,I", "Initialize a B2xx device.") +        ("load-fw,W", po::value<std::string>(&fw_file)->default_value(""), +            "Load a firmware (hex) file into the FX3.") +        ("load-fpga,L", po::value<std::string>(&fpga_file)->default_value(""), +            "Load a FPGA (bin) file into the FPGA.") +    ; + +    po::variables_map vm; +    po::store(po::parse_command_line(argc, argv, desc), vm); +    po::notify(vm); + +    if (vm.count("help")){ +        std::cout << boost::format("B2xx Utilitiy Program %s") % desc << std::endl; +        return ~0; +    } else if (vm.count("reset-usb")) { +        /* Okay, first, we need to discover what the path is to the ehci and +         * xhci device files. */ +        std::set<fs::path> path_list; +        path_list.insert("/sys/bus/pci/drivers/xhci-pci/"); +        path_list.insert("/sys/bus/pci/drivers/ehci-pci/"); +        path_list.insert("/sys/bus/pci/drivers/xhci_hcd/"); +        path_list.insert("/sys/bus/pci/drivers/ehci_hcd/"); + +        /* Check each of the possible paths above to find which ones this system +         * uses. */ +        for(std::set<fs::path>::iterator found = path_list.begin(); +                found != path_list.end(); ++found) { + +            if(fs::exists(*found)) { + +                fs::path devpath = *found; + +                std::set<fs::path> globbed; + +                /* Now, glob all of the files in the directory. */ +                fs::directory_iterator end_itr; +                for(fs::directory_iterator itr(devpath); itr != end_itr; ++itr) { +                    globbed.insert((*itr).path()); +                } + +                /* Check each file path string to see if it is a device file. */ +                for(std::set<fs::path>::iterator it = globbed.begin(); +                        it != globbed.end(); ++it) { + +                    std::string file = fs::path((*it).filename()).string(); + +                    if(file.compare(0, 5, "0000:") == 0) { +                        /* Un-bind the device. */ +                        std::fstream unbind((devpath.string() + "unbind").c_str(), +                                std::fstream::out); +                        unbind << file; +                        unbind.close(); + +                        /* Re-bind the device. */ +                        std::cout << "Re-binding: " << file << " in " +                            << devpath.string() << std::endl; +                        std::fstream bind((devpath.string() + "bind").c_str(), +                                std::fstream::out); +                        bind << file; +                        bind.close(); +                    } +                } +            } +        } + +        return 0; +    } + +    vid = atoh(vid_str); +    pid = atoh(pid_str); + +    /* Pointer to pointer of device, used to retrieve a list of devices. */ +    libusb_device **devs; +    libusb_device_handle *dev_handle; +    libusb_context *ctx = NULL; +    libusb_error error_code; + +    libusb_init(&ctx); +    libusb_set_debug(ctx, 3); +    libusb_get_device_list(ctx, &devs); + +    /* If we are initializing the device, the VID/PID will default to the +     * Cypress VID/PID for the initial FW load. */ +    if (vm.count("init-device")) { +        dev_handle = libusb_open_device_with_vid_pid(ctx, FX3_VID, +                FX3_DEFAULT_PID); +        if(dev_handle == NULL) { +            std::cerr << "Cannot open device with vid: " << vid << " and pid: " +                << pid << std::endl; +            return -1; +        } else { std::cout << "Uninitialized B2xx detected..." << std::flush; } +        libusb_free_device_list(devs, 1); + +        /* Find out if kernel driver is attached, and if so, detach it. */ +        if(libusb_kernel_driver_active(dev_handle, 0) == 1) { +            std::cout << " Competing Driver Identified... " << std::flush; + +            if(libusb_detach_kernel_driver(dev_handle, 0) == 0) { +                std::cout << " Competing Driver Destroyed!" << std::flush; +            } +        } +        libusb_claim_interface(dev_handle, 0); +        std::cout << " Control of B2xx granted..." << std::endl << std::endl; + +        /* Load the FW. */ +        error_code = (libusb_error) fx3_load_firmware(dev_handle, fw_file); +        if(error_code != 0) { +            std::cerr << std::flush << "Error loading firmware. Error code: " +                << error_code << std::endl; +            libusb_release_interface(dev_handle, 0); +            libusb_close(dev_handle); +            libusb_exit(ctx); +            return ~0; +        } + +        /* Let the device re-enumerate. */ +        libusb_release_interface(dev_handle, 0); +        libusb_close(dev_handle); +        dev_handle = libusb_open_device_with_vid_pid(ctx, FX3_VID, +                FX3_REENUM_PID); +        if(dev_handle == NULL) { +            std::cerr << "Cannot open device with vid: " << vid << " and pid: " +                << pid << std::endl; +            return -1; +        } else { +            std::cout << "Detected in-progress init of B2xx..." << std::flush; +        } +        //libusb_free_device_list(devs, 1); +        libusb_claim_interface(dev_handle, 0); +        std::cout << " Reenumeration complete, Device claimed..." +            << std::endl; + +        /* Now, initialize the device. */ +        byte_vector_t bytes(8); +        bytes[0] = 0x43; +        bytes[1] = 0x59; +        bytes[2] = 0x14; +        bytes[3] = 0xB2; +        bytes[4] = (B2XX_PID & 0xff); +        bytes[5] = (B2XX_PID >> 8); +        bytes[6] = (B2XX_VID & 0xff); +        bytes[7] = (B2XX_VID >> 8); +        write_eeprom(dev_handle, 0x0, 0x0, bytes); +        std::cout << "EEPROM initialized, resetting device..." +            << std::endl << std::endl; + +        /* Reset the device! */ +        boost::uint8_t data_buffer[1]; +        fx3_control_write(dev_handle, B2XX_VREQ_FX3_RESET, +                0x00, 0x00, data_buffer, 1, 5000); + +        std::cout << "Initialization Process Complete." +            << std::endl << std::endl; +        libusb_release_interface(dev_handle, 0); +        libusb_close(dev_handle); +        libusb_exit(ctx); +        return 0; +    } + +    dev_handle = libusb_open_device_with_vid_pid(ctx, vid, pid); +    if(dev_handle == NULL) { +        std::cerr << "Cannot open device with vid: " << vid << " and pid: " +            << pid << std::endl; +            return -1; +    } else { std::cout << "Reactor Core Online..." << std::flush; } +    libusb_free_device_list(devs, 1); + +    /* Find out if kernel driver is attached, and if so, detach it. */ +    if(libusb_kernel_driver_active(dev_handle, 0) == 1) { +        std::cout << " Competing Driver Identified... " << std::flush; + +        if(libusb_detach_kernel_driver(dev_handle, 0) == 0) { +            std::cout << " Competing Driver Destroyed!" << std::flush; +        } +    } + +    /* Claim interface 0 of device. */ +    error_code = (libusb_error) libusb_claim_interface(dev_handle, 0); +    std::cout << " All Systems Nominal..." << std::endl << std::endl; + +    boost::uint8_t data_buffer[16]; +    memset(data_buffer, 0x0, sizeof(data_buffer)); + +    if (vm.count("speed")){ +        error_code = fx3_control_read(dev_handle, B2XX_VREQ_GET_USB, +                0x00, 0x00, data_buffer, 1, 5000); + +        boost::uint8_t speed = boost::lexical_cast<boost::uint8_t>(data_buffer[0]); + +        std::cout << "Currently operating at USB " << (int) speed << std::endl; + +    } else if (vm.count("reset-device")) { +        error_code = fx3_control_write(dev_handle, B2XX_VREQ_FX3_RESET, +                0x00, 0x00, data_buffer, 1, 5000); + +    } else if (vm.count("reset-fpga")) { +        error_code = fx3_control_write(dev_handle, B2XX_VREQ_FPGA_RESET, +                0x00, 0x00, data_buffer, 1, 5000); + +    } else if (vm.count("load-fw")) { +        error_code = (libusb_error) fx3_load_firmware(dev_handle, fw_file); + +        if(error_code != 0) { +            std::cerr << std::flush << "Error loading firmware. Error code: " +                << error_code << std::endl; +            libusb_release_interface(dev_handle, 0); +            libusb_close(dev_handle); +            libusb_exit(ctx); +            return ~0; +        } + +        std::cout << "Firmware load complete, releasing USB interface..." +            << std::endl; + +    } else if (vm.count("load-fpga")) { +        error_code = (libusb_error) load_fpga(dev_handle, fpga_file); + +        if(error_code != 0) { +            std::cerr << std::flush << "Error loading FPGA. Error code: " +                << error_code << std::endl; +            libusb_release_interface(dev_handle, 0); +            libusb_close(dev_handle); +            libusb_exit(ctx); +            return ~0; +        } + +        std::cout << "FPGA load complete, releasing USB interface..." +            << std::endl; + +    } else { +        std::cout << boost::format("B2xx Utilitiy Program %s") % desc << std::endl; +        libusb_release_interface(dev_handle, 0); +        libusb_close(dev_handle); +        libusb_exit(ctx); +        return ~0; +    } + +    std::cout << std::endl << "Reactor Shutting Down..." << std::endl; + +    error_code = (libusb_error) libusb_release_interface(dev_handle, 0); +    libusb_close(dev_handle); +    libusb_exit(ctx); + +    return 0; +} + diff --git a/host/utils/fx2_init_eeprom.cpp b/host/utils/fx2_init_eeprom.cpp index c210ae575..701092a5d 100644 --- a/host/utils/fx2_init_eeprom.cpp +++ b/host/utils/fx2_init_eeprom.cpp @@ -41,12 +41,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      po::variables_map vm;      po::store(po::parse_command_line(argc, argv, desc), vm); -    po::notify(vm);  +    po::notify(vm);      //print the help message      if (vm.count("help")){          std::cout << boost::format("USRP EEPROM initialization %s") % desc << std::endl; -        return ~0; +        return EXIT_FAILURE;      }      //cant find a uninitialized usrp with this mystery module in the way... @@ -76,7 +76,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      if (found_addrs.size() == 0){          std::cerr << "No USRP devices found" << std::endl; -        return ~0; +        return EXIT_FAILURE;      }      for (size_t i = 0; i < found_addrs.size(); i++){ @@ -89,5 +89,5 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      std::cout << "Power-cycle the usrp for the changes to take effect." << std::endl; -    return 0; +    return EXIT_SUCCESS;  } diff --git a/host/utils/query_gpsdo_sensors.cpp b/host/utils/query_gpsdo_sensors.cpp index 8e34bb3d5..91088112c 100644 --- a/host/utils/query_gpsdo_sensors.cpp +++ b/host/utils/query_gpsdo_sensors.cpp @@ -27,6 +27,7 @@  #include <boost/thread.hpp>  #include <string>  #include <cmath> +#include <ctime>  #include <cstdlib>  namespace po = boost::program_options; @@ -102,6 +103,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){    //Check PPS and compare UHD device time to GPS time    boost::this_thread::sleep(boost::posix_time::seconds(1));    uhd::sensor_value_t gps_time = usrp->get_mboard_sensor("gps_time"); +  const time_t pc_clock_time = time(NULL);    const uhd::time_spec_t last_pps_time = usrp->get_time_last_pps();    if (last_pps_time.to_ticks(1.0) == gps_time.to_int()) {      std::cout << boost::format("GPS and UHD Device time are aligned.\n"); @@ -114,6 +116,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){    uhd::sensor_value_t rmc_string = usrp->get_mboard_sensor("gps_gprmc");    std::cout << boost::format("%s\n%s\n%s\n") % gga_string.to_pp_string() % rmc_string.to_pp_string() % gps_time.to_pp_string();    std::cout << boost::format("UHD Device time: %.0f seconds\n") % (last_pps_time.get_real_secs()); +  std::cout << boost::format("PC Clock time: %.0f seconds\n") % pc_clock_time;    //finished    std::cout << boost::format("\nDone!\n\n"); diff --git a/host/utils/uhd-usrp.rules b/host/utils/uhd-usrp.rules index 56d9a8c43..2f5198d64 100644 --- a/host/utils/uhd-usrp.rules +++ b/host/utils/uhd-usrp.rules @@ -15,5 +15,11 @@  # along with this program.  If not, see <http://www.gnu.org/licenses/>.  # +#USRP1  SUBSYSTEMS=="usb", ATTRS{idVendor}=="fffe", ATTRS{idProduct}=="0002", MODE:="0666" + +#B100  SUBSYSTEMS=="usb", ATTRS{idVendor}=="2500", ATTRS{idProduct}=="0002", MODE:="0666" + +#B200 +SUBSYSTEMS=="usb", ATTRS{idVendor}=="2500", ATTRS{idProduct}=="0020", MODE:="0666" diff --git a/host/utils/uhd_cal_rx_iq_balance.cpp b/host/utils/uhd_cal_rx_iq_balance.cpp index 68d0443da..5fb494114 100644 --- a/host/utils/uhd_cal_rx_iq_balance.cpp +++ b/host/utils/uhd_cal_rx_iq_balance.cpp @@ -29,6 +29,7 @@  #include <complex>  #include <cmath>  #include <ctime> +#include <cstdlib>  namespace po = boost::program_options; @@ -120,7 +121,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){          std::cout <<              "This application measures leakage between RX and TX on an XCVR daughterboard to self-calibrate.\n"              << std::endl; -        return ~0; +        return EXIT_FAILURE;      }      //create a usrp device @@ -239,5 +240,5 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      store_results(usrp, results, "RX", "rx", "iq"); -    return 0; +    return EXIT_SUCCESS;  } diff --git a/host/utils/uhd_cal_tx_dc_offset.cpp b/host/utils/uhd_cal_tx_dc_offset.cpp index 8f69b3ce1..c9cf757f4 100644 --- a/host/utils/uhd_cal_tx_dc_offset.cpp +++ b/host/utils/uhd_cal_tx_dc_offset.cpp @@ -123,7 +123,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){          std::cout <<              "This application measures leakage between RX and TX on an XCVR daughterboard to self-calibrate.\n"              << std::endl; -        return ~0; +        return EXIT_FAILURE;      }      //create a usrp device @@ -237,5 +237,5 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      store_results(usrp, results, "TX", "tx", "dc"); -    return 0; +    return EXIT_SUCCESS;  } diff --git a/host/utils/uhd_cal_tx_iq_balance.cpp b/host/utils/uhd_cal_tx_iq_balance.cpp index 5478b07e3..20d018edf 100644 --- a/host/utils/uhd_cal_tx_iq_balance.cpp +++ b/host/utils/uhd_cal_tx_iq_balance.cpp @@ -28,6 +28,7 @@  #include <iostream>  #include <complex>  #include <ctime> +#include <cstdlib>  namespace po = boost::program_options; @@ -123,7 +124,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){          std::cout <<              "This application measures leakage between RX and TX on an XCVR daughterboard to self-calibrate.\n"              << std::endl; -        return ~0; +        return EXIT_FAILURE;      }      //create a usrp device @@ -242,5 +243,5 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      store_results(usrp, results, "TX", "tx", "iq"); -    return 0; +    return EXIT_SUCCESS;  } diff --git a/host/utils/uhd_find_devices.cpp b/host/utils/uhd_find_devices.cpp index b778eeb68..c258c580e 100644 --- a/host/utils/uhd_find_devices.cpp +++ b/host/utils/uhd_find_devices.cpp @@ -20,6 +20,7 @@  #include <boost/program_options.hpp>  #include <boost/format.hpp>  #include <iostream> +#include <cstdlib>  namespace po = boost::program_options; @@ -37,7 +38,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //print the help message      if (vm.count("help")){          std::cout << boost::format("UHD Find Devices %s") % desc << std::endl; -        return ~0; +        return EXIT_FAILURE;      }      //discover the usrps and print the results @@ -45,7 +46,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      if (device_addrs.size() == 0){          std::cerr << "No UHD Devices Found" << std::endl; -        return ~0; +        return EXIT_FAILURE;      }      for (size_t i = 0; i < device_addrs.size(); i++){ @@ -56,5 +57,5 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){          //uhd::device::make(device_addrs[i]); //test make      } -    return 0; +    return EXIT_SUCCESS;  } diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp index 5b3702fb4..98ed84850 100644 --- a/host/utils/uhd_usrp_probe.cpp +++ b/host/utils/uhd_usrp_probe.cpp @@ -30,6 +30,7 @@  #include <iostream>  #include <sstream>  #include <vector> +#include <cstdlib>  namespace po = boost::program_options;  using namespace uhd; @@ -114,13 +115,16 @@ static std::string get_dboard_pp_string(const std::string &type, property_tree::      ss << boost::format("%s Dboard: %s") % type % path.leaf() << std::endl;      //ss << std::endl;      const std::string prefix = (type == "RX")? "rx" : "tx"; -    usrp::dboard_eeprom_t db_eeprom = tree->access<usrp::dboard_eeprom_t>(path / (prefix + "_eeprom")).get(); -    if (db_eeprom.id != usrp::dboard_id_t::none()) ss << boost::format("ID: %s") % db_eeprom.id.to_pp_string() << std::endl; -    if (not db_eeprom.serial.empty()) ss << boost::format("Serial: %s") % db_eeprom.serial << std::endl; -    if (type == "TX"){ -        usrp::dboard_eeprom_t gdb_eeprom = tree->access<usrp::dboard_eeprom_t>(path / "gdb_eeprom").get(); -        if (gdb_eeprom.id != usrp::dboard_id_t::none()) ss << boost::format("ID: %s") % gdb_eeprom.id.to_pp_string() << std::endl; -        if (not gdb_eeprom.serial.empty()) ss << boost::format("Serial: %s") % gdb_eeprom.serial << std::endl; +    if (tree->exists(path / (prefix + "_eeprom"))) +    { +        usrp::dboard_eeprom_t db_eeprom = tree->access<usrp::dboard_eeprom_t>(path / (prefix + "_eeprom")).get(); +        if (db_eeprom.id != usrp::dboard_id_t::none()) ss << boost::format("ID: %s") % db_eeprom.id.to_pp_string() << std::endl; +        if (not db_eeprom.serial.empty()) ss << boost::format("Serial: %s") % db_eeprom.serial << std::endl; +        if (type == "TX"){ +            usrp::dboard_eeprom_t gdb_eeprom = tree->access<usrp::dboard_eeprom_t>(path / "gdb_eeprom").get(); +            if (gdb_eeprom.id != usrp::dboard_id_t::none()) ss << boost::format("ID: %s") % gdb_eeprom.id.to_pp_string() << std::endl; +            if (not gdb_eeprom.serial.empty()) ss << boost::format("Serial: %s") % gdb_eeprom.serial << std::endl; +        }      }      BOOST_FOREACH(const std::string &name, tree->list(path / (prefix + "_frontends"))){          ss << make_border(get_frontend_pp_string(type, tree, path / (prefix + "_frontends") / name)); @@ -197,12 +201,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //print the help message      if (vm.count("help")){          std::cout << boost::format("UHD USRP Probe %s") % desc << std::endl; -        return ~0; +        return EXIT_FAILURE;      }      if (vm.count("version")){          std::cout << uhd::get_version_string() << std::endl; -        return 0; +        return EXIT_SUCCESS;      }      device::sptr dev = device::make(vm["args"].as<std::string>()); @@ -210,11 +214,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      if (vm.count("string")){          std::cout << tree->access<std::string>(vm["string"].as<std::string>()).get() << std::endl; -        return 0; +        return EXIT_SUCCESS;      }      if (vm.count("tree") != 0) print_tree("/", tree);      else std::cout << make_border(get_device_pp_string(tree)) << std::endl; -    return 0; +    return EXIT_SUCCESS;  } diff --git a/host/utils/usrp_burn_db_eeprom.cpp b/host/utils/usrp_burn_db_eeprom.cpp index b6b2dc4d6..3ca953115 100644 --- a/host/utils/usrp_burn_db_eeprom.cpp +++ b/host/utils/usrp_burn_db_eeprom.cpp @@ -58,7 +58,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){              "Omit the ID argument to perform readback,\n"              "Or specify a new ID to burn into the EEPROM.\n"          ) << std::endl; -        return ~0; +        return EXIT_FAILURE;      }      //make the device and extract the dboard w/ property @@ -96,5 +96,5 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      std::cout << boost::format("  Current revision: \"%s\"") % db_eeprom.revision << std::endl;      std::cout << "  Done" << std::endl << std::endl; -    return 0; +    return EXIT_SUCCESS;  } diff --git a/host/utils/usrp_burn_mb_eeprom.cpp b/host/utils/usrp_burn_mb_eeprom.cpp index ca9a6c8ba..1b13fb615 100644 --- a/host/utils/usrp_burn_mb_eeprom.cpp +++ b/host/utils/usrp_burn_mb_eeprom.cpp @@ -47,7 +47,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){              "Omit the value argument to perform a readback,\n"              "Or specify a new value to burn into the EEPROM.\n"          ) << std::endl; -        return ~0; +        return EXIT_FAILURE;      }      std::cout << "Creating USRP device from address: " + args << std::endl; @@ -60,7 +60,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){          uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get();          if (not mb_eeprom.has_key(key)){              std::cerr << boost::format("Cannot find value for EEPROM[%s]") % key << std::endl; -            return ~0; +            return EXIT_FAILURE;          }          std::cout << boost::format("    EEPROM [\"%s\"] is \"%s\"") % key % mb_eeprom[key] << std::endl;          std::cout << std::endl; @@ -74,5 +74,5 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      }      std::cout << "Done" << std::endl; -    return 0; +    return EXIT_SUCCESS;  } diff --git a/host/utils/usrp_cal_utils.hpp b/host/utils/usrp_cal_utils.hpp index bda6fc31b..bab6ddd91 100644 --- a/host/utils/usrp_cal_utils.hpp +++ b/host/utils/usrp_cal_utils.hpp @@ -77,6 +77,9 @@ static inline void set_optimum_defaults(uhd::usrp::multi_usrp::sptr usrp){      else if (tx_name.find("SBX") != std::string::npos){          usrp->set_tx_gain(0);      } +    else if (tx_name.find("CBX") != std::string::npos){ +        usrp->set_tx_gain(0); +    }      else if (tx_name.find("RFX") != std::string::npos){          usrp->set_tx_gain(0);      } @@ -92,6 +95,9 @@ static inline void set_optimum_defaults(uhd::usrp::multi_usrp::sptr usrp){      else if (rx_name.find("SBX") != std::string::npos){          usrp->set_rx_gain(25);      } +    else if (rx_name.find("CBX") != std::string::npos){ +        usrp->set_rx_gain(25); +    }      else if (rx_name.find("RFX") != std::string::npos){          usrp->set_rx_gain(25);      } diff --git a/host/utils/usrp_n2xx_net_burner_gui.py b/host/utils/usrp_n2xx_net_burner_gui.py index 75d246c25..bad065f08 100755 --- a/host/utils/usrp_n2xx_net_burner_gui.py +++ b/host/utils/usrp_n2xx_net_burner_gui.py @@ -203,20 +203,30 @@ class USRPN2XXNetBurnerApp(tkinter.Frame):              #make a new burner object and attempt the burner operation              burner = usrp_n2xx_net_burner.burner_socket(addr=addr,quiet=False) -            for (image_type, fw_img, fpga_img) in (('FPGA', '', fpga), ('Firmware', fw, '')): -                #setup callbacks that update the gui -                def status_cb(status): -                    self._pbar.set(0.0) #status change, reset the progress -                    self._status.set("%s %s "%(status.title(), image_type)) -                    self.update() -                def progress_cb(progress): -                    self._pbar.set(progress) -                    self.update() -                burner.set_callbacks(progress_cb=progress_cb, status_cb=status_cb) -                burner.burn_fw(fw=fw_img, fpga=fpga_img, reset=False, safe=False, check_rev=not options.dont_check_rev) - -            if tkinter.messagebox.askyesno("Burn was successful!", "Reset the device?"): -                burner.reset_usrp() +            #setup callbacks that update the gui +            def status_cb(status): +                self._pbar.set(0.0) #status change, reset the progress +                self._status.set("%s %s "%(status.title(), image_type)) +                self.update() +            def progress_cb(progress): +                self._pbar.set(progress) +                self.update() + +            if options.overwrite_safe: +                if tkinter.messagebox.askyesno("Overwrite safe images?", "Overwrite safe images! This is ALMOST ALWAYS a terrible idea."): +                    for (image_type, fw_img, fpga_img) in (('FPGA', '', fpga), ('Firmware', fw, '')): +                        burner.set_callbacks(progress_cb=progress_cb, status_cb=status_cb) +                        burner.burn_fw(fw=fw_img, fpga=fpga_img, reset=False, safe=True, check_rev=not options.dont_check_rev) + +                    if tkinter.messagebox.askyesno("Burn was successful!", "Reset the device?"): +                        burner.reset_usrp() +            else: +                for (image_type, fw_img, fpga_img) in (('FPGA', '', fpga), ('Firmware', fw, '')): +                    burner.set_callbacks(progress_cb=progress_cb, status_cb=status_cb) +                    burner.burn_fw(fw=fw_img, fpga=fpga_img, reset=False, safe=False, check_rev=not options.dont_check_rev) + +                if tkinter.messagebox.askyesno("Burn was successful!", "Reset the device?"): +                    burner.reset_usrp()          except Exception as e:              tkinter.messagebox.showerror('Verbose:', 'Error: %s'%str(e)) | 
