#!/usr/bin/env python """ # TOP2049 Open Source programming suite # # USB dump parser # # Copyright (c) 2010 Michael Buesch # # 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 2 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, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ import sys import re packethdr_re = re.compile(r"Dev\s+([0-9a-fA-F]{4,4}):([0-9a-fA-F]{4,4})\s+EP([0-9a-fA-F]+)\s+(\w+)\s(\w+)\s+len=(\d+)") payload_re = re.compile(r"\[([0-9a-fA-F]+)\]:\s+([0-9a-fA-F\s]+)\s+.+") def generateHexdump(mem): def toAscii(char): if char >= 32 and char <= 126: return chr(char) return "." ret = "" ascii = "" for i in range(0, len(mem)): if i % 16 == 0 and i != 0: ret += " " + ascii + "\n" ascii = "" if i % 16 == 0: ret += "0x%04X: " % i c = mem[i] ret += "%02X" % c if (i % 2 != 0): ret += " " ascii += toAscii(c) ret += " " + ascii + "\n\n" return ret def dumpMem(mem): sys.stdout.write(generateHexdump(mem)) def dumpInstr(instr, description): for i in instr: sys.stdout.write("%02X" % i) sys.stdout.write(" " * (10 - len(instr))) sys.stdout.write(": " + description) sys.stdout.write("\n") def parseBulkIn(data): if len(data) == 64: print "Read buffer register" dumpMem(data) def parseBulkOut(data): i = 0 while i < len(data): if data[i] == 0x00: dumpInstr(data[i:i+1], "Delay 4 usec") elif data[i] == 0x01: dumpInstr(data[i:i+1], "Read byte from FPGA") elif data[i] == 0x07: dumpInstr(data[i:i+1], "Read buffer register request") elif data[i] == 0x0A: dumpInstr(data[i:i+3], "Write 0x%02X to the FPGA at address 0x%02X" % (data[i+2], data[i+1])) i += 2 elif data[i] == 0x0B: dumpInstr(data[i:i+2], "Read data from FPGA at address 0x%02X" % (data[i+1])) i += 1 elif data[i] == 0x0E and data[i+1] == 0x11: dumpInstr(data[i:i+4], "Read device ID request") i += 3 elif data[i] == 0x0E and data[i+1] == 0x12: centivolts = data[i+2] dumpInstr(data[i:i+4], "Set VPP to %.2f Volts" % (float(centivolts) / 10)) i += 3 elif data[i] == 0x0E and data[i+1] == 0x13: centivolts = data[i+2] dumpInstr(data[i:i+4], "Set VCC to %.2f Volts" % (float(centivolts) / 10)) i += 3 elif data[i] == 0x0E and data[i+1] == 0x14: dumpInstr(data[i:i+4], "Loading VPP layout %d" % data[i+1]) i += 3 elif data[i] == 0x0E and data[i+1] == 0x15: dumpInstr(data[i:i+4], "Loading VCC layout %d" % data[i+1]) i += 3 elif data[i] == 0x0E and data[i+1] == 0x16: dumpInstr(data[i:i+4], "Loading GND layout %d" % data[i+1]) i += 3 elif data[i] == 0x0E and data[i+1] == 0x20: dumpInstr(data[i:i+4], "Unknown 0x0E20%02X%02X" % (data[i+2], data[i+3])) i += 3 elif data[i] == 0x0E and data[i+1] == 0x21: dumpInstr(data[i:i+4], "Initiate FPGA programming") i += 3 elif data[i] == 0x0E and data[i+1] == 0x22: dumpInstr(data[i:i+4], "Upload FPGA configuration data") i += 63 elif data[i] == 0x0E and data[i+1] == 0x25: dumpInstr(data[i:i+4], "Unknown 0x0E25") i += 3 elif data[i] == 0x0E and data[i+1] == 0x28: op = "Disable" if data[i+2] == chr(0): op = "Enable" dumpInstr(data[i:i+4], "%s the ZIF socket" % op) i += 3 elif data[i] == 0x0E and data[i+1] == 0x1F: dumpInstr(data[i:i+4], "Unknown 0x0E1F") i += 3 elif data[i] == 0x0D: dumpInstr(data[i:i+1], "Unknown 0x0D") elif data[i] == 0x10: dumpInstr(data[i:i+2], "Write 0x%02X to the FPGA at address 0x10" % data[i+1]) i += 1 elif data[i] == 0x19: dumpInstr(data[i:i+1], "Unknown 0x19") elif data[i] == 0x1B: dumpInstr(data[i:i+1], "Delay 10 msec") elif data[i] == 0x34: dumpInstr(data[i:i+1], "Unknown 0x34") elif data[i] == 0x38: dumpInstr(data[i:i+2], "Unknown 0x38") i += 1 elif data[i] == 0x39: dumpInstr(data[i:i+1], "Unknown 0x39") elif data[i] == 0x4A: dumpInstr(data[i:i+2], "Unknown 0x4A") i += 1 elif data[i] == 0x4B: dumpInstr(data[i:i+2], "Unknown 0x4B") i += 1 else: print "UNKNOWN INSTRUCTION 0x%02X. Aborting..." % data[i] for j in range(i, len(data)): sys.stdout.write("%02X " % data[j]) print "" sys.exit(1) i += 1 def parseDumpFile(fd): transtype = None bulkData = [] for line in fd.readlines(): if transtype == "BULK": # Bulk IN or OUT transfer m = payload_re.match(line) if m: offset = int(m.group(1), 16) dataString = m.group(2) dataString = dataString.replace(" ", "").strip() assert(len(dataString) % 2 == 0) for i in range(0, len(dataString), 2): byteStr = dataString[i:i+2] bulkData.append(int(byteStr, 16)) else: # Transfer done assert(len(bulkData) == length) if direction == "IN": parseBulkIn(bulkData) elif direction == "OUT": parseBulkOut(bulkData) else: assert(0) transtype = None bulkData = [] m = packethdr_re.match(line) if m: vendor = int(m.group(1), 16) device = int(m.group(2), 16) ep = int(m.group(3), 16) transtype = m.group(4).upper() direction = m.group(5).upper() length = int(m.group(6)) def usage(): print "dump-parser.py file.dump" def main(argv): if len(argv) != 2: usage() return 1 fd = open(argv[1]) parseDumpFile(fd) return 0 if __name__ == "__main__": sys.exit(main(sys.argv))