diff options
Diffstat (limited to 'host/utils')
| -rw-r--r-- | host/utils/b2xx_fx3_utils.cpp | 86 | ||||
| -rwxr-xr-x | host/utils/b2xx_side_channel.py | 644 | ||||
| -rw-r--r-- | host/utils/octoclock_firmware_burner.cpp | 57 | 
3 files changed, 745 insertions, 42 deletions
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..7b1e980eb --- /dev/null +++ b/host/utils/b2xx_side_channel.py @@ -0,0 +1,644 @@ +#!/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/>. +# + +import sys +import time +import struct + +from optparse import OptionParser + +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 pysusb'" +    exit(1) + +import serial + +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 + +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' +] + +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"] + +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_STATES.has_key(ltssm_key): +                ltssm_val = LTSSM_STATES[ltssm_key][1] +            ltssm_val = "LTSSM: " + ltssm_val +            l += [(USB_EVENTS[0x80][0] + "+%i" % (d & ~0x80), ltssm_val)] +        elif USB_EVENTS.has_key(d): +            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, e: +            print 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, e: +                if e.errno == 32: +                    print e +                    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 VRQS.has_key(vrt): +            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, 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, 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: +                idx = raw.index(0, last) +                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, e: +                print 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(map(lambda x: ("[%05i] " % (self.usb_event_log_read_count)) + x[0] + ":\t" + x[1], 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 = filter(lambda x: x[0] > 0, items) +    smallest_interval = min(map(lambda x: x[0], 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(map(lambda x: time_now_str + ("[%05i] " % (usb_event_log_read_count)) + x[0] + ":\t" + x[1], l)) +            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 e +            break +    else: +        dev = usb_device() +        while True: +            try: +                dev.open(idVendor=hex_to_int(options.vid), idProduct=hex_to_int(options.pid)) + +                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))) +                if len(options.cmd) == 0: +                    run_log(dev, options) +                    pass +                else: +                    pass +                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/octoclock_firmware_burner.cpp b/host/utils/octoclock_firmware_burner.cpp index d624095e6..eb8198a2b 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 @@ -121,26 +136,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 +163,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 +180,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 +196,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 +212,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 +223,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 +247,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 +264,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 +320,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 +332,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 +349,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,6 +357,7 @@ 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!");      } @@ -354,7 +378,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 +388,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;  }  | 
