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 | 49 | ||||
-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, 854 insertions, 56 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..ce0879c8e 100644 --- a/host/utils/usrp_burn_mb_eeprom.cpp +++ b/host/utils/usrp_burn_mb_eeprom.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// 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 @@ -19,9 +19,11 @@ #include <uhd/device.hpp> #include <uhd/property_tree.hpp> #include <uhd/usrp/mboard_eeprom.hpp> +#include <boost/algorithm/string.hpp> #include <boost/program_options.hpp> #include <boost/format.hpp> #include <iostream> +#include <vector> namespace po = boost::program_options; @@ -32,8 +34,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ desc.add_options() ("help", "help message") ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]") - ("key", po::value<std::string>(&key), "the indentifier for a value in EEPROM") - ("val", po::value<std::string>(&val), "the new value to set, omit for readback") + ("key", po::value<std::string>(&key), "identifiers for new values in EEPROM, separate multiple by \",\"") + ("val", po::value<std::string>(&val), "the new values to set, omit for readback, separate multiple by \",\"") ; po::variables_map vm; @@ -47,7 +49,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; @@ -55,24 +57,39 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::property_tree::sptr tree = dev->get_tree(); std::cout << std::endl; - if (true /*always readback*/){ - std::cout << "Fetching current settings from EEPROM..." << std::endl; - 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; + //remove whitespace, split arguments and values + boost::algorithm::erase_all(key, " "); + boost::algorithm::erase_all(val, " "); + + std::vector<std::string> keys_vec, vals_vec; + boost::split(keys_vec, key, boost::is_any_of("\"',")); + boost::split(vals_vec, val, boost::is_any_of("\"',")); + + if((keys_vec.size() != vals_vec.size()) and val != "") { + //If zero values are given, then user just wants values read to them + throw std::runtime_error("Number of keys must match number of values!"); + } + + std::cout << "Fetching current settings from EEPROM..." << std::endl; + uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get(); + for(size_t i = 0; i < keys_vec.size(); i++){ + if (not mb_eeprom.has_key(keys_vec[i])){ + std::cerr << boost::format("Cannot find value for EEPROM[%s]") % keys_vec[i] << std::endl; + return EXIT_FAILURE; } - std::cout << boost::format(" EEPROM [\"%s\"] is \"%s\"") % key % mb_eeprom[key] << std::endl; - std::cout << std::endl; + std::cout << boost::format(" EEPROM [\"%s\"] is \"%s\"") % keys_vec[i] % mb_eeprom[keys_vec[i]] << std::endl; } + std::cout << std::endl; if (vm.count("val")){ - uhd::usrp::mboard_eeprom_t mb_eeprom; mb_eeprom[key] = val; - std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % key % val << std::endl; - tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").set(mb_eeprom); + for(size_t i = 0; i < vals_vec.size(); i++){ + uhd::usrp::mboard_eeprom_t mb_eeprom; mb_eeprom[keys_vec[i]] = vals_vec[i]; + std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % keys_vec[i] % vals_vec[i] << std::endl; + tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").set(mb_eeprom); + } std::cout << "Power-cycle the USRP device for the changes to take effect." << std::endl; std::cout << std::endl; } 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)) |