diff options
-rwxr-xr-x | host/utils/b2xx_side_channel.py | 272 | ||||
-rwxr-xr-x | tools/b200/b2x0_side_channel.py | 650 |
2 files changed, 223 insertions, 699 deletions
diff --git a/host/utils/b2xx_side_channel.py b/host/utils/b2xx_side_channel.py index 7b1e980eb..070f5684c 100755 --- a/host/utils/b2xx_side_channel.py +++ b/host/utils/b2xx_side_channel.py @@ -16,25 +16,27 @@ # 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 pysusb'" + 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) -import serial - VRT_OUT = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_OUT VRT_IN = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_IN @@ -62,7 +64,7 @@ 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 +COUNTER_MAGIC = 0x10024001 """ typedef struct Counters { int magic; @@ -162,6 +164,10 @@ USB_PHY_ERROR_REGISTERS = [ USB_ERROR_COUNTERS += USB_PHY_ERROR_REGISTERS +PIB_COUNTERS = [ + 'socket_inactive' +] + COUNTERS = [ 'magic', @@ -177,7 +183,13 @@ COUNTERS = [ 'heap_size', - 'resume_count' + '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 = {} @@ -243,6 +255,101 @@ 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: @@ -252,11 +359,11 @@ def _parse_usb_event_log(data): #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): + 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 USB_EVENTS.has_key(d): + elif d in USB_EVENTS: l += [USB_EVENTS[d]] #else: # l += [("?", "?")] @@ -313,8 +420,8 @@ class counter_set(): try: vals = struct.unpack(self._fmt_str, data) self._update(vals) - except Exception, e: - print e + except Exception as e: + print(("While updating counter set '%s':" % self._name), e) def __str__(self): return self.to_string() @@ -346,7 +453,7 @@ class usb_device(): self.timeout = 2000 def open(self, idVendor, idProduct): - print "Finding %04x:%04x..." % (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)) @@ -362,7 +469,7 @@ class usb_device(): #self.dev.set_configuration() # This will throw as device is already claimed - print "Opened %04x:%04x" % (idVendor, idProduct) + 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 @@ -379,40 +486,41 @@ class usb_device(): l = [] try: l = self.dev.ctrl_transfer(VRT_IN, B200_VREQ_GET_USB_SPEED, 0, 0, 1) - except usb.core.USBError, e: + except usb.core.USBError as e: if e.errno == 32: - print e + 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 + print("Operating at USB", self.usb_speed) break else: - print "Retrying..." + print("Retrying...") #if self.usb_speed == 3: # self.max_buffer_size = 512 - print "Max buffer size:", self.max_buffer_size - print + 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): + if vrt in VRQS: vrt_str += " (%s)" % (VRQS[vrt]) - print "%s: %s" % (vrt_str, str(e)) + 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: + 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, e: + except usb.core.USBError as e: self._handle_error(e, vrt) return None @@ -428,7 +536,11 @@ class usb_device(): last = 0 while raw[last] != 0: try: - idx = raw.index(0, last) + 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) @@ -439,8 +551,8 @@ class usb_device(): last = idx + 1 if last >= len(raw): break - except Exception, e: - print e + except Exception as e: + print("Exception while parsing log buffer:", e) break return lines @@ -450,8 +562,8 @@ class usb_device(): return for l in lines: #print l - print "[%05i %05i] %s" % (l[0], self.log_read_count, l[1]) - print + 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) @@ -462,8 +574,8 @@ class usb_device(): def print_counters(self): self.get_counters() - print "[%05i]" % (self.counters_read_count) - print self.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) @@ -480,8 +592,8 @@ class usb_device(): 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 + 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 = [ @@ -489,8 +601,8 @@ def run_log(dev, options): (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)) + 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) @@ -506,7 +618,7 @@ def run_log(dev, options): if time_now < (time_last + items[i][0]): continue if options.clear_screen and not cleared: - print chr(27) + "[2J" + print(chr(27) + "[2J") cleared = True #print items[i][1] items[i][1]() @@ -535,9 +647,9 @@ def recv_serial_data(ser): data = data[0:-2] if data == "": #print "[Received an empty line]" - print + print() elif data[0] == ' ': - print time_now_str, data[1:] + print(time_now_str, data[1:]) elif data[0] == 'U': data = data[1:] cur_type = 0 @@ -553,20 +665,20 @@ def recv_serial_data(ser): i = ord(c) - ord('A') cur_type = 2 else: - print time_now_str, "[Unknown type: '%s' (0x%02x) in '%s']" % (c, ord(c), data) + 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) + 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] + 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) + 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] @@ -578,11 +690,14 @@ def recv_serial_data(ser): 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)) + 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]") @@ -597,26 +712,34 @@ def main(): 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 + print("Opened", options.tty) + try: recv_serial_data(ser) except KeyboardInterrupt: break except Exception as e: - print 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: @@ -627,17 +750,68 @@ def main(): 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) - pass else: - pass + 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 + print(e) break + return 0 if __name__ == '__main__': diff --git a/tools/b200/b2x0_side_channel.py b/tools/b200/b2x0_side_channel.py deleted file mode 100755 index cf88bd35f..000000000 --- a/tools/b200/b2x0_side_channel.py +++ /dev/null @@ -1,650 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright 2013-2014 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 usb - please have pyusb in your PYTHONPATH" - raise e - -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)) - #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, 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, e: - if e.errno == 19: # No such device - pass - print e - break - - return 0 - -if __name__ == '__main__': - main() |