diff options
Diffstat (limited to 'host/utils')
-rw-r--r-- | host/utils/CMakeLists.txt | 4 | ||||
-rw-r--r-- | host/utils/b2xx_fx3_utils.cpp | 86 | ||||
-rwxr-xr-x | host/utils/b2xx_side_channel.py | 818 | ||||
-rw-r--r-- | host/utils/nirio_programmer.cpp | 275 | ||||
-rw-r--r-- | host/utils/octoclock_firmware_burner.cpp | 81 | ||||
-rw-r--r-- | host/utils/uhd_image_loader.cpp | 122 | ||||
-rw-r--r-- | host/utils/uhd_images_downloader.py.in | 161 | ||||
-rwxr-xr-x | host/utils/usrp_n2xx_net_burner.py | 51 | ||||
-rw-r--r-- | host/utils/usrp_n2xx_simple_net_burner.cpp | 57 | ||||
-rw-r--r-- | host/utils/usrp_x3xx_fpga_burner.cpp | 71 |
10 files changed, 1318 insertions, 408 deletions
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index e24b417c1..530bcf087 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2014 Ettus Research LLC +# Copyright 2010-2015 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 @@ -21,11 +21,11 @@ SET(util_runtime_sources uhd_find_devices.cpp uhd_usrp_probe.cpp + uhd_image_loader.cpp uhd_cal_rx_iq_balance.cpp uhd_cal_tx_dc_offset.cpp uhd_cal_tx_iq_balance.cpp usrp_n2xx_simple_net_burner.cpp - nirio_programmer.cpp ) SET(x3xx_burner_sources diff --git a/host/utils/b2xx_fx3_utils.cpp b/host/utils/b2xx_fx3_utils.cpp index 572daef70..bc14932f1 100644 --- a/host/utils/b2xx_fx3_utils.cpp +++ b/host/utils/b2xx_fx3_utils.cpp @@ -51,20 +51,26 @@ struct vid_pid_t { const static vid_pid_t known_vid_pids[] = { {FX3_VID, FX3_DEFAULT_PID}, {FX3_VID, FX3_REENUM_PID}, - {B200_VENDOR_ID, B200_PRODUCT_ID} + {B200_VENDOR_ID, B200_PRODUCT_ID}, + {B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID}, + {B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID} }; const static std::vector<vid_pid_t> known_vid_pid_vector(known_vid_pids, known_vid_pids + (sizeof(known_vid_pids) / sizeof(known_vid_pids[0]))); -const static boost::uint8_t eeprom_init_values[] = { - 0x43, - 0x59, - 0x14, - 0xB2, - (B200_PRODUCT_ID & 0xff), - (B200_PRODUCT_ID >> 8), - (B200_VENDOR_ID & 0xff), - (B200_VENDOR_ID >> 8) - }; -const static uhd::byte_vector_t eeprom_init_value_vector(eeprom_init_values, eeprom_init_values + (sizeof(eeprom_init_values) / sizeof(eeprom_init_values[0]))); + +static const size_t EEPROM_INIT_VALUE_VECTOR_SIZE = 8; +static uhd::byte_vector_t construct_eeprom_init_value_vector(boost::uint16_t vid, boost::uint16_t pid) +{ + uhd::byte_vector_t init_values(EEPROM_INIT_VALUE_VECTOR_SIZE); + init_values.at(0) = 0x43; + init_values.at(1) = 0x59; + init_values.at(2) = 0x14; + init_values.at(3) = 0xB2; + init_values.at(4) = static_cast<boost::uint8_t>(pid & 0xff); + init_values.at(5) = static_cast<boost::uint8_t>(pid >> 8); + init_values.at(6) = static_cast<boost::uint8_t>(vid & 0xff); + init_values.at(7) = static_cast<boost::uint8_t>(vid >> 8); + return init_values; +} //!used with lexical cast to parse a hex string template <class T> struct to_hex{ @@ -153,15 +159,22 @@ uhd::transport::usb_device_handle::sptr open_device(const boost::uint16_t vid, c try { // try caller's VID/PID first - handles = uhd::transport::usb_device_handle::get_device_list(vp.vid,vp.pid); - if (user_supplied && handles.size() == 0) - std::cerr << (boost::format("Failed to open device with VID 0x%04x and PID 0x%04x - trying other known VID/PIDs") % vid % pid).str() << std::endl; - - // try known VID/PIDs next - for (size_t i = 0; handles.size() == 0 && i < known_vid_pid_vector.size(); i++) + std::vector<uhd::transport::usb_device_handle::vid_pid_pair_t> vid_pid_pair_list(1,uhd::transport::usb_device_handle::vid_pid_pair_t(vid,pid)); + handles = uhd::transport::usb_device_handle::get_device_list(vid_pid_pair_list); + if (handles.size() == 0) { - vp = known_vid_pid_vector[i]; - handles = uhd::transport::usb_device_handle::get_device_list(vp.vid,vp.pid); + if (user_supplied) + { + std::cerr << (boost::format("Failed to open device with VID 0x%04x and PID 0x%04x - trying other known VID/PIDs") % vid % pid).str() << std::endl; + } + + // try known VID/PIDs next + for (size_t i = 0; handles.size() == 0 && i < known_vid_pid_vector.size(); i++) + { + vp = known_vid_pid_vector[i]; + handles = uhd::transport::usb_device_handle::get_device_list(vp.vid, vp.pid); + } + } if (handles.size() > 0) @@ -221,7 +234,7 @@ int read_eeprom(b200_iface::sptr& b200, uhd::byte_vector_t& data) int write_eeprom(b200_iface::sptr& b200, const uhd::byte_vector_t& data) { try { - b200->write_eeprom(0x0, 0x0, data); + b200->write_eeprom(0x0, 0x0, data); } catch (std::exception &e) { std::cerr << "Exception while writing EEPROM: " << e.what() << std::endl; return -1; @@ -281,7 +294,7 @@ int erase_eeprom(b200_iface::sptr& b200) 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; + std::string pid_str, vid_str, fw_file, fpga_file, writevid_str, writepid_str; bool user_supplied_vid_pid = false; po::options_description visible("Allowed options"); @@ -295,7 +308,6 @@ boost::int32_t main(boost::int32_t argc, char *argv[]) { ("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), "Load a firmware (hex) file into the FX3.") ("load-fpga,L", po::value<std::string>(&fpga_file), @@ -305,9 +317,14 @@ boost::int32_t main(boost::int32_t argc, char *argv[]) { // Hidden options provided for testing - use at your own risk! po::options_description hidden("Hidden options"); hidden.add_options() - ("uninit-device,U", "Uninitialize a B2xx device.") + ("init-device,I", "Initialize a B2xx device.") + ("uninit-device", "Uninitialize a B2xx device.") ("read-eeprom,R", "Read first 8 bytes of EEPROM") - ("erase-eeprom,E", "Erase first 8 bytes of EEPROM"); + ("erase-eeprom,E", "Erase first 8 bytes of EEPROM") + ("write-vid", po::value<std::string>(&writevid_str), + "Write VID field of EEPROM") + ("write-pid", po::value<std::string>(&writepid_str), + "Write PID field of EEPROM"); po::options_description desc; desc.add(visible); @@ -486,9 +503,24 @@ boost::int32_t main(boost::int32_t argc, char *argv[]) { * Cypress VID/PID for the initial FW load, but we can initialize from any state. */ if (vm.count("init-device")) { + uint16_t writevid = B200_VENDOR_ID; + uint16_t writepid = B200_PRODUCT_ID; + /* Now, initialize the device. */ - if (write_and_verify_eeprom(b200, eeprom_init_value_vector)) - return -1; + // Added for testing purposes - not exposed + if (vm.count("write-vid") && vm.count("write-pid")) + { + try { + writevid = atoh(writevid_str); + writepid = atoh(writepid_str); + } catch (std::exception &e) { + std::cerr << "Exception while parsing write VID and PID: " << e.what() << std:: endl; + return ~0; + } + } + + std::cout << "Writing VID and PID to EEPROM..." << std::endl << std::endl; + if (write_and_verify_eeprom(b200, construct_eeprom_init_value_vector(writevid, writepid))) return -1; std::cout << "EEPROM initialized, resetting device..." << std::endl << std::endl; diff --git a/host/utils/b2xx_side_channel.py b/host/utils/b2xx_side_channel.py new file mode 100755 index 000000000..070f5684c --- /dev/null +++ b/host/utils/b2xx_side_channel.py @@ -0,0 +1,818 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2013-2015 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/>. +# +""" +Tool to read log buffers from the FX3. Use to debug USB connection issues. +Requires PyUSB 1.0. +""" + +import sys +import time +import struct +from optparse import OptionParser +import serial + +try: + import usb.core + import usb.util +except Exception as e: + print("Failed to import module 'usb'.") + print("Please make sure you have PyUSB installed and in your PYTHONPATH.") + print("PyUSB PyPI website: https://pypi.python.org/pypi/pyusb") + print("To install, download from the website or use 'pip install pyusb'") + exit(1) + +VRT_OUT = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_OUT +VRT_IN = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_IN + +VRQS = {} +B200_VREQ_GET_LOG = 0x23 +VRQS[B200_VREQ_GET_LOG] = 'B200_VREQ_GET_LOG' +B200_VREQ_GET_COUNTERS = 0x24 +VRQS[B200_VREQ_GET_COUNTERS] = 'B200_VREQ_GET_COUNTERS' +B200_VREQ_CLEAR_COUNTERS = 0x25 +VRQS[B200_VREQ_CLEAR_COUNTERS] = 'B200_VREQ_CLEAR_COUNTERS' +B200_VREQ_GET_USB_EVENT_LOG = 0x26 +VRQS[B200_VREQ_GET_USB_EVENT_LOG] = 'B200_VREQ_GET_USB_EVENT_LOG' +B200_VREQ_SET_CONFIG = 0x27 +VRQS[B200_VREQ_SET_CONFIG] = 'B200_VREQ_SET_CONFIG' +B200_VREQ_GET_CONFIG = 0x28 +VRQS[B200_VREQ_GET_CONFIG] = 'B200_VREQ_GET_CONFIG' +B200_VREQ_GET_USB_SPEED = 0x80 +VRQS[B200_VREQ_GET_USB_SPEED] ='B200_VREQ_GET_USB_SPEED' +B200_VREQ_WRITE_SB = 0x29 +VRQS[B200_VREQ_WRITE_SB] = 'B200_VREQ_WRITE_SB' +B200_VREQ_SET_SB_BAUD_DIV = 0x30 +VRQS[B200_VREQ_SET_SB_BAUD_DIV] = 'B200_VREQ_SET_SB_BAUD_DIV' +B200_VREQ_FLUSH_DATA_EPS = 0x31 +VRQS[B200_VREQ_FLUSH_DATA_EPS] = 'B200_VREQ_FLUSH_DATA_EPS' +B200_VREQ_AD9361_LOOPBACK = 0x92 +VRQS[B200_VREQ_AD9361_LOOPBACK] = 'B200_VREQ_AD9361_LOOPBACK' + +COUNTER_MAGIC = 0x10024001 +""" +typedef struct Counters { + int magic; + + DMA_COUNTERS dma_to_host; + DMA_COUNTERS dma_from_host; + + int log_overrun_count; + + int usb_error_update_count; + USB_ERROR_COUNTERS usb_error_counters; + + int usb_ep_underrun_count; + + int heap_size; +} COUNTERS, *PCOUNTERS; + +typedef struct USBErrorCounters { + int phy_error_count; + int link_error_count; + + int PHY_LOCK_EV; + int TRAINING_ERROR_EV; + int RX_ERROR_CRC32_EV; + int RX_ERROR_CRC16_EV; + int RX_ERROR_CRC5_EV; + int PHY_ERROR_DISPARITY_EV; + int PHY_ERROR_EB_UND_EV; + int PHY_ERROR_EB_OVR_EV; + int PHY_ERROR_DECODE_EV; +} USB_ERROR_COUNTERS, *PUSB_ERROR_COUNTERS; + +typedef struct DMACounters { + int XFER_CPLT; + int SEND_CPLT; + int RECV_CPLT; + int PROD_EVENT; + int CONS_EVENT; + int ABORTED; + int ERROR; + int PROD_SUSP; + int CONS_SUSP; + + int BUFFER_MARKER; + int BUFFER_EOP; + int BUFFER_ERROR; + int BUFFER_OCCUPIED; + + int last_count; + int last_size; + + int last_sid; + int bad_sid_count; + + int resume_count; +} DMA_COUNTERS, *PDMA_COUNTERS; +""" +DMA_COUNTERS = [ + 'XFER_CPLT', + 'SEND_CPLT', + 'RECV_CPLT', + 'PROD_EVENT', + 'CONS_EVENT', + 'ABORTED', + 'ERROR', + 'PROD_SUSP', + 'CONS_SUSP', + + 'BUFFER_MARKER', + 'BUFFER_EOP', + 'BUFFER_ERROR', + 'BUFFER_OCCUPIED', + + 'last_count', + 'last_size', + + 'last_sid', + 'bad_sid_count' +] + +USB_ERROR_COUNTERS = [ + 'phy_error_count', + 'link_error_count' +] + +USB_PHY_ERROR_REGISTERS = [ + 'PHY_LOCK_EV', + 'TRAINING_ERROR_EV', + 'RX_ERROR_CRC32_EV', + 'RX_ERROR_CRC16_EV', + 'RX_ERROR_CRC5_EV', + 'PHY_ERROR_DISPARITY_EV', + 'PHY_ERROR_EB_UND_EV', + 'PHY_ERROR_EB_OVR_EV', + 'PHY_ERROR_DECODE_EV' +] + +USB_ERROR_COUNTERS += USB_PHY_ERROR_REGISTERS + +PIB_COUNTERS = [ + 'socket_inactive' +] + +COUNTERS = [ + 'magic', + + ('dma_to_host', DMA_COUNTERS), + ('dma_from_host', DMA_COUNTERS), + + 'log_overrun_count', + + 'usb_error_update_count', + ('usb_error_counters', USB_ERROR_COUNTERS), + + 'usb_ep_underrun_count', + + 'heap_size', + + 'resume_count', + 'state_transition_count', + 'invalid_gpif_state', + ('thread_0', PIB_COUNTERS), + ('thread_1', PIB_COUNTERS), + ('thread_2', PIB_COUNTERS), + ('thread_3', PIB_COUNTERS), +] + +USB_EVENTS = {} +USB_EVENTS[0x01] = ('CYU3P_USB_LOG_VBUS_OFF' , 'Indicates VBus turned off.') +USB_EVENTS[0x02] = ('CYU3P_USB_LOG_VBUS_ON' , 'Indicates VBus turned on.') +USB_EVENTS[0x03] = ('CYU3P_USB_LOG_USB2_PHY_OFF' , 'Indicates that the 2.0 PHY has been turned off.') +USB_EVENTS[0x04] = ('CYU3P_USB_LOG_USB3_PHY_OFF' , 'Indicates that the 3.0 PHY has been turned off.') +USB_EVENTS[0x05] = ('CYU3P_USB_LOG_USB2_PHY_ON' , 'Indicates that the 2.0 PHY has been turned on.') +USB_EVENTS[0x06] = ('CYU3P_USB_LOG_USB3_PHY_ON' , 'Indicates that the 3.0 PHY has been turned on.') +USB_EVENTS[0x10] = ('CYU3P_USB_LOG_USBSS_DISCONNECT' , 'Indicates that the USB 3.0 link has been disabled.') +USB_EVENTS[0x11] = ('CYU3P_USB_LOG_USBSS_RESET' , 'Indicates that a USB 3.0 reset (warm/hot) has happened.') +USB_EVENTS[0x12] = ('CYU3P_USB_LOG_USBSS_CONNECT' , 'Indicates that USB 3.0 Rx Termination has been detected.') +USB_EVENTS[0x14] = ('CYU3P_USB_LOG_USBSS_CTRL' , 'Indicates that a USB 3.0 control request has been received.') +USB_EVENTS[0x15] = ('CYU3P_USB_LOG_USBSS_STATUS' , 'Indicates completion of status stage for a 3.0 control request.') +USB_EVENTS[0x16] = ('CYU3P_USB_LOG_USBSS_ACKSETUP' , 'Indicates that the CyU3PUsbAckSetup API has been called.') +USB_EVENTS[0x21] = ('CYU3P_USB_LOG_LGO_U1' , 'Indicates that a LGO_U1 command has been received.') +USB_EVENTS[0x22] = ('CYU3P_USB_LOG_LGO_U2' , 'Indicates that a LGO_U2 command has been received.') +USB_EVENTS[0x23] = ('CYU3P_USB_LOG_LGO_U3' , 'Indicates that a LGO_U3 command has been received.') +USB_EVENTS[0x40] = ('CYU3P_USB_LOG_USB2_SUSP' , 'Indicates that a USB 2.0 suspend condition has been detected.') +USB_EVENTS[0x41] = ('CYU3P_USB_LOG_USB2_RESET' , 'Indicates that a USB 2.0 bus reset has been detected.') +USB_EVENTS[0x42] = ('CYU3P_USB_LOG_USB2_HSGRANT' , 'Indicates that the USB High-Speed handshake has been completed.') +USB_EVENTS[0x44] = ('CYU3P_USB_LOG_USB2_CTRL' , 'Indicates that a FS/HS control request has been received.') +USB_EVENTS[0x45] = ('CYU3P_USB_LOG_USB2_STATUS' , 'Indicates completion of status stage for a FS/HS control transfer.') +USB_EVENTS[0x50] = ('CYU3P_USB_LOG_USB_FALLBACK' , 'Indicates that the USB connection is dropping from 3.0 to 2.0') +USB_EVENTS[0x51] = ('CYU3P_USB_LOG_USBSS_ENABLE' , 'Indicates that a USB 3.0 connection is being attempted again.') +USB_EVENTS[0x52] = ('CYU3P_USB_LOG_USBSS_LNKERR' , 'The number of link errors has crossed the threshold.') +USB_EVENTS[0x80] = ('CYU3P_USB_LOG_LTSSM_CHG' , 'Base of values that indicate a USB 3.0 LTSSM state change.') + +LTSSM_STATES = {} +LTSSM_STATES[0x00] = ['00000', "SS.Disabled"] +LTSSM_STATES[0x01] = ['00001', "Rx.Detect.Reset"] +LTSSM_STATES[0x02] = ['00010', "Rx.Detect.Active"] +LTSSM_STATES[0x03] = ['00011', "Rx.Detect.Quiet"] +LTSSM_STATES[0x04] = ['00100', "SS.Inactive.Quiet"] +LTSSM_STATES[0x05] = ['00101', "SS.Inactive.Disconnect.Detect"] +LTSSM_STATES[0x06] = ['00110', "Hot Reset.Active"] +LTSSM_STATES[0x07] = ['00111', "Hot Reset.Exit"] +LTSSM_STATES[0x08] = ['01000', "Polling.LFPS"] +LTSSM_STATES[0x09] = ['01001', "Polling.RxEQ"] +LTSSM_STATES[0x0a] = ['01010', "Polling.Active"] +LTSSM_STATES[0x0b] = ['01011', "Polling.Configuration"] +LTSSM_STATES[0x0c] = ['01100', "Polling.Idle"] +LTSSM_STATES[0x0d] = ['01101', "(none)"] +#LTSSM_STATES[0x0X] = ['0111X', "(none)"] +LTSSM_STATES[0x0e] = ['0111X', "(none)"] +LTSSM_STATES[0x0f] = ['0111X', "(none)"] +LTSSM_STATES[0x10] = ['10000', "U0"] +LTSSM_STATES[0x11] = ['10001', "U1"] +LTSSM_STATES[0x12] = ['10010', "U2"] +LTSSM_STATES[0x13] = ['10011', "U3"] +LTSSM_STATES[0x14] = ['10100', "Loopback.Active"] +LTSSM_STATES[0x15] = ['10101', "Loopback.Exit"] +LTSSM_STATES[0x16] = ['10110', "(none)"] +LTSSM_STATES[0x17] = ['10111', "Compliance"] +LTSSM_STATES[0x18] = ['11000', "Recovery.Active"] +LTSSM_STATES[0x19] = ['11001', "Recovery.Configuration"] +LTSSM_STATES[0x1a] = ['11010', "Recovery.Idle"] +LTSSM_STATES[0x1b] = ['11011', "(none)"] +#LTSSM_STATES[0x1X] = ['111XX', "(none)"] +LTSSM_STATES[0x1c] = ['111XX', "(none)"] +LTSSM_STATES[0x1d] = ['111XX', "(none)"] +LTSSM_STATES[0x1c] = ['111XX', "(none)"] +LTSSM_STATES[0x1f] = ['111XX', "(none)"] +LTSSM_STATES[0x2c] = ['101100', "Cypress/Intel workaround"] + +CF_NONE = 0 +CF_TX_SWING = 1 << 0 +CF_TX_DEEMPHASIS = 1 << 1 +CF_DISABLE_USB2 = 1 << 2 +CF_ENABLE_AS_SUPERSPEED = 1 << 3 +CF_PPORT_DRIVE_STRENGTH = 1 << 4 +CF_DMA_BUFFER_SIZE = 1 << 5 +CF_DMA_BUFFER_COUNT = 1 << 6 +CF_MANUAL_DMA = 1 << 7 +CF_SB_BAUD_DIV = 1 << 8 + +CF_RE_ENUM = 1 << 31 + +""" +typedef struct Config { + int tx_swing; // [90] [65] 45 + int tx_deemphasis; // 0x11 + int disable_usb2; // 0 + int enable_as_superspeed; // 1 + int pport_drive_strength; // CY_U3P_DS_THREE_QUARTER_STRENGTH + int dma_buffer_size; // [USB3] (max) + int dma_buffer_count; // [USB3] 1 + int manual_dma; // 0 + int sb_baud_div; // 434*2 +} CONFIG, *PCONFIG; + +typedef struct ConfigMod { + int flags; + CONFIG config; +} CONFIG_MOD, *PCONFIG_MOD; +""" + +class Config(): + def __init__(self, + tx_swing=None, tx_deemphasis=None, disable_usb2=None, enable_as_superspeed=None, + pport_drive_strength=None, + dma_buffer_size=None, dma_buffer_count=None, manual_dma=None, + sb_baud_div=None, + raw=None): + self.tx_swing = tx_swing + self.tx_deemphasis = tx_deemphasis + self.disable_usb2 = disable_usb2 + self.enable_as_superspeed = enable_as_superspeed + self.pport_drive_strength = pport_drive_strength + self.dma_buffer_size = dma_buffer_size + self.dma_buffer_count = dma_buffer_count + self.manual_dma = manual_dma + self.sb_baud_div = sb_baud_div + self._count = 9 + + if raw: + (self.tx_swing, + self.tx_deemphasis, + self.disable_usb2, + self.enable_as_superspeed, + self.pport_drive_strength, + self.dma_buffer_size, + self.dma_buffer_count, + self.manual_dma, + self.sb_baud_div) = struct.unpack("i"*self._count, raw) + def pack(self): + return struct.pack("i"*self._count, + self.tx_swing, + self.tx_deemphasis, + self.disable_usb2, + self.enable_as_superspeed, + self.pport_drive_strength, + self.dma_buffer_size, + self.dma_buffer_count, + self.manual_dma, + self.sb_baud_div) + def __str__(self): + return self.to_string() + def to_string(self, flags=-1): + s = "" + if flags & CF_TX_SWING: + s += "tx_swing = %s\n" % (self.tx_swing) + if flags & CF_TX_DEEMPHASIS: + s += "tx_deemphasis = %s\n" % (self.tx_deemphasis) + if flags & CF_DISABLE_USB2: + s += "disable_usb2 = %s\n" % (self.disable_usb2) + if flags & CF_ENABLE_AS_SUPERSPEED: + s += "enable_as_superspeed = %s\n" % (self.enable_as_superspeed) + if flags & CF_PPORT_DRIVE_STRENGTH: + s += "pport_drive_strength = %s\n" % (self.pport_drive_strength) + if flags & CF_DMA_BUFFER_SIZE: + s += "dma_buffer_size = %s\n" % (self.dma_buffer_size) + if flags & CF_DMA_BUFFER_COUNT: + s += "dma_buffer_count = %s\n" % (self.dma_buffer_count) + if flags & CF_MANUAL_DMA: + s += "manual_dma = %s\n" % (self.manual_dma) + if flags & CF_SB_BAUD_DIV: + s += "sb_baud_div = %s\n" % (self.sb_baud_div) + return s + +def _parse_usb_event_log(data): + l = [] + for d in data: + if d == 0x14 or d == 0x15 or d == 0x16: # CTRL, STATUS, ACKSETUP + continue + elif (d & 0x80): + #l += [(USB_EVENTS[0x80][0] + "+%i" % (d & ~0x80), USB_EVENTS[0x80][1])] + ltssm_key = (d & ~0x80) + ltssm_val = "(unknown)" + if ltssm_key in LTSSM_STATES: + ltssm_val = LTSSM_STATES[ltssm_key][1] + ltssm_val = "LTSSM: " + ltssm_val + l += [(USB_EVENTS[0x80][0] + "+%i" % (d & ~0x80), ltssm_val)] + elif d in USB_EVENTS: + l += [USB_EVENTS[d]] + #else: + # l += [("?", "?")] + return l + +class counter_set(): + def __init__(self, counters, name='(top)'): + self._counters = counters + self._counter_names = [] + self._name = name + for c in counters: + o = 0 + default_value = False + if isinstance(c, str): + name = c + default_value = True + elif isinstance(c, tuple): + name = c[0] + o = counter_set(c[1]) + elif isinstance(c, dict): + raise Exception('Not implemented yet') + else: + raise Exception('Unknown counter format') + setattr(self, name, o) + self._counter_names += [(name, default_value)] + self._fmt_str = self._get_struct_format() + + def _get_struct_format(self): + fmt_str = "" + for name, default_value in self._counter_names: + if default_value: + fmt_str += "i" + else: + o = getattr(self, name) + fmt_str += o._get_struct_format() + return fmt_str + + def _update(self, data, parents=[]): + if len(data) == 0: + raise Exception('Ran out of data entering %s' % (self._name)) + #return [] + for name, default_value in self._counter_names: + if default_value: + if len(data) == 0: + raise Exception('Ran out of data setting %s in %s' % (name, self._name)) + setattr(self, name, data[0]) + data = data[1:] + else: + o = getattr(self, name) + data = o._update(data, parents+[self]) + return data + + def update(self, data): + try: + vals = struct.unpack(self._fmt_str, data) + self._update(vals) + except Exception as e: + print(("While updating counter set '%s':" % self._name), e) + + def __str__(self): + return self.to_string() + + def to_string(self, parents=[]): + s = "" + cnt = 0 + for name, default_value in self._counter_names: + o = getattr(self, name) + if default_value: + if cnt > 0: + s += "\t" + s += "%s: %05i" % (name, o) + cnt += 1 + else: + if cnt > 0: + s += "\n" + s += "\t"*(len(parents) + 1) + s += o.to_string(parents+[self]) + cnt = 0 + s += "\n" + return s + +class usb_device(): + def __init__(self): + #self.max_buffer_size = 64 # Default to USB2 + self.max_buffer_size = 1024*4 # Apparently it'll frag bigger packets + self.counters = counter_set(COUNTERS) + self.timeout = 2000 + + def open(self, idVendor, idProduct): + print("Finding %04x:%04x..." % (idVendor, idProduct)) + self.dev = usb.core.find(idVendor=idVendor, idProduct=idProduct) + if self.dev is None: + raise ValueError('Device not found: %04x:%04x' % (idVendor, idProduct)) + + self.log_index = 0 + self.log_read_count = 0 + self.usb_event_log_read_count = 0 + self.counters_read_count = 0 + + #if self.dev.is_kernel_driver_active(0): + # print "Detaching kernel driver..." + # self.dev.detach_kernel_driver(0) + + #self.dev.set_configuration() # This will throw as device is already claimed + + print("Opened %04x:%04x" % (idVendor, idProduct)) + + #self.dev.ctrl_transfer(0x21, 0x09, 0, 0, [0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00] ) + #self.dev.ctrl_transfer(bmRequestType, bRequest, wValue=0, wIndex=0, data_or_wLength = None, timeout = None + + #res = self.dev.ctrl_transfer(VRT_IN, 0x83, 0, 0, 1024) + # Can give 1024 byte size for IN, result will be actual payload size + # Invalid VREQ results in usb.core.USBError 32 Pipe error + #print res + + #res = self.dev.ctrl_transfer(VRT_IN, B200_VREQ_GET_USB_SPEED, 0, 0, 1) + #self.usb_speed = res[0] + while True: + #l = self.vrt_get(B200_VREQ_GET_USB_SPEED) + l = [] + try: + l = self.dev.ctrl_transfer(VRT_IN, B200_VREQ_GET_USB_SPEED, 0, 0, 1) + except usb.core.USBError as e: + if e.errno == 32: + print(e) + print("Is the firmware loaded?") + sys.exit(0) + if len(l) > 0: + self.usb_speed = l[0] + print("Operating at USB", self.usb_speed) + break + else: + print("Retrying...") + #if self.usb_speed == 3: + # self.max_buffer_size = 512 + print("Max buffer size:", self.max_buffer_size) + print() + + def _handle_error(self, e, vrt): + if e.errno == 19: # No such device + raise e + vrt_str = "0x%02x" % (vrt) + if vrt in VRQS: + vrt_str += " (%s)" % (VRQS[vrt]) + print("%s: %s" % (vrt_str, str(e))) + + def vrt_get(self, vrt): + try: + return self.dev.ctrl_transfer(VRT_IN, vrt, 0, 0, self.max_buffer_size, self.timeout) + except usb.core.USBError as e: + self._handle_error(e, vrt) + return [] + + def vrt_set(self, vrt, data=""): + try: + return self.dev.ctrl_transfer(VRT_OUT, vrt, 0, 0, data, self.timeout) + except usb.core.USBError as e: + self._handle_error(e, vrt) + return None + + def get_log(self, with_log_index=True): + lines = [] + raw = self.vrt_get(B200_VREQ_GET_LOG) + if len(raw) == 0: + return lines + if raw[0] == 0: + return lines + self.log_read_count += 1 + raw = list(raw) + last = 0 + while raw[last] != 0: + try: + try: + idx = raw.index(0, last) + except ValueError as e: + print("No null termination in log buffer (length: %d, last null: %d)" % (len(raw), last)) + break + self.log_index += 1 + line = "".join(map(chr, raw[last:idx])) + #print "[%05i %05i] %s" % (self.log_index, self.log_read_count, line) + if with_log_index: + lines += [(self.log_index, line)] + else: + lines += [line] + last = idx + 1 + if last >= len(raw): + break + except Exception as e: + print("Exception while parsing log buffer:", e) + break + return lines + + def print_log(self): + lines = self.get_log() + if len(lines) == 0: + return + for l in lines: + #print l + print("[%05i %05i] %s" % (l[0], self.log_read_count, l[1])) + print() + + def get_counters(self): + data = self.vrt_get(B200_VREQ_GET_COUNTERS) + if len(data) == 0: + return + self.counters_read_count += 1 + self.counters.update(data) + + def print_counters(self): + self.get_counters() + print("[%05i]" % (self.counters_read_count)) + print(self.counters) + + def get_usb_event_log(self): + data = self.vrt_get(B200_VREQ_GET_USB_EVENT_LOG) + if len(data) == 0: + return [] + if len(data) == self.max_buffer_size: # ZLP when no new events have been recorded + return [] + if len(data) > 64: + raise Exception("USB event log data len = %i" % (len(data))) + self.usb_event_log_read_count += 1 + return _parse_usb_event_log(data) + + def print_usb_event_log(self): + l = self.get_usb_event_log() + if len(l) == 0: + return + print("\n".join([("[%05i] " % (self.usb_event_log_read_count)) + x[0] + ":\t" + x[1] for x in l])) + print() + +def run_log(dev, options): + items = [ + (options.log, dev.print_log), + (options.counters, dev.print_counters), + (options.usb_events, dev.print_usb_event_log) + ] + items = [x for x in items if x[0] > 0] + smallest_interval = min([x[0] for x in items]) + time_now = time.time() + last = [time_now]*len(items) + + try: + for i in items: + if i[0] < 0: + i[1]() + while True: + time_now = time.time() + cleared = False + for i in range(len(items)): + time_last = last[i] + if time_now < (time_last + items[i][0]): + continue + if options.clear_screen and not cleared: + print(chr(27) + "[2J") + cleared = True + #print items[i][1] + items[i][1]() + last[i] = time.time() + time.sleep(smallest_interval) + except KeyboardInterrupt: + return + +def hex_to_int(s): + radix = 10 + s = s.lower() + if (len(s) > 1 and s[0] == 'x') or (len(s) > 2 and s[0:2] == "0x"): + radix = 16 + return int(s, radix) + +def recv_serial_data(ser): + data = "" + usb_event_log_read_count = 0 + time_start = time.time() + while True: + c = ser.read() + data += c + #if c == '\n': + if len(data) >= 2 and data[-2:] == "\r\n": + time_now_str = "[%06d]" % (int(time.time() - time_start)) + data = data[0:-2] + if data == "": + #print "[Received an empty line]" + print() + elif data[0] == ' ': + print(time_now_str, data[1:]) + elif data[0] == 'U': + data = data[1:] + cur_type = 0 + i = 0 + usb_events = [] + while len(data) > 0: + c = data[0] + + if cur_type == 0: + if c == 'a': + cur_type = 1 + elif (c >= 'A') and (c <= 'P'): + i = ord(c) - ord('A') + cur_type = 2 + else: + print(time_now_str, "[Unknown type: '%s' (0x%02x) in '%s']" % (c, ord(c), data)) + + elif cur_type == 1: + i = ord(c) - ord('a') + if (i < 0) or (i >= len(USB_PHY_ERROR_REGISTERS)): + print(time_now_str, "[Unknown PHY error register index: '%s' (0x%02x) (%d) in '%s']" % (c, ord(c), i, data)) + else: + print(time_now_str, USB_PHY_ERROR_REGISTERS[i]) + cur_type = 0 + + elif cur_type == 2: + i2 = ord(c) - ord('A') + if (c < 'A') or (c > 'P'): + print(time_now_str, "[Unknown second USB event part: '%s' (0x%02x) (%d) in '%s']" % (c, ord(c), i2, data)) + else: + i = (i << 4) | i2 + usb_events += [i] + + cur_type = 0 + + data = data[1:] + + if len(usb_events) > 0: + usb_event_log_read_count += 1 + l = _parse_usb_event_log(usb_events) + print("\n".join([time_now_str + ("[%05i] " % (usb_event_log_read_count)) + x[0] + ":\t" + x[1] for x in l])) + #print + + data = "" + +def main(): + parser = OptionParser(usage="%prog: [options]") #option_class=eng_option, + + parser.add_option("-v", "--vid", type="string", default="0x2500", help="VID [default=%default]") + parser.add_option("-p", "--pid", type="string", default="0x0020", help="PID [default=%default]") + parser.add_option("-t", "--tty", type="string", default=None, help="TTY [default=%default]") + parser.add_option("-c", "--cmd", type="string", default="", help="Command (empty opens prompt)") + parser.add_option("-n", "--counters", type="float", default="5.0", help="Counter print interval [default=%default]") + parser.add_option("-l", "--log", type="float", default="0.25", help="Log print interval [default=%default]") + parser.add_option("-e", "--usb-events", type="float", default="0.25", help="USB event log print interval [default=%default]") + parser.add_option("-s", "--sb", type="string", default=None, help="Settings Bus write message [default=%default]") + parser.add_option("-d", "--sb-baud-div", type="int", default=None, help="Settings Bus baud rate divisor [default=%default]") + parser.add_option("-b", "--sb-baud", type="int", default=None, help="Settings Bus baud rate [default=%default]") + parser.add_option("-r", "--clear-screen", action="store_true", default=False, help="Clear screen [default=%default]") + parser.add_option("-R", "--reset-counters", action="store_true", default=False, help="Reset counters [default=%default]") + parser.add_option("-f", "--flush-data-eps", action="store_true", default=False, help="Flush data endpoints [default=%default]") + parser.add_option("-L", "--fe-loopback", type="int", default=None, help="Change AD9361 digital loopback [default=%default]") + + (options, args) = parser.parse_args() + + if options.tty is not None and options.tty != "": + while True: + try: + ser = serial.Serial(port=options.tty, baudrate=115200, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=None) # timeout: None (blocking), 0 (non-blocking) + print("Opened", options.tty) + + try: + recv_serial_data(ser) + except KeyboardInterrupt: + break + except Exception as e: + print("Unable to open serial port:", e) + break + else: + dev = usb_device() + + while True: + try: + dev.open(idVendor=hex_to_int(options.vid), idProduct=hex_to_int(options.pid)) + + raw_config = dev.vrt_get(B200_VREQ_GET_CONFIG) + current_config = Config(raw=raw_config) + print("Current config:") + print(current_config) + + if options.flush_data_eps: + dev.vrt_set(B200_VREQ_FLUSH_DATA_EPS) + if options.sb_baud_div is not None: + dev.vrt_set(B200_VREQ_SET_SB_BAUD_DIV, struct.pack('H', options.sb_baud_div)) + if options.sb is not None and len(options.sb) > 0: + dev.vrt_set(B200_VREQ_WRITE_SB, " " + options.sb) + if options.reset_counters: + dev.vrt_set(B200_VREQ_CLEAR_COUNTERS) + if options.fe_loopback is not None: + dev.vrt_set(B200_VREQ_AD9361_LOOPBACK, struct.pack('B', int(options.fe_loopback))) + options.cmd = options.cmd.strip() + if len(options.cmd) == 0: + run_log(dev, options) + else: + cmds = options.cmd.split(',') + flags = 0 + for cmd in cmds: + cmd = cmd.strip() + if len(cmd) == 0: + continue + parts = cmd.split(' ') + action = parts[0].lower() + try: + if action == "txswing": + current_config.tx_swing = int(parts[1]) + flags |= CF_TX_SWING + elif action == "txdeemph": + current_config.tx_deemphasis = int(parts[1]) + flags |= CF_TX_DEEMPHASIS + elif action == "ss": + current_config.enable_as_superspeed = int(parts[1]) + flags |= CF_ENABLE_AS_SUPERSPEED + elif action == "disableusb2": + current_config.disable_usb2 = int(parts[1]) + flags |= CF_DISABLE_USB2 + elif action == "pportdrive": + current_config.pport_drive_strength = int(parts[1]) + flags |= CF_PPORT_DRIVE_STRENGTH + elif action == "dmasize": + current_config.dma_buffer_size = int(parts[1]) + flags |= CF_DMA_BUFFER_SIZE + elif action == "dmacount": + current_config.dma_buffer_count = int(parts[1]) + flags |= CF_DMA_BUFFER_COUNT + elif action == "manualdma": + current_config.manual_dma = int(parts[1]) + flags |= CF_MANUAL_DMA + elif action == "sbbauddiv": + current_config.sb_baud_div = int(parts[1]) + flags |= CF_SB_BAUD_DIV + elif action == "reenum": + flags |= CF_RE_ENUM + else: + print("'%s' not implemented" % (action)) + except Exception as e: + print("Exception while handling action '%s'" % (action), e) + if flags != 0: + print("New config to be set:") + print(current_config.to_string(flags)) + #print current_config + #print "Update flags: 0x%x" % (flags) + new_config = struct.pack("I", flags) + current_config.pack() + dev.vrt_set(B200_VREQ_SET_CONFIG, new_config) + else: + print("Not updating config") + break + except usb.core.USBError as e: + if e.errno == 19: # No such device + pass + print(e) + break + + return 0 + +if __name__ == '__main__': + main() diff --git a/host/utils/nirio_programmer.cpp b/host/utils/nirio_programmer.cpp deleted file mode 100644 index c8c5e72d3..000000000 --- a/host/utils/nirio_programmer.cpp +++ /dev/null @@ -1,275 +0,0 @@ - -#include <uhd/transport/nirio/niusrprio_session.h> -#include <uhd/transport/nirio/niriok_proxy.h> -#include <uhd/transport/nirio/nifpga_lvbitx.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <fcntl.h> -#include <iostream> -#include <fstream> -#include <streambuf> -#include <boost/program_options.hpp> -#include <boost/format.hpp> -#include <boost/thread/thread.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/regex.hpp> - -using namespace uhd::niusrprio; -using namespace uhd::usrprio_rpc; - -class dummy_lvbitx : public nifpga_lvbitx { -public: - dummy_lvbitx(const std::string& fpga_lvbitx_path) : _fpga_lvbitx_path(fpga_lvbitx_path) { - std::ifstream lvbitx_stream(_fpga_lvbitx_path.c_str()); - if (lvbitx_stream.is_open()) { - std::string lvbitx_contents; - lvbitx_stream.seekg(0, std::ios::end); - lvbitx_contents.reserve(static_cast<size_t>(lvbitx_stream.tellg())); - lvbitx_stream.seekg(0, std::ios::beg); - lvbitx_contents.assign((std::istreambuf_iterator<char>(lvbitx_stream)), std::istreambuf_iterator<char>()); - try { - boost::smatch md5_match; - if (boost::regex_search(lvbitx_contents, md5_match, boost::regex("<BitstreamMD5>([a-zA-Z0-9]{32})<\\/BitstreamMD5>", boost::regex::icase))) { - _bitstream_checksum = std::string(md5_match[1].first, md5_match[1].second); - } - boost::to_upper(_bitstream_checksum); - } catch (boost::exception&) { - _bitstream_checksum = ""; - } - try { - boost::smatch sig_match; - if (boost::regex_search(lvbitx_contents, sig_match, boost::regex("<SignatureRegister>([a-zA-Z0-9]{32})<\\/SignatureRegister>", boost::regex::icase))) { - _signature = std::string(sig_match[1].first, sig_match[1].second); - } - boost::to_upper(_signature); - } catch (boost::exception&) { - _signature = ""; - } - } - } - ~dummy_lvbitx() {} - - virtual const char* get_bitfile_path() { return _fpga_lvbitx_path.c_str(); } - virtual const char* get_signature() { return _signature.c_str(); } - virtual const char* get_bitstream_checksum() { return _bitstream_checksum.c_str(); } - - virtual size_t get_input_fifo_count() { return 0; } - virtual const char** get_input_fifo_names() { return NULL; } - - virtual size_t get_output_fifo_count() { return 0; } - virtual const char** get_output_fifo_names() { return NULL; } - - virtual size_t get_control_count() { return 0; } - virtual const char** get_control_names() { return NULL; } - - virtual size_t get_indicator_count() { return 0; } - virtual const char** get_indicator_names() { return NULL; } - - virtual void init_register_info(nirio_register_info_vtr& vtr) { vtr.clear(); } - virtual void init_fifo_info(nirio_fifo_info_vtr& vtr) { vtr.clear(); } - -private: - std::string _fpga_lvbitx_path; - std::string _bitstream_checksum; - std::string _signature; -}; - -int main(int argc, char *argv[]) -{ - nirio_status status = NiRio_Status_Success; - - //Setup the program options - uint32_t interface_num, peek_addr, poke_addr, poke_data; - std::string rpc_port, fpga_lvbitx_path, flash_path, peek_tokens_str, poke_tokens_str; - - namespace po = boost::program_options; - po::options_description desc("Allowed options"); - desc.add_options() - ("help", "help message") - ("interface", po::value<uint32_t>(&interface_num)->default_value(0), "The interface number to communicate with.") - ("port", po::value<std::string>(&rpc_port)->default_value("5444"), "Port to communicate with RPC server.") - ("fpga", po::value<std::string>(&fpga_lvbitx_path)->default_value(""), "The absolute path to the LVBITX file to download to the FPGA.") - ("flash", po::value<std::string>(&flash_path)->default_value(""), "The path to the image to download to the flash OR 'erase' to erase the FPGA image from flash.") - ("peek", po::value<std::string>(&peek_tokens_str)->default_value(""), "Peek32.") - ("poke", po::value<std::string>(&poke_tokens_str)->default_value(""), "Poke32.") - ("stats", "Dump interface and DMA stats.") - ; - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); - - //Print the help message - if (vm.count("help")){ - std::cout << boost::format("USRP-NIRIO-Programmer\n\n %s") % desc << std::endl; - return ~0; - } - - std::string resource_name = boost::str(boost::format("RIO%u") % interface_num); - - //Download LVBITX image - if (fpga_lvbitx_path != "") - { - printf("Downloading image %s to FPGA as %s...", fpga_lvbitx_path.c_str(), resource_name.c_str()); - fflush(stdout); - uhd::niusrprio::niusrprio_session fpga_session(resource_name, rpc_port); - uhd::niusrprio::nifpga_lvbitx::sptr lvbitx(new dummy_lvbitx(fpga_lvbitx_path)); - nirio_status_chain(fpga_session.open(lvbitx, true), status); - //Download BIN to flash or erase - if (flash_path != "erase") { - if (flash_path != "") { - printf("Writing FPGA image %s to flash...", flash_path.c_str()); - fflush(stdout); - nirio_status_chain(fpga_session.download_bitstream_to_flash(flash_path), status); - printf("DONE\n"); - } - } else { - printf("Erasing FPGA image from flash..."); - fflush(stdout); - nirio_status_chain(fpga_session.download_bitstream_to_flash(""), status); - printf("DONE\n"); - } - fpga_session.close(); - printf("DONE\n"); - } - - fflush(stdout); - usrprio_rpc_client temp_rpc_client("localhost", rpc_port); - std::string interface_path; - nirio_status_chain(temp_rpc_client.niusrprio_get_interface_path(resource_name, interface_path), status); - if (interface_path.empty()) { - printf("ERROR: Could not open a proxy to interface %u. If it exists, try downloading an LVBITX to the FPGA first.\n", interface_num); - exit(EXIT_FAILURE); - } - - niriok_proxy::sptr dev_proxy = niriok_proxy::make_and_open(interface_path); - - if (poke_tokens_str != ""){ - std::stringstream ss; - std::vector<std::string> poke_tokens; - boost::split(poke_tokens, poke_tokens_str, boost::is_any_of(":")); - ss.clear(); - ss << std::hex << poke_tokens[1]; - ss >> poke_addr; - ss.clear(); - ss << std::hex << poke_tokens[2]; - ss >> poke_data; - - niriok_scoped_addr_space(dev_proxy, poke_tokens[0]=="c"?BUS_INTERFACE:FPGA, status); - if (poke_tokens[0]=="z") { - nirio_status_chain(dev_proxy->poke(poke_addr, (uint32_t)0x70000 + poke_addr), status); - } else { - nirio_status_chain(dev_proxy->poke(poke_addr, poke_data), status); - } - printf("[POKE] %s:0x%x <= 0x%x (%u)\n", poke_tokens[0]=="c"?"Chinch":(poke_tokens[0]=="z"?"ZPU":"FPGA"), poke_addr, poke_data, poke_data); - } - - if (peek_tokens_str != ""){ - std::stringstream ss; - std::vector<std::string> peek_tokens; - boost::split(peek_tokens, peek_tokens_str, boost::is_any_of(":")); - ss.clear(); - ss << std::hex << peek_tokens[1]; - ss >> peek_addr; - - niriok_scoped_addr_space(dev_proxy, peek_tokens[0]=="c"?BUS_INTERFACE:FPGA, status); - uint32_t reg_val = 0; - if (peek_tokens[0]=="z") { - nirio_status_chain(dev_proxy->poke((uint32_t)0x60000 + peek_addr, (uint32_t)0), status); - do { - nirio_status_chain(dev_proxy->peek((uint32_t)0x60000 + peek_addr, reg_val), status); - } while (reg_val != 0); - nirio_status_chain(dev_proxy->peek((uint32_t)0x70000 + peek_addr, reg_val), status); - } else { - nirio_status_chain(dev_proxy->peek(peek_addr, reg_val), status); - } - - printf("[PEEK] %s:0x%x = 0x%x (%u)\n", peek_tokens[0]=="c"?"Chinch":(peek_tokens[0]=="z"?"ZPU":"FPGA"), peek_addr, reg_val, reg_val); - } - - //Display attributes - if (vm.count("stats")){ - printf("[Interface %u]\n", interface_num); - uint32_t attr_val = 0; - nirio_status_chain(dev_proxy->get_attribute(RIO_IS_FPGA_PROGRAMMED, attr_val), status); - printf("* Is FPGA Programmed? = %s\n", (attr_val==1)?"YES":"NO"); - - std::string signature; - for (int i = 0; i < 4; i++) { - nirio_status_chain(dev_proxy->peek(0x3FFF4, attr_val), status); - signature += boost::str(boost::format("%08x") % attr_val); - } - printf("* FPGA Signature = %s\n", signature.c_str()); - - std::string checksum; - for (int i = 0; i < 4; i++) { - nirio_status_chain(dev_proxy->peek(0x40030 + (i * 4), attr_val), status); - checksum += boost::str(boost::format("%08x") % attr_val); - } - printf("* FPGA Bitstream Checksum = %s\n", checksum.c_str()); - - uint32_t reg_val = 0; - nirio_status_chain(dev_proxy->set_attribute(RIO_ADDRESS_SPACE, BUS_INTERFACE), status); - nirio_status_chain(dev_proxy->peek(0, reg_val), status); - printf("* Chinch Signature = %x\n", reg_val); - nirio_status_chain(dev_proxy->set_attribute(RIO_ADDRESS_SPACE, FPGA), status); - nirio_status_chain(dev_proxy->peek(0, reg_val), status); - printf("* PCIe FPGA Signature = %x\n", reg_val); - - printf("\n[DMA Stream Stats]\n"); - - nirio_status_chain(dev_proxy->set_attribute(RIO_ADDRESS_SPACE, FPGA), status); - - printf("------------------------------------------------------------------------------------------------"); - printf("\nChannel => |"); - for (uint32_t i = 0; i < 6; i++) { - printf("%11u |", i); - } - printf("\n------------------------------------------------------------------------------------------------"); - printf("\nTX Status |"); - for (uint32_t i = 0; i < 6; i++) { - nirio_status_chain(dev_proxy->peek(0x40200 + (i * 16), reg_val), status); - printf("%s |", reg_val==0 ? " Good" : " Error"); - } - printf("\nRX Status |"); - for (uint32_t i = 0; i < 6; i++) { - nirio_status_chain(dev_proxy->peek(0x40400 + (i * 16), reg_val), status); - printf("%s |", reg_val==0 ? " Good" : " Error"); - } - printf("\nTX Frm Size |"); - for (uint32_t i = 0; i < 6; i++) { - nirio_status_chain(dev_proxy->peek(0x40204 + (i * 16), reg_val), status); - printf("%11u |", reg_val); - } - printf("\nRX Frm Size |"); - for (uint32_t i = 0; i < 6; i++) { - nirio_status_chain(dev_proxy->peek(0x40404 + (i * 16), reg_val), status); - printf("%11u |", reg_val); - } - printf("\nTX Pkt Count |"); - for (uint32_t i = 0; i < 6; i++) { - nirio_status_chain(dev_proxy->peek(0x4020C + (i * 16), reg_val), status); - printf("%11u |", reg_val); - } - printf("\nTX Samp Count |"); - for (uint32_t i = 0; i < 6; i++) { - nirio_status_chain(dev_proxy->peek(0x40208 + (i * 16), reg_val), status); - printf("%11u |", reg_val); - } - printf("\nRX Pkt Count |"); - for (uint32_t i = 0; i < 6; i++) { - nirio_status_chain(dev_proxy->peek(0x4040C + (i * 16), reg_val), status); - printf("%11u |", reg_val); - } - printf("\nRX Samp Count |"); - for (uint32_t i = 0; i < 6; i++) { - nirio_status_chain(dev_proxy->peek(0x40408 + (i * 16), reg_val), status); - printf("%11u |", reg_val); - } - printf("\n------------------------------------------------------------------------------------------------\n"); - } - - exit(EXIT_SUCCESS); -} - - diff --git a/host/utils/octoclock_firmware_burner.cpp b/host/utils/octoclock_firmware_burner.cpp index d624095e6..1ec77d0c8 100644 --- a/host/utils/octoclock_firmware_burner.cpp +++ b/host/utils/octoclock_firmware_burner.cpp @@ -1,5 +1,5 @@ // -// Copyright 2014 Ettus Research LLC +// Copyright 2014-2015 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 @@ -74,8 +74,23 @@ boost::uint8_t firmware_image[MAX_FIRMWARE_SIZE]; size_t firmware_size = 0; boost::uint8_t octoclock_data[udp_simple::mtu]; octoclock_packet_t *pkt_in = reinterpret_cast<octoclock_packet_t *>(octoclock_data); -std::string firmware_path; +std::string firmware_path, actual_firmware_path; size_t num_blocks = 0; +bool hex = true; + +static uint16_t calculate_crc(boost::uint8_t* buffer, boost::uint16_t len){ + boost::uint16_t crc = 0xFFFF; + + for(size_t i = 0; i < len; i++){ + crc ^= buffer[i]; + for(boost::uint8_t j = 0; j < 8; ++j){ + if(crc & 1) crc = (crc >> 1) ^ 0xA001; + else crc = (crc >> 1); + } + } + + return crc; +} /* * Functions @@ -89,6 +104,28 @@ void list_octoclocks(){ } } +void print_image_loader_warning(const std::string &fw_path, const po::variables_map &vm){ + // Newline + indent + #ifdef UHD_PLATFORM_WIN32 + const std::string nl = " ^\n "; + #else + const std::string nl = " \\\n "; + #endif + + std::string uhd_image_loader = str(boost::format("uhd_image_loader --args=\"type=octoclock,addr=%s\"" + "%s --fw-path=%s") + % vm["addr"].as<std::string>() % nl % fw_path); + + std::cout << "************************************************************************************************" << std::endl + << "WARNING: This utility will be removed in an upcoming version of UHD. In the future, use" << std::endl + << " this command:" << std::endl + << std::endl + << uhd_image_loader << std::endl + << std::endl + << "************************************************************************************************" << std::endl + << std::endl; +} + /* * Manually find bootloader. This sends multiple packets in order to increase chances of getting * bootloader before it switches to the application. @@ -121,26 +158,25 @@ device_addrs_t bootloader_find(const std::string &ip_addr){ } void read_firmware(){ - std::ifstream firmware_file(firmware_path.c_str(), std::ios::binary); - firmware_file.seekg(0, std::ios::end); - firmware_size = size_t(firmware_file.tellg()); + std::ifstream firmware_file(actual_firmware_path.c_str(), std::ios::binary); + firmware_size = size_t(fs::file_size(actual_firmware_path)); if(firmware_size > MAX_FIRMWARE_SIZE){ firmware_file.close(); throw uhd::runtime_error(str(boost::format("Firmware file too large: %d > %d") % firmware_size % (MAX_FIRMWARE_SIZE))); } - firmware_file.seekg(0, std::ios::beg); firmware_file.read((char*)firmware_image, firmware_size); firmware_file.close(); - num_blocks = (firmware_size % BLOCK_SIZE) ? (firmware_size / BLOCK_SIZE) - : ((firmware_size / BLOCK_SIZE) + 1); + num_blocks = (firmware_size % BLOCK_SIZE) ? ((firmware_size / BLOCK_SIZE) + 1) + : (firmware_size / BLOCK_SIZE); } void burn_firmware(udp_simple::sptr udp_transport){ octoclock_packet_t pkt_out; pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand()); - pkt_out.len = uhd::htonx<boost::uint16_t>((boost::uint16_t)firmware_size); + pkt_out.len = (boost::uint16_t)firmware_size; + pkt_out.crc = calculate_crc(firmware_image, firmware_size); size_t len = 0, current_pos = 0; //Tell OctoClock not to jump to application, wait for us instead @@ -149,6 +185,7 @@ void burn_firmware(udp_simple::sptr udp_transport){ if(UHD_OCTOCLOCK_PACKET_MATCHES(FW_BURN_READY_ACK, pkt_out, pkt_in, len)) std::cout << "ready." << std::endl; else{ std::cout << std::endl; + if(hex) fs::remove(actual_firmware_path); throw uhd::runtime_error("Could not get OctoClock in valid state for firmware download."); } @@ -165,7 +202,7 @@ void burn_firmware(udp_simple::sptr udp_transport){ << "% (" << (i+1) << "/" << num_blocks << " blocks)" << std::flush; memset(pkt_out.data, 0, BLOCK_SIZE); - memcpy((void*)(pkt_out.data), &firmware_image[i*BLOCK_SIZE], std::min(int(firmware_size-current_pos), BLOCK_SIZE)); + memcpy((void*)(pkt_out.data), &firmware_image[i*BLOCK_SIZE], BLOCK_SIZE); bool success = false; while(num_tries <= 5){ @@ -181,6 +218,7 @@ void burn_firmware(udp_simple::sptr udp_transport){ } if(not success){ std::cout << std::endl; + if(hex) fs::remove(actual_firmware_path); throw uhd::runtime_error("Failed to burn firmware to OctoClock!"); } @@ -196,7 +234,6 @@ void verify_firmware(udp_simple::sptr udp_transport){ pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand()); size_t len = 0, current_pos = 0; - for(size_t i = 0; i < num_blocks; i++){ pkt_out.sequence++; pkt_out.addr = i*BLOCK_SIZE; @@ -208,11 +245,13 @@ void verify_firmware(udp_simple::sptr udp_transport){ if(memcmp((void*)(pkt_in->data), &firmware_image[i*BLOCK_SIZE], std::min(int(firmware_size-current_pos), BLOCK_SIZE))){ std::cout << std::endl; + if(hex) fs::remove(actual_firmware_path); throw uhd::runtime_error("Failed to verify OctoClock firmware!"); } } else{ std::cout << std::endl; + if(hex) fs::remove(actual_firmware_path); throw uhd::runtime_error("Failed to verify OctoClock firmware!"); } } @@ -230,6 +269,7 @@ bool reset_octoclock(const std::string &ip_addr){ UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, RESET_CMD, pkt_out, len, octoclock_data); if(not UHD_OCTOCLOCK_PACKET_MATCHES(RESET_ACK, pkt_out, pkt_in, len)){ std::cout << std::endl; + if(hex) fs::remove(actual_firmware_path); throw uhd::runtime_error("Failed to place device in state to receive firmware."); } @@ -246,11 +286,13 @@ void finalize(udp_simple::sptr udp_transport){ UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, FINALIZE_BURNING_CMD, pkt_out, len, octoclock_data); if(not UHD_OCTOCLOCK_PACKET_MATCHES(FINALIZE_BURNING_ACK, pkt_out, pkt_in, len)){ std::cout << std::endl; + if(hex) fs::remove(actual_firmware_path); std::cout << "no ACK. Bootloader may not have loaded application." << std::endl; } } -int UHD_SAFE_MAIN(int argc, char *argv[]){ +int UHD_SAFE_MAIN(UHD_UNUSED(int argc), UHD_UNUSED(char *argv[])){ + std::string ip_addr; po::options_description desc("Allowed options"); desc.add_options() @@ -300,7 +342,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ throw uhd::runtime_error(str(boost::format("This filepath does not exist: %s") % firmware_path)); } } - else firmware_path = find_image_path("octoclock_r4_fw.bin"); + else firmware_path = find_image_path("octoclock_r4_fw.hex"); //If Intel hex file detected, convert to binary std::string ext = fs::extension(firmware_path); @@ -312,9 +354,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ % time_spec_t::get_system_time().get_full_secs())); Hex2Bin(firmware_path.c_str(), temp_bin.string().c_str(), false); - firmware_path = temp_bin.string(); + actual_firmware_path = temp_bin.string(); } else if(ext == ".bin"){ + hex = false; + actual_firmware_path = firmware_path; std::cout << "Found firmware at path: " << firmware_path << std::endl; } else throw uhd::runtime_error("The firmware file has in improper extension (must be .hex or .bin)."); @@ -327,6 +371,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ if(reset_octoclock(ip_addr)) std::cout << "successful." << std::endl; else{ std::cout << "failed." << std::endl; + if(hex) fs::remove(actual_firmware_path); throw uhd::runtime_error("Failed to reset OctoClock device into its bootloader."); } } @@ -334,11 +379,14 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ } else{ std::cout << "failed." << std::endl; + if(hex) fs::remove(actual_firmware_path); throw uhd::runtime_error("Could not find OctoClock with given IP address!"); } read_firmware(); + print_image_loader_warning(firmware_path, vm); + std::signal(SIGINT, &sig_int_handler); burn_firmware(udp_transport); @@ -354,7 +402,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ if(octoclocks.size() == 1){ if(octoclocks[0]["type"] == "octoclock-bootloader"){ std::cout << std::endl; - throw uhd::runtime_error("OctoClock failed to leave bootloader state."); + if(hex) fs::remove(actual_firmware_path); + throw uhd::runtime_error("Firmware did not load properly."); } else{ std::cout << "found." << std::endl << std::endl @@ -363,8 +412,10 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ } else{ std::cout << std::endl; + if(hex) fs::remove(actual_firmware_path); throw uhd::runtime_error("Failed to reinitialize OctoClock."); } + if(hex) fs::remove(actual_firmware_path); return EXIT_SUCCESS; } diff --git a/host/utils/uhd_image_loader.cpp b/host/utils/uhd_image_loader.cpp new file mode 100644 index 000000000..39efc8f1e --- /dev/null +++ b/host/utils/uhd_image_loader.cpp @@ -0,0 +1,122 @@ +// +// Copyright 2015 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 <csignal> +#include <cstdlib> +#include <iostream> + +#include <boost/assign.hpp> +#include <boost/filesystem.hpp> +#include <boost/format.hpp> + +#include <uhd/config.hpp> +#include <uhd/image_loader.hpp> +#include <uhd/types/device_addr.hpp> +#include <uhd/utils/safe_main.hpp> +#include <boost/program_options.hpp> + +namespace fs = boost::filesystem; +namespace po = boost::program_options; + +static std::string device_type = ""; +static int num_ctrl_c = 0; + +/* + * If the user presses Ctrl+C, warn them that they may corrupt their device. + * If they press it again, provide instructions on restoring the device + * (if applicable) and exit. + */ +void sigint_handler(int){ + num_ctrl_c++; + if(num_ctrl_c == 1){ + std::cout << std::endl + << "Are you sure you want to abort? If you do, your device will likely" << std::endl + << "be in an unstable or unusable state." << std::endl + << "Press Ctrl+C again to abort." << std::endl << std::endl; + } + else{ + std::cout << std::endl << uhd::image_loader::get_recovery_instructions(device_type) << std::endl; + exit(EXIT_FAILURE); + } +} + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + + std::string fw_path = ""; + std::string fpga_path = ""; + + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("args", po::value<std::string>()->default_value(""), "Device args, optional loader args") + ("fw-path", po::value<std::string>(&fw_path)->default_value(""), "Firmware path (uses default if none specified)") + ("fpga-path", po::value<std::string>(&fpga_path)->default_value(""), "FPGA path (uses default if none specified)") + ("no-fw", "Don't burn firmware") + ("no-fpga", "Don't burn FPGA") + ; + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + // Help message + if (vm.count("help")){ + std::cout << "UHD Image Loader" << std::endl + << std::endl + << "Load firmware and/or FPGA images onto an Ettus Research device." << std::endl + << std::endl + << desc << std::endl; + return EXIT_FAILURE; + } + + // Convert user options + uhd::image_loader::image_loader_args_t image_loader_args; + image_loader_args.args = vm["args"].as<std::string>(); + image_loader_args.load_firmware = (vm.count("no-fw") == 0); + image_loader_args.load_fpga = (vm.count("no-fpga") == 0); + image_loader_args.firmware_path = vm["fw-path"].as<std::string>(); + image_loader_args.fpga_path = vm["fpga-path"].as<std::string>(); + + // Clean up paths, if given + if(image_loader_args.firmware_path != ""){ + #ifndef UHD_PLATFORM_WIN32 + if(image_loader_args.firmware_path.find("~") == 0){ + image_loader_args.firmware_path.replace(0,1,getenv("HOME")); + } + #endif /* UHD_PLATFORM_WIN32 */ + image_loader_args.firmware_path = fs::absolute(image_loader_args.firmware_path).string(); + } + if(image_loader_args.fpga_path != ""){ + #ifndef UHD_PLATFORM_WIN32 + if(image_loader_args.fpga_path.find("~") == 0){ + image_loader_args.fpga_path.replace(0,1,getenv("HOME")); + } + #endif /* UHD_PLATFORM_WIN32 */ + image_loader_args.fpga_path = fs::absolute(image_loader_args.fpga_path).string(); + } + + // Detect which type of device we're working with + device_type = image_loader_args.args.get("type",""); + + std::signal(SIGINT, &sigint_handler); + if(not uhd::image_loader::load(image_loader_args)){ + std::cerr << "No applicable UHD devices found" << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/host/utils/uhd_images_downloader.py.in b/host/utils/uhd_images_downloader.py.in index 3903edc8c..e0375fb43 100644 --- a/host/utils/uhd_images_downloader.py.in +++ b/host/utils/uhd_images_downloader.py.in @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2012-2014 Ettus Research LLC +# Copyright 2012-2015 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 @@ -23,7 +23,7 @@ import math import traceback import shutil import hashlib -import urllib2 +import requests import zipfile from optparse import OptionParser @@ -47,8 +47,8 @@ def md5Checksum(filePath): break m.update(data) return m.hexdigest() - except Exception, e: - print "Failed to calculated MD5 sum of: %s (%s)" % (filePath, e) + except Exception as e: + print("Failed to calculated MD5 sum of: %s (%s)" % (filePath, e)) raise e _checksum_fns = { @@ -60,16 +60,16 @@ class temporary_directory(): try: self.name = tempfile.mkdtemp() return self.name - except Exception, e: - print "Failed to create a temporary directory (%s)" % (e) + except Exception as e: + print("Failed to create a temporary directory (%s)" % (e)) raise e # Can return 'True' to suppress incoming exception def __exit__(self, type, value, traceback): try: shutil.rmtree(self.name) - except Exception, e: - print "Could not delete temporary directory: %s (%s)" % (self.name, e) + except Exception as e: + print("Could not delete temporary directory: %s (%s)" % (self.name, e)) class uhd_images_downloader(): def __init__(self): @@ -77,25 +77,20 @@ class uhd_images_downloader(): def download(self, images_url, filename, buffer_size=_DEFAULT_BUFFER_SIZE, print_progress=False): """ Run the download, show progress """ - opener = urllib2.build_opener() - opener.add_headers = [('User-Agent', 'UHD Images Downloader')] - u = opener.open(images_url) - meta = u.info() - filesize = float(meta.getheaders("Content-Length")[0]) + r = requests.get(images_url, stream=True, headers={'User-Agent': 'UHD Images Downloader'}) + filesize = float(r.headers['content-length']) filesize_dl = 0 with open(filename, "wb") as f: - while True: - buff = u.read(buffer_size) - if not buff: - break - f.write(buff) - filesize_dl += len(buff) + for buff in r.iter_content(chunk_size=buffer_size): + if buff: + f.write(buff) + filesize_dl += len(buff) if print_progress: status = r"%05d kB / %05d kB (%03d%%)" % (int(math.ceil(filesize_dl/1000.)), int(math.ceil(filesize/1000.)), int(math.ceil(filesize_dl*100.)/filesize)) status += chr(8)*(len(status)+1) - print status, + sys.stdout.write(status) if print_progress: - print + print('') return (filesize, filesize_dl) def check_directories(self, dirs, print_progress=False): @@ -105,23 +100,23 @@ class uhd_images_downloader(): def _check_part(head, tail=None): if print_progress: - print "Checking: %s" % (head) + print("Checking: %s" % (head)) if tail is not None and tail == "": return True if not os.path.exists(head): if print_progress: - print "Does not exist: %s" % (head) + print("Does not exist: %s" % (head)) return _check_part(*os.path.split(head)) if not os.path.isdir(head): if print_progress: - print "Is not a directory: %s" % (head) + print("Is not a directory: %s" % (head)) return (False, head) if not os.access(head, os.W_OK): if print_progress: - print "Write permission denied on: %s" % (head) + print("Write permission denied on: %s" % (head)) return (False, head) if print_progress: - print "Write permission granted on: %s" % (head) + print("Write permission granted on: %s" % (head)) return (True, head) return _check_part(dirs) @@ -137,34 +132,34 @@ class uhd_images_downloader(): def extract_images_archive(self, archive_path, destination=None, print_progress=False): if not os.path.exists(archive_path): if print_progress: - print "Path does not exist: %s" % (archive_path) + print("Path does not exist: %s" % (archive_path)) raise Exception("path does not exist: %s" % (archive_path)) if print_progress: - print "Archive path: %s" % (archive_path) + print("Archive path: %s" % (archive_path)) (head, tail) = os.path.split(archive_path) if not os.access(head, os.W_OK): if print_progress: - print "Write access denied on: %s" % (head) + print("Write access denied on: %s" % (head)) raise Exception("write access denied on: %s" % (head)) (root, ext) = os.path.splitext(tail) temp_dir = os.path.join(head, root) if print_progress: - print "Temporary extraction location: %s" % (temp_dir) + print("Temporary extraction location: %s" % (temp_dir)) if os.path.exists(temp_dir): if print_progress: - print "Deleting existing location: %s" % (temp_dir) + print("Deleting existing location: %s" % (temp_dir)) shutil.rmtree(temp_dir) if print_progress: - print "Creating directory: %s" % (temp_dir) + print("Creating directory: %s" % (temp_dir)) os.mkdir(temp_dir) if print_progress: - print "Extracting archive %s to %s" % (archive_path, temp_dir) + print("Extracting archive %s to %s" % (archive_path, temp_dir)) images_zip = zipfile.ZipFile(archive_path) images_zip.extractall(temp_dir) @@ -175,27 +170,27 @@ class uhd_images_downloader(): def install_images(self, source, dest, keep=False, print_progress=False): if not os.path.exists(source): if print_progress: - print "Source path does not exist: %s" % (source) + print("Source path does not exist: %s" % (source)) return if keep: if print_progress: - print "Not wiping directory tree (existing files will be overwritten): %s" % (dest) + print("Not wiping directory tree (existing files will be overwritten): %s" % (dest)) elif os.path.exists(dest): if print_progress: - print "Deleting directory tree: %s" % (dest) + print("Deleting directory tree: %s" % (dest)) shutil.rmtree(dest) (head, tail) = os.path.split(source) if print_progress: - print "Source install path: %s" % (source) + print("Source install path: %s" % (source)) uhd_source = os.path.join(source, tail, *_BASE_DIR_STRUCTURE_PARTS) if print_progress: - print "Copying files from: %s" % (uhd_source) - print "Copying files to: %s" % (dest) + print("Copying files from: %s" % (uhd_source)) + print("Copying files to: %s" % (dest)) if keep: # mgrant @ http://stackoverflow.com/questions/12683834/how-to-copy-directory-recursively-in-python-and-overwrite-all @@ -222,12 +217,12 @@ def main(): ### Set defaults from env variables if os.environ.get("UHD_IMAGES_DIR") != None and os.environ.get("UHD_IMAGES_DIR") != "": default_images_dir = os.environ.get("UHD_IMAGES_DIR") - print "UHD_IMAGES_DIR environment variable is set.\nDefault install location: {0}".format(default_images_dir) + print("UHD_IMAGES_DIR environment variable is set.\nDefault install location: {0}".format(default_images_dir)) else: default_images_dir = _DEFAULT_INSTALL_PATH if os.environ.get("UHD_IMAGES_BASE_URL") != None and os.environ.get("UHD_IMAGES_BASE_URL") != "": default_base_url = os.environ.get("UHD_IMAGES_BASE_URL") - print "UHD_IMAGES_BASE_URL environment variable is set.\nDefault base URL: {0}".format(default_base_url) + print("UHD_IMAGES_BASE_URL environment variable is set.\nDefault base URL: {0}".format(default_base_url)) else: default_base_url = _DEFAULT_BASE_URL @@ -244,22 +239,22 @@ def main(): parser.add_option("-c", "--checksum", type="string", default=_AUTOGEN_IMAGES_CHECKSUM, help="Validate images archive against this checksum (blank to skip) [default=%default]") parser.add_option("-t", "--checksum-type", type="string", default=_IMAGES_CHECKSUM_TYPE, - help=("Select checksum hash function (options: %s) [default=%%default]" % (",".join(_checksum_fns.keys())))) + help=("Select checksum hash function (options: %s) [default=%%default]" % (",".join(list(_checksum_fns.keys()))))) parser.add_option("-k", "--keep", action="store_true", default=False, help="Do not clear images directory before extracting new files [default=%default]") parser.add_option("-v", "--verbose", action="store_true", default=False, help="Enable verbose output [default=%default]") (options, args) = parser.parse_args() if options.buffer_size <= 0: - print "Invalid buffer size: %s" % (options.buffer_size) + print("Invalid buffer size: %s" % (options.buffer_size)) return 1 ### Select checksum algorithm (MD5) checksum_fn = None if options.checksum != "": options.checksum_type = options.checksum_type.lower() - if not _checksum_fns.has_key(options.checksum_type): - print "Not a supported checksum function: %s" % (options.checksum_type) + if options.checksum_type not in _checksum_fns: + print("Not a supported checksum function: %s" % (options.checksum_type)) return 1 checksum_fn = _checksum_fns[options.checksum_type] @@ -275,30 +270,30 @@ def main(): base_url_is_local = True if options.verbose: - print "Requested install location: %s" % (options.install_location) - print "Images base URL: %s" % (options.base_url) - print "Images filename: %s" % (options.filename) - print "Images checksum: %s (%s)" % (options.checksum, _IMAGES_CHECKSUM_TYPE) - print "Final install location: %s" % (images_dir) - print "Copying locally: {0}".format("Yes" if base_url_is_local else "No") + print("Requested install location: %s" % (options.install_location)) + print("Images base URL: %s" % (options.base_url)) + print("Images filename: %s" % (options.filename)) + print("Images checksum: %s (%s)" % (options.checksum, _IMAGES_CHECKSUM_TYPE)) + print("Final install location: %s" % (images_dir)) + print("Copying locally: {0}".format("Yes" if base_url_is_local else "No")) else: - print "Images destination: %s" % (images_dir) + print("Images destination: %s" % (images_dir)) ### Download or copy downloader = uhd_images_downloader() try: (access, last_path) = downloader.check_directories(images_dir, print_progress=options.verbose) if not access: - print "You do not have sufficient permissions to write to: %s" % (last_path) - print "Are you root?" + print("You do not have sufficient permissions to write to: %s" % (last_path)) + print("Are you root?") return 1 with temporary_directory() as temp_dir: if options.verbose: - print "Using temporary directory: %s" % (temp_dir) + print("Using temporary directory: %s" % (temp_dir)) temp_images_dest = os.path.join(temp_dir, options.filename) if not base_url_is_local: - print "Downloading images from: {0}".format(images_url) - print "Downloading images to: {0}".format(temp_images_dest) + print("Downloading images from: {0}".format(images_url)) + print("Downloading images to: {0}".format(temp_images_dest)) (reported_size, downloaded_size) = downloader.download( images_url=images_url, filename=temp_images_dest, @@ -306,12 +301,12 @@ def main(): print_progress=True ) if options.verbose: - print "Downloaded %d of %d bytes" % (downloaded_size, reported_size) + print("Downloaded %d of %d bytes" % (downloaded_size, reported_size)) else: local_images_pkg = os.path.join(options.base_url, options.filename) - print "Copying images from: {0}".format(local_images_pkg) + print("Copying images from: {0}".format(local_images_pkg)) if not os.path.isfile(local_images_pkg): - print "[ERROR] No such file." + print("[ERROR] No such file.") return 1 shutil.copyfile(local_images_pkg, temp_images_dest) (checksum_match, calculated_checksum) = downloader.validate_checksum( @@ -321,48 +316,46 @@ def main(): print_progress=options.verbose ) if options.verbose: - print "Calculated checksum: %s" % (calculated_checksum) + print("Calculated checksum: %s" % (calculated_checksum)) if checksum_match: if options.verbose: if options.checksum == "": - print "Ignoring checksum" + print("Ignoring checksum") else: - print "Checksum OK" + print("Checksum OK") try: extract_path = downloader.extract_images_archive(temp_images_dest, print_progress=options.verbose) if options.verbose: - print "Image archive extracted to: %s" % (extract_path) + print("Image archive extracted to: %s" % (extract_path)) downloader.install_images(extract_path, images_dir, options.keep, print_progress=options.verbose) if options.verbose: - print "Cleaning up temp location: %s" % (extract_path) + print("Cleaning up temp location: %s" % (extract_path)) shutil.rmtree(extract_path) - print - print "Images successfully installed to: %s" % (images_dir) - except Exception, e: - print "Failed to install image archive: %s" % (e) - print "This is usually a permissions problem." - print "Please check your file system access rights and try again." + print("\nImages successfully installed to: %s" % (images_dir)) + except Exception as e: + print("Failed to install image archive: %s" % (e)) + print("This is usually a permissions problem.") + print("Please check your file system access rights and try again.") if options.verbose: traceback.print_exc() else: - print "You can run this again with the '--verbose' flag to see more information" - print "If the problem persists, please email the output to: %s" % (_CONTACT) + print("You can run this again with the '--verbose' flag to see more information") + print("If the problem persists, please email the output to: %s" % (_CONTACT)) else: - print "Checksum of downloaded file is not correct (not installing - see options to override)" - print "Expected: %s" % (options.checksum) - print "Calculated: %s" % (calculated_checksum) - print "Please try downloading again." - print "If the problem persists, please email the output to: %s" % (_CONTACT) + print("Checksum of downloaded file is not correct (not installing - see options to override)") + print("Expected: %s" % (options.checksum)) + print("Calculated: %s" % (calculated_checksum)) + print("Please try downloading again.") + print("If the problem persists, please email the output to: %s" % (_CONTACT)) except KeyboardInterrupt: - print - print "Cancelled at user request" - except Exception, e: - print "Downloader raised an unhandled exception: %s" % (e) + print("\nCancelled at user request") + except Exception as e: + print("Downloader raised an unhandled exception: %s" % (e)) if options.verbose: traceback.print_exc() else: - print "You can run this again with the '--verbose' flag to see more information" - print "If the problem persists, please email the output to: %s" % (_CONTACT) + print("You can run this again with the '--verbose' flag to see more information") + print("If the problem persists, please email the output to: %s" % (_CONTACT)) return 1 return 0 diff --git a/host/utils/usrp_n2xx_net_burner.py b/host/utils/usrp_n2xx_net_burner.py index 8f16de501..5605b0028 100755 --- a/host/utils/usrp_n2xx_net_burner.py +++ b/host/utils/usrp_n2xx_net_burner.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2010-2011 Ettus Research LLC +# Copyright 2010-2011,2015 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 @@ -91,6 +91,45 @@ def seq(): return _seq ######################################################################## +# print equivalent uhd_image_loader command +######################################################################## +def print_image_loader_warning(fw, fpga, reset, safe, addr): + + # Newline + indent + if platform.system() == "Windows": + nl = " ^\n " + else: + nl = " \\\n " + + # Generate uhd_image_loader command based on given arguments + uhd_image_loader = "uhd_image_loader --args=\"type=usrp2,addr={0}".format(addr) + if reset: + uhd_image_loader += ",reset" + if safe: + uhd_image_loader += ",overwrite-safe" + uhd_image_loader += "\"" + + if fw: + uhd_image_loader += "{0}--fw-path=\"{1}\"".format(nl, fw) + else: + uhd_image_loader += "{0}--no-fw".format(nl) + + if fpga: + uhd_image_loader += "{0}--fpga-path=\"{1}\"".format(nl, fpga) + else: + uhd_image_loader += "{0}--no-fpga".format(nl) + + print("") + print("************************************************************************************************") + print("WARNING: This utility will be removed in an upcoming version of UHD. In the future, use") + print(" this command:") + print("") + print(uhd_image_loader) + print("") + print("************************************************************************************************") + print("") + +######################################################################## # helper functions ######################################################################## def unpack_flash_args_fmt(s): @@ -234,6 +273,7 @@ def enumerate_devices(): class burner_socket(object): def __init__(self, addr, quiet): self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self._addr = addr self._quiet = quiet self._sock.settimeout(UDP_TIMEOUT) self._sock.connect((addr, UDP_FW_UPDATE_PORT)) @@ -284,6 +324,8 @@ class burner_socket(object): return (self.memory_size_bytes, self.sector_size_bytes) def burn_fw(self, fw, fpga, reset, safe, check_rev=True): + print_image_loader_warning(fw, fpga, reset, safe, self._addr) + (flash_size, sector_size) = self.get_flash_info() hw_rev = self.get_hw_rev() @@ -501,7 +543,12 @@ if __name__=='__main__': if options.overwrite_safe and not options.read: print("Are you REALLY, REALLY sure you want to overwrite the safe image? This is ALMOST ALWAYS a terrible idea.") print("If your image is faulty, your USRP2+ will become a brick until reprogrammed via JTAG.") - response = raw_input("""Type "yes" to continue, or anything else to quit: """) + + python_major_version = int(platform.python_version_tuple()[0]) + if python_major_version > 2: + response = input("""Type "yes" to continue, or anything else to quit: """) + else: + response = raw_input("""Type "yes" to continue, or anything else to quit: """) if response != "yes": sys.exit(0) burner = burner_socket(addr=options.addr,quiet=False) diff --git a/host/utils/usrp_n2xx_simple_net_burner.cpp b/host/utils/usrp_n2xx_simple_net_burner.cpp index 642e9a407..b105e9cb6 100644 --- a/host/utils/usrp_n2xx_simple_net_burner.cpp +++ b/host/utils/usrp_n2xx_simple_net_burner.cpp @@ -1,5 +1,5 @@ // -// Copyright 2012-2014 Ettus Research LLC +// Copyright 2012-2015 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 @@ -184,6 +184,59 @@ void list_usrps(){ /*********************************************************************** * Find USRP N2XX with specified IP address and return type **********************************************************************/ +void print_image_loader_warning(const std::string &fw_path, + const std::string &fpga_path, + const po::variables_map &vm){ + + // Newline + indent + #ifdef UHD_PLATFORM_WIN32 + const std::string nl = " ^\n "; + #else + const std::string nl = " \\\n "; + #endif + + std::string uhd_image_loader = str(boost::format("uhd_image_loader --args=\"type=usrp2,addr=%s") + % vm["addr"].as<std::string>()); + if(vm.count("auto-reboot") > 0) + uhd_image_loader += ",reset"; + if(vm.count("overwrite-safe") > 0) + uhd_image_loader += ",overwrite-safe"; + if(vm.count("dont-check-rev") > 0) + uhd_image_loader += ",dont-check-rev"; + + uhd_image_loader += "\""; + + if(vm.count("no-fw") == 0){ + uhd_image_loader += str(boost::format("%s--fw-path=\"%s\"") + % nl % fw_path); + } + else{ + uhd_image_loader += str(boost::format("%s--no-fw") + % nl); + } + + if(vm.count("no-fpga") == 0){ + uhd_image_loader += str(boost::format("%s--fpga-path=\"%s\"") + % nl % fpga_path); + } + else{ + uhd_image_loader += str(boost::format("%s--no-fpga") + % nl); + } + + std::cout << "************************************************************************************************" << std::endl + << "WARNING: This utility will be removed in an upcoming version of UHD. In the future, use" << std::endl + << " this command:" << std::endl + << std::endl + << uhd_image_loader << std::endl + << std::endl + << "************************************************************************************************" << std::endl + << std::endl; +} + +/*********************************************************************** + * Find USRP N2XX with specified IP address and return type + **********************************************************************/ boost::uint32_t find_usrp(udp_simple::sptr udp_transport, bool check_rev){ boost::uint32_t hw_rev; bool found_it = false; @@ -627,6 +680,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ fw_image_size = read_fw_image(fw_path); } + print_image_loader_warning(fw_path, fpga_path, vm); + std::cout << "Will burn the following images:" << std::endl; if(burn_fw) std::cout << boost::format(" * Firmware: %s\n") % fw_path; if(burn_fpga) std::cout << boost::format(" * FPGA: %s\n") % fpga_path; diff --git a/host/utils/usrp_x3xx_fpga_burner.cpp b/host/utils/usrp_x3xx_fpga_burner.cpp index 3c6225531..704b291be 100644 --- a/host/utils/usrp_x3xx_fpga_burner.cpp +++ b/host/utils/usrp_x3xx_fpga_burner.cpp @@ -1,5 +1,5 @@ // -// Copyright 2013-2014 Ettus Research LLC +// Copyright 2013-2015 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 @@ -54,7 +54,7 @@ extern "C" { } #define X300_FPGA_BIN_SIZE_BYTES 15877916 -#define X300_FPGA_BIT_MAX_SIZE_BYTES 15878022 +#define X300_FPGA_BIT_MAX_SIZE_BYTES 15878032 #define X300_FPGA_PROG_UDP_PORT 49157 #define X300_FLASH_SECTOR_SIZE 131072 #define X300_PACKET_SIZE_BYTES 256 @@ -195,6 +195,71 @@ void extract_from_lvbitx(std::string lvbitx_path, std::vector<char> &bitstream){ bitstream.swap(decoded_bitstream); } +void print_image_loader_warning(const std::string &fpga_path, const po::variables_map &vm){ + + // Newline + indent + #ifdef UHD_PLATFORM_WIN32 + const std::string nl = " ^\n "; + #else + const std::string nl = " \\\n "; + #endif + + // Generate equivalent uhd_image_loader command + std::string uhd_image_loader = "uhd_image_loader --args=\"type=x300"; + + if(vm.count("addr") > 0){ + uhd_image_loader += str(boost::format(",addr=%s") + % vm["addr"].as<std::string>()); + + if(vm.count("configure") > 0){ + uhd_image_loader += ",configure"; + } + + if(vm.count("verify") > 0){ + uhd_image_loader += ",verify"; + } + } + else{ + uhd_image_loader += str(boost::format(",resource=%s") + % vm["resource"].as<std::string>()); + + /* + * Since we have a default value, vm.count("rpc-port") will + * always be > 0, so only add the option if a different port + * is given. + */ + if(vm["rpc-port"].as<std::string>() != "5444"){ + uhd_image_loader += str(boost::format(",rpc-port=%s") + % vm["rpc-port"].as<std::string>()); + } + } + + if(vm.count("type") > 0){ + uhd_image_loader += str(boost::format(",fpga=%s") + % vm["type"].as<std::string>()); + } + + uhd_image_loader += "\""; + + /* + * The --type option overrides any given path, so only add an FPGA path + * if there was no --type argument. + */ + if(vm.count("type") == 0){ + uhd_image_loader += str(boost::format("%s--fpga-path=\"%s\"") + % nl % fpga_path); + } + + std::cout << "************************************************************************************************" << std::endl + << "WARNING: This utility will be removed in an upcoming version of UHD. In the future, use" << std::endl + << " this command:" << std::endl + << std::endl + << uhd_image_loader << std::endl + << std::endl + << "************************************************************************************************" << std::endl + << std::endl; +} + void ethernet_burn(udp_simple::sptr udp_transport, std::string fpga_path, bool verify){ boost::uint32_t max_size; std::vector<char> bitstream; @@ -479,6 +544,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ throw std::runtime_error("The image filename must end in .bin, .bit, or .lvbitx."); } + print_image_loader_warning(fpga_path, vm); + std::signal(SIGINT, &sig_int_handler); if(vm.count("addr")){ udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(X300_FPGA_PROG_UDP_PORT)); |