class SetupPacket: """Represents the SETUP stage of a control transfer. This is responsible for decoding the bitfields and structure of the packet, but not for defining the meaning of a particular request. """ _recipNames = Struct.EnumDict({ 0x00: 'device', 0x01: 'interface', 0x02: 'endpoint', 0x03: 'other', }) _typeNames = Struct.EnumDict({ 0x00: 'standard', 0x20: 'class', 0x40: 'vendor', 0x60: 'reserved', }) def __init__(self, event): self.event = event (self.bitmap, self.request, self.wValue, self.wIndex, self.wLength) = struct.unpack("<BBHHH", event.data[:8]) # Decode self.bitmap self.recip = self._recipNames[self.bitmap & 0x1F] self.type = self._typeNames[self.bitmap & 0x60] # Split up wValue/wIndex for convenience self.wValueHigh = self.wValue >> 8 self.wValueLow = self.wValue & 0xFF self.wIndexHigh = self.wIndex >> 8 self.wIndexLow = self.wIndex & 0xFF
def handleTCP(self, event, data, datalen): """Decode an IPPROTO_TCP packet header, and log the payload.""" datalen -= 0x14 tcpHeader = Struct.Group(None, Struct.UInt16BEHex("source"), Struct.UInt16BEHex("dest"), Struct.UInt32BE("seq"), Struct.UInt32BE("ack_seq"), Struct.UInt16BEHex("flags"), Struct.UInt16BE("window"), Struct.UInt16BEHex("checksum"), Struct.UInt16BEHex("urg_ptr")) data = tcpHeader.decode(data) event.pushDecoded("iPhone TCP [%s -> %s] len=0x%04x" % ( self.portNumbers[tcpHeader.source], self.portNumbers[tcpHeader.dest], datalen, )) event.appendDecoded("\nTCP Header:\n%s" % str(tcpHeader)) event.appendDecoded("\nTCP Payload:\n%s" % Types.hexDump(data)) # Look for a protocol-specific handler for port in tcpHeader.source, tcpHeader.dest: fn = getattr(self, "port_%s" % self.portNumbers[port], None) if fn: fn(event, data, datalen)
def handleEvent(self, event): if not event.isDataTransaction(): return header = Struct.Group(None, Struct.UInt8("eventCode"), Struct.UInt8("numParameters"), ) params = header.decode(event.data) event.pushDecoded("BT Event: %s" % self.eventNames[header.eventCode])
def __init__(self, cdb): self.header = Struct.Group(None, Struct.UInt8("opcode")) params = self.header.decode(cdb) self.name = self._opcodes[self.header.opcode] if self.name in self._structs: fmt, children = self._structs[self.name] self.params = Struct.Group(None, *children()) self.params.decode(params) self.summary = fmt % self.params.__dict__ else: self.params = None self.summary = ''
class StatusDecoder: """Decodes USBS status blocks""" _statusCodes = Struct.EnumDict({ 0x00: 'ok', 0x01: 'FAILED', 0x02: 'PHASE ERROR', }) def handleEvent(self, event): if not event.isDataTransaction(): return if not event.data.startswith("USBS"): return header = Struct.Group(None, Struct.UInt32("sig"), Struct.UInt32("tag"), Struct.UInt32("residue"), Struct.UInt8("status")) header.decode(event.data) if header.residue: residue = ', residue=%d' % header.residue else: residue = '' event.pushDecoded("Storage Status (%s%s)" % (self._statusCodes[header.status], residue)) event.appendDecoded("\n%s" % header)
def decode_HCICommand(self, setup): header = Struct.Group(None, Struct.UInt16("opcode"), Struct.UInt8("numParameters"), ) params = header.decode(setup.event.data[8:]) if header.opcode is None: ocf = ogf = None else: ocf = header.opcode & 0x03FF ogf = header.opcode >> 10 ogfName = self.hciOpcodes.get(ogf, (ogf, {}))[0] ocfName = self.hciOpcodes.get(ogf, (ogf, {}))[1].get(ocf, ocf) setup.event.pushDecoded("BT Command: %s [%s]" % (ocfName, ogfName))
def handleEvent(self, event): if not event.isDataTransaction(): return if not event.data.startswith("USBS"): return header = Struct.Group(None, Struct.UInt32("sig"), Struct.UInt32("tag"), Struct.UInt32("residue"), Struct.UInt8("status")) header.decode(event.data) if header.residue: residue = ', residue=%d' % header.residue else: residue = '' event.pushDecoded("Storage Status (%s%s)" % (self._statusCodes[header.status], residue)) event.appendDecoded("\n%s" % header)
class EventDecoder: """This decodes incoming Interrupt traffic from a bluetooth HCI device, representing HCI events. """ eventNames = Struct.EnumDict({ 0x01: 'Inquiry Complete', 0x02: 'Inquiry Result', 0x03: 'Connection Complete', 0x04: 'Connection Request', 0x05: 'Disconnection Complete', 0x06: 'Authentication Complete', 0x07: 'Remote Name Request Complete', 0x08: 'Encryption Change', 0x09: 'Change Connection Link Key Complete', 0x0A: 'Master Link Key Complete', 0x0B: 'Read Remote Supported Features Complete', 0x0C: 'Read Remote Version Information Complete', 0x0D: 'QoS Setup Complete', 0x0E: 'Command Complete', 0x0F: 'Command Status', 0x10: 'Hardware Error', 0x11: 'Flush Occurred', 0x12: 'Role Change', 0x13: 'Number of Completed Packets', 0x14: 'Mode Change', 0x15: 'Return Link Keys', 0x16: 'PIN Code Request', 0x17: 'Link Key Request', 0x18: 'Link Key Notification', 0x19: 'Loopback Command', 0x1A: 'Data Buffer Overflow', 0x1B: 'Max Slots Change', 0x1C: 'Read Clock Offset Complete', 0x1D: 'Connection Packet Type Changed', 0x1E: 'QoS Violation', 0x20: 'Page Scan Repetition Mode Change', 0x21: 'HCI Flow Specification Complete', 0x22: 'Inquiry Result With RSSI', 0x23: 'Read Remote Extended Features Complete', 0x2C: 'Synchronous Connection Complete', 0x2D: 'Synchronous Connection Changed', }) def handleEvent(self, event): if not event.isDataTransaction(): return header = Struct.Group( None, Struct.UInt8("eventCode"), Struct.UInt8("numParameters"), ) params = header.decode(event.data) event.pushDecoded("BT Event: %s" % self.eventNames[header.eventCode])
def handleEvent(self, event): if not event.isDataTransaction(): return setup = SetupPacket(event) # Look up the request name setup.requestName = getattr(self, "%sRequests" % setup.type, Struct.EnumDict())[setup.request] # Look up a corresponding decoder getattr(self, "decode_%s" % setup.requestName, self.decodeGeneric)(setup)
def handleEvent(self, event): if not event.isDataTransaction(): return header = Struct.Group(None, Struct.UInt16("handle"), Struct.UInt16("dataTotalLength"), ) params = header.decode(event.data) if header.handle is None: return boundaryFlag = (header.handle >> 12) & 3 broadcastFlag = (header.handle >> 14) & 3 handle = header.handle & 0x0FFF event.pushDecoded("BT ACL: handle=0x%04x len=0x%04x (%s%s)" % (handle, header.dataTotalLength, self.packetBoundaryNames[boundaryFlag], self.broadcastFlagNames[broadcastFlag]))
def handleGenericPacket(self, event): """Decode the usbmuxd header.""" muxHeader = Struct.Group(None, Struct.UInt32BE("protocol"), Struct.UInt32BE("length")) data = muxHeader.decode(event.data) description = "iPhone usbmuxd: " if muxHeader.length is None: description += "ERROR" else: self.remainingLength = muxHeader.length - event.datalen description += "proto=%s len=0x%04x" % (self.ipProto[muxHeader.protocol], muxHeader.length) if self.remainingLength: description += " (0x%04x remaining)" % self.remainingLength event.pushDecoded(description) if self.ipProto[muxHeader.protocol] == 'TCP': self.handleTCP(event, data, muxHeader.length - 0x08)
def handleEvent(self, event): if not event.isDataTransaction(): return if not event.data.startswith("USBC"): return header = Struct.Group(None, Struct.UInt32("sig"), Struct.UInt32("tag"), Struct.UInt32("datalen"), Struct.UInt8("flag"), Struct.UInt8("lun"), Struct.UInt8("cdblen")) cdb = header.decode(event.data) command = SCSICommand(cdb) event.pushDecoded("Storage Command: %s" % command) event.appendDecoded("\n%s" % command.params)
class USBMuxDecoder: """Decodes incoming or outgoing usbmuxd bulk plackets.""" ipProto = Struct.EnumDict({ 0: 'VERSION', 1: 'ICMP', 6: 'TCP', 17: 'UDP', 41: 'IPv6', }) portNumbers = Struct.EnumDict({ 62078: 'lockdownd', }) remainingLength = 0 lockdownBuffer = "" def handleEvent(self, event): if not event.isDataTransaction(): return if self.remainingLength == 0: # Beginning a new packet self.handleGenericPacket(event) elif self.remainingLength >= event.datalen: # Continuing a packet self.remainingLength -= event.datalen event.pushDecoded("[usbmuxd continuation, %d bytes left]" % self.remainingLength) else: event.pushDecoded("[usbmuxd ERROR, only expected %d bytes]" % self.remainingLength) self.remainingLength = 0 def handleGenericPacket(self, event): """Decode the usbmuxd header.""" muxHeader = Struct.Group(None, Struct.UInt32BE("protocol"), Struct.UInt32BE("length")) data = muxHeader.decode(event.data) description = "iPhone usbmuxd: " if muxHeader.length is None: description += "ERROR" else: self.remainingLength = muxHeader.length - event.datalen description += "proto=%s len=0x%04x" % (self.ipProto[muxHeader.protocol], muxHeader.length) if self.remainingLength: description += " (0x%04x remaining)" % self.remainingLength event.pushDecoded(description) if self.ipProto[muxHeader.protocol] == 'TCP': self.handleTCP(event, data, muxHeader.length - 0x08) def handleTCP(self, event, data, datalen): """Decode an IPPROTO_TCP packet header, and log the payload.""" datalen -= 0x14 tcpHeader = Struct.Group(None, Struct.UInt16BEHex("source"), Struct.UInt16BEHex("dest"), Struct.UInt32BE("seq"), Struct.UInt32BE("ack_seq"), Struct.UInt16BEHex("flags"), Struct.UInt16BE("window"), Struct.UInt16BEHex("checksum"), Struct.UInt16BEHex("urg_ptr")) data = tcpHeader.decode(data) event.pushDecoded("iPhone TCP [%s -> %s] len=0x%04x" % ( self.portNumbers[tcpHeader.source], self.portNumbers[tcpHeader.dest], datalen, )) event.appendDecoded("\nTCP Header:\n%s" % str(tcpHeader)) event.appendDecoded("\nTCP Payload:\n%s" % Types.hexDump(data)) # Look for a protocol-specific handler for port in tcpHeader.source, tcpHeader.dest: fn = getattr(self, "port_%s" % self.portNumbers[port], None) if fn: fn(event, data, datalen) def port_lockdownd(self, event, data, datalen): """Handle lockdownd packets. These form a stream, which may or may not line up with the underlying USB packets. Each lockdownd packet is an XML plist, prefixed with a 32-bit length. """ summary = [] self.lockdownBuffer += data if datalen == 0: # Leave the TCP decoder at the top of the stac return elif datalen != len(data): # Nothing we can reliably do without the whole log. self.lockdownBuffer = "" summary.append("ERROR, incomplete log!") elif (len(self.lockdownBuffer) >= 10 and self.lockdownBuffer[0] == '\0' and isascii(self.lockdownBuffer[1:])): # I haven't seen this documented, but sometimes lockdownd sends # ASCII error messages that are prefixed with one NUL byte. summary.append("Message, %r" % self.lockdownBuffer[1:]) elif len(self.lockdownBuffer) >= 10 and self.lockdownBuffer[4:9] != "<?xml": # Something else that isn't a plist? self.lockdownBuffer = "" summary.append("UNRECOGNIZED (SSL encrypted?)") else: # Decode all the packets we can while len(self.lockdownBuffer) >= 4: length = struct.unpack(">I", self.lockdownBuffer[:4])[0] if len(self.lockdownBuffer) < length + 4: break packet = self.lockdownBuffer[4:length + 4] self.lockdownBuffer = self.lockdownBuffer[length + 4:] event.appendDecoded("\nComplete lockdownd packet:\n%s" % Types.hexDump(packet)) kvFull = [] kvAbbrev = [] for k, v in plistlib.readPlistFromString(packet).items(): kvFull.append(" %s = %s" % (k, v)) if isinstance(v, plistlib.Data): v = "(data)" elif isinstance(v, dict): v = "(dict)" kvAbbrev.append("%s=%s" % (k, v)) event.appendDecoded("\nDecoded plist:\n%s" % "\n".join(kvFull)) summary.append("{%s}" % " ".join(kvAbbrev)) event.pushDecoded("lockdownd: %s" % (" ".join(summary) or "fragment"))
class SCSICommand: """Decodes a SCSI command block""" _opcodes = Struct.EnumDict({ 0x00: 'TEST_UNIT_READY', 0x01: 'REZERO_UNIT', 0x03: 'REQUEST_SENSE', 0x04: 'FORMAT_UNIT', 0x05: 'READ_BLOCKLIMITS', 0x07: 'REASSIGN_BLOCKS', 0x07: 'INIT_ELEMENT_STATUS', 0x08: 'READ(6)', 0x0a: 'WRITE(6)', 0x0a: 'PRINT', 0x0b: 'SEEK(6)', 0x0b: 'SLEW_AND_PRINT', 0x0f: 'READ_REVERSE', 0x10: 'WRITE_FILEMARKS', 0x10: 'SYNC_BUFFER', 0x11: 'SPACE', 0x12: 'INQUIRY', 0x14: 'RECOVER_BUFFERED', 0x15: 'MODE_SELECT', 0x16: 'RESERVE_UNIT', 0x17: 'RELEASE_UNIT', 0x18: 'COPY', 0x19: 'ERASE', 0x1a: 'MODE_SENSE', 0x1b: 'START_UNIT', 0x1b: 'SCAN', 0x1b: 'STOP_PRINT', 0x1c: 'RECV_DIAGNOSTIC', 0x1d: 'SEND_DIAGNOSTIC', 0x1e: 'MEDIUM_REMOVAL', 0x23: 'READ_FORMAT_CAPACITIES', 0x24: 'SET_WINDOW', 0x25: 'GET_WINDOW', 0x25: 'READ_CAPACITY', 0x28: 'READ(10)', 0x29: 'READ_GENERATION', 0x2a: 'WRITE(10)', 0x2b: 'SEEK(10)', 0x2b: 'POSITION_TO_ELEMENT', 0x2d: 'READ_UPDATED_BLOCK', 0x2e: 'WRITE_VERIFY', 0x2f: 'VERIFY', 0x30: 'SEARCH_DATA_HIGH', 0x31: 'SEARCH_DATA_EQUAL', 0x32: 'SEARCH_DATA_LOW', 0x33: 'SET_LIMITS', 0x34: 'PREFETCH', 0x34: 'READ_POSITION', 0x35: 'SYNC_CACHE', 0x36: 'LOCKUNLOCK_CACHE', 0x37: 'READ_DEFECT_DATA', 0x38: 'MEDIUM_SCAN', 0x39: 'COMPARE', 0x3a: 'COPY_VERIFY', 0x3b: 'WRITE_BUFFER', 0x3c: 'READ_BUFFER', 0x3d: 'UPDATE_BLOCK', 0x3e: 'READ_LONG', 0x3f: 'WRITE_LONG', 0x40: 'CHANGE_DEF', 0x41: 'WRITE_SAME', 0x42: 'READ_SUBCHANNEL', 0x43: 'READ_TOC', 0x44: 'READ_HEADER', 0x45: 'PLAY_AUDIO(10)', 0x46: 'GET_CONFIGURATION', 0x47: 'PLAY_AUDIO_MSF', 0x48: 'PLAY_AUDIO_TRACK', 0x49: 'PLAY_AUDIO_RELATIVE', 0x4a: 'GET_EVENT_STATUS_NOTIFICATION', 0x4b: 'PAUSE', 0x4c: 'LOG_SELECT', 0x4d: 'LOG_SENSE', 0x4e: 'STOP_PLAY', 0x51: 'READ_DISC_INFO', 0x52: 'READ_TRACK_INFO', 0x53: 'RESERVE_TRACK', 0x54: 'SEND_OPC_INFORMATION', 0x55: 'MODE_SELECT(10)', 0x56: 'RESERVE_UNIT(10)', 0x57: 'RELEASE_UNIT(10)', 0x5a: 'MODE_SENSE(10)', 0x5b: 'CLOSE_SESSION', 0x5c: 'READ_BUFFER_CAPACITY', 0x5d: 'SEND_CUE_SHEET', 0x5e: 'PERSISTENT_RESERVE_IN', 0x5f: 'PERSISTENT_RESERVE_OUT', 0x88: 'READ(16)', 0x8a: 'WRITE(16)', 0x9e: 'READ_CAPACITY(16)', 0xa0: 'REPORT_LUNS', 0xa1: 'BLANK', 0xa3: 'MAINTENANCE_IN', 0xa4: 'MAINTENANCE_OUT', 0xa3: 'SEND_KEY', 0xa4: 'REPORT_KEY', 0xa5: 'MOVE_MEDIUM', 0xa5: 'PLAY_AUDIO(12)', 0xa6: 'EXCHANGE_MEDIUM', 0xa6: 'LOADCD', 0xa8: 'READ(12)', 0xa9: 'PLAY_TRACK_RELATIVE', 0xaa: 'WRITE(12)', 0xac: 'ERASE(12)', 0xac: 'GET_PERFORMANCE', 0xad: 'READ_DVD_STRUCTURE', 0xae: 'WRITE_VERIFY(12)', 0xaf: 'VERIFY(12)', 0xb0: 'SEARCH_DATA_HIGH(12)', 0xb1: 'SEARCH_DATA_EQUAL(12)', 0xb2: 'SEARCH_DATA_LOW(12)', 0xb3: 'SET_LIMITS(12)', 0xb5: 'REQUEST_VOLUME_ELEMENT_ADDR', 0xb6: 'SEND_VOLUME_TAG', 0xb6: 'SET_STREAMING', 0xb7: 'READ_DEFECT_DATA(12)', 0xb8: 'READ_ELEMENT_STATUS', 0xb8: 'SELECT_CDROM_SPEED', 0xb9: 'READ_CD_MSF', 0xba: 'AUDIO_SCAN', 0xbb: 'SET_CDROM_SPEED', 0xbc: 'SEND_CDROM_XA_DATA', 0xbc: 'PLAY_CD', 0xbd: 'MECH_STATUS', 0xbe: 'READ_CD', 0xbf: 'SEND_DVD_STRUCTURE', }) # For every command we want to decode parameters for, this includes # a struct definition, and a format string that defines a useful # summary of the parameters. The entire struct is included after # the summary line. _structs = { # 'INQUIRY': None, # FIXME: We should decode this. SCSI-2, page 104 (8.2.5) 'READ(6)': ( "0x%(length)02x blocks at 0x%(lba)04x", lambda: ( Struct.UInt8('lun'), # FIXME: lun is actually a bitfield Struct.UInt16BE('lba'), Struct.UInt8('length'), Struct.UInt8('control'))), 'READ(10)': ( "0x%(length)04x blocks at 0x%(lba)08x", lambda: ( Struct.UInt8('lun'), # FIXME: lun is actually a bitfield Struct.UInt32BE('lba'), Struct.UInt8('reserved_1'), Struct.UInt16BE('length'), Struct.UInt8('control'))), 'WRITE(6)': ( "0x%(length)02x blocks at 0x%(lba)04x", lambda: ( Struct.UInt8('lun'), # FIXME: lun is actually a bitfield Struct.UInt16BE('lba'), Struct.UInt8('length'), Struct.UInt8('control'))), 'WRITE(10)': ( "0x%(length)04x blocks at 0x%(lba)08x", lambda: ( Struct.UInt8('lun'), # FIXME: lun is actually a bitfield Struct.UInt32BE('lba'), Struct.UInt8('reserved_1'), Struct.UInt16BE('length'), Struct.UInt8('control'))), } def __init__(self, cdb): self.header = Struct.Group(None, Struct.UInt8("opcode")) params = self.header.decode(cdb) self.name = self._opcodes[self.header.opcode] if self.name in self._structs: fmt, children = self._structs[self.name] self.params = Struct.Group(None, *children()) self.params.decode(params) self.summary = fmt % self.params.__dict__ else: self.params = None self.summary = '' def __str__(self): return "%s %s" % (self.name, self.summary)
class ControlDecoder(Decode.ControlDecoder): """This extends the default ControlDecoder with support for HCI commands encapsulated within class-specific control requests. """ classRequests = Struct.EnumDict({ 0x00: 'HCICommand', }) hciOpcodes = { 0x01: ("LC", { 0x0001: "HCI_Inquiry", 0x0002: "HCI_Inquiry_Cancel", 0x0003: "HCI_Periodic_Inquiry_Mode", 0x0004: "HCI_Exit_Periodic_Inquiry_Mode", 0x0005: "HCI_Create_Connection", 0x0006: "HCI_Disconnect", 0x0008: "HCI_Create_Connection_Cancel", 0x0009: "HCI_Accept_Connection_Request", 0x000A: "HCI_Reject_Connection_Request", 0x000B: "HCI_Link_Key_Request_Reply", 0x000C: "HCI_Link_Key_Request_Negative_Reply", 0x000D: "HCI_PIN_Code_Request_Reply", 0x000E: "HCI_PIN_Code_Request_Negative_Reply", 0x000F: "HCI_Change_Connection_Packet_Type", 0x0011: "HCI_Authentication_Requested", 0x0013: "HCI_Set_Connection_Encryption", 0x0015: "HCI_Change_Connection_Link_Key", 0x0017: "HCI_Master_Link_Key", 0x0019: "HCI_Remote_Name_Request", 0x001A: "HCI_Remote_Name_Request_Cancel", 0x001B: "HCI_Read_Remote_Supported_Features", 0x001C: "HCI_Read_Remote_Extended_Features", 0x001D: "HCI_Read_Remote_Version_Information", 0x001F: "HCI_Read_Clock_Offset", 0x0020: "HCI_Read_LMP_Handle", 0x0028: "HCI_Setup_Synchronous_Connection", 0x0029: "HCI_Accept_Synchronous_Connection_Request", 0x002A: "HCI_Reject_Synchronous_Connection_Request", }), 0x02: ("LP", { 0x0001: "HCI_Hold_Mode", 0x0003: "HCI_Sniff_Mode", 0x0004: "HCI_Exit_Sniff_Mode", 0x0005: "HCI_Park_State", 0x0006: "HCI_Exit_Park_State", 0x0007: "HCI_QoS_Setup", 0x0009: "HCI_Role_Discovery", 0x000B: "HCI_Switch_Role", 0x000C: "HCI_Read_Link_Policy_Settings", 0x000D: "HCI_Write_Link_Policy_Settings", 0x000E: "HCI_Read_Default_Link_Policy_Settings", 0x000F: "HCI_Write_Default_Link_Policy_Settings", 0x0010: "HCI_Flow_Specification", }), 0x03: ("C&B", {0x0001: "HCI_Set_Event_Mask", 0x0003: "HCI_Reset", 0x0005: "HCI_Set_Event_Filter", 0x0008: "HCI_Flush", 0x0009: "HCI_Read_PIN_Type", 0x000A: "HCI_Write_PIN_Type", 0x000B: "HCI_Create_New_Unit_Key", 0x000D: "HCI_Read_Stored_Link_Key", 0x0011: "HCI_Write_Stored_Link_Key", 0x0012: "HCI_Delete_Stored_Link_Key", 0x0013: "HCI_Write_Local_Name", 0x0014: "HCI_Read_Local_Name", 0x0015: "HCI_Read_Connection_Accept_Timeout", 0x0016: "HCI_Write_Connection_Accept_Timeout", 0x0017: "HCI_Read_Page_Timeout", 0x0018: "HCI_Write_Page_Timeout", 0x0019: "HCI_Read_Scan_Enable", 0x001A: "HCI_Write_Scan_Enable", 0x001B: "HCI_Read_Page_Scan_Activity", 0x001C: "HCI_Write_Page_Scan_Activity", 0x001D: "HCI_Read_Inquiry_Scan_Activity", 0x001E: "HCI_Write_Inquiry_Scan_Activity", 0x001F: "HCI_Read_Authentication_Enable", 0x0020: "HCI_Write_Authentication_Enable", 0x0021: "HCI_Read_Encryption_Mode", 0x0022: "HCI_Write_Encryption_Mode", 0x0023: "HCI_Read_Class_of_Device", 0x0024: "HCI_Write_Class_of_Device", 0x0025: "HCI_Read_Voice_Setting", 0x0026: "HCI_Write_Voice_Setting", 0x0027: "HCI_Read_Automatic_Flush_Timeout", 0x0028: "HCI_Write_Automatic_Flush_Timeout", 0x0029: "HCI_Read_Num_Broadcast_Transmissions", 0x002A: "HCI_Write_Num_Broadcast_Transmissions", 0x002B: "HCI_Read_Hold_Mode_Activity", 0x002C: "HCI_Write_Hold_Mode_Activity", 0x002D: "HCI_Read_Transmit_Power_Level", 0x002E: "HCI_Read_Synchronous_Flow_Control_Enable", 0x002F: "HCI_Write_Synchronous_Flow_Control_Enable", 0x0031: "HCI_Set_Controller_To_Host_Flow_Control", 0x0033: "HCI_Host_Buffer_Size", 0x0035: "HCI_Host_Number_Of_Completed_Packets", 0x0036: "HCI_Read_Link_Supervision_Timeout", 0x0037: "HCI_Write_Link_Supervision_Timeout", 0x0038: "HCI_Read_Number_Of_Supported_IAC", 0x0039: "HCI_Read_Current_IAC_LAP", 0x003A: "HCI_Write_Current_IAC_LAP", 0x003B: "HCI_Read_Page_Scan_Period_Mode", 0x003C: "HCI_Write_Page_Scan_Period_Mode", 0x003F: "Set_AFH_Host_Channel_Classification", 0x0042: "HCI_Read_Inquiry_Scan_Type", 0x0043: "HCI_Write_Inquiry_Scan_Type", 0x0044: "HCI_Read_Inquiry_Mode", 0x0045: "HCI_Write_Inquiry_Mode", 0x0046: "HCI_Read_Page_Scan_Type", 0x0047: "HCI_Write_Page_Scan_Type", 0x0048: "Read_AFH_Channel_Assignment_Mode", 0x0049: "Write_AFH_Channel_Assignment_Mode", }), 0x04: ("IP", { 0x0001: "HCI_Read_Local_Version_Information", 0x0002: "HCI_Read_Local_Supported_Commands", 0x0003: "HCI_Read_Local_Supported_Features", 0x0004: "HCI_Read_Local_Extended_Features", 0x0005: "HCI_Read_Buffer_Size", 0x0009: "HCI_Read_BD_Addr", }), 0x05: ("SP", { 0x0001: "HCI_Read_Failed_Contact_Counter", 0x0002: "HCI_Reset_Failed_Contact_Counter", 0x0003: "HCI_Read_Link_Quality", 0x0005: "HCI_Read_RSSI", 0x0006: "HCI_Read_AFH_Channel_Map", 0x0007: "HCI_Read_Clock", }), 0x06: ("Test",{0x0001: "HCI_Read_Loopback_Mode", 0x0002: "HCI_Write_Loopback_Mode", 0x0003: "HCI_Enable_Device_Under_Test_Mode", }), } def decode_HCICommand(self, setup): header = Struct.Group(None, Struct.UInt16("opcode"), Struct.UInt8("numParameters"), ) params = header.decode(setup.event.data[8:]) if header.opcode is None: ocf = ogf = None else: ocf = header.opcode & 0x03FF ogf = header.opcode >> 10 ogfName = self.hciOpcodes.get(ogf, (ogf, {}))[0] ocfName = self.hciOpcodes.get(ogf, (ogf, {}))[1].get(ocf, ocf) setup.event.pushDecoded("BT Command: %s [%s]" % (ocfName, ogfName))
def decode_SetFeature(self, setup): feature = getattr(self, "%sFeatures" % setup.type, Struct.EnumDict())[setup.wValue] setup.event.pushDecoded("%s %s(%s, %s=0x%02x)" % (setup.type, setup.requestName, feature, setup.recip, setup.wIndex))
class ControlDecoder: """Decodes standard control requests, and tries to detect additional class decoders based on descriptors we see. Control requests first have their names looked up in a table of the form <type>Requests. They may then go to a default decoder, or we may look up one of the form decode_<name> from this class. This class defines all standard requests. Subclasses may define extra class- or vendor-specific requests. """ standardRequests = Struct.EnumDict({ 0x00: 'GetStatus', 0x01: 'ClearFeature', 0x03: 'SetFeature', 0x05: 'SetAddress', 0x06: 'GetDescriptor', 0x07: 'SetDescriptor', 0x08: 'GetConfiguration', 0x09: 'SetConfiguration', 0x0A: 'GetInterface', 0x0B: 'SetInterface', 0x0C: 'SynchFrame', }) standardFeatures = Struct.EnumDict({ 0x00: 'ENDPOINT_HALT', 0x01: 'DEVICE_REMOTE_WAKEUP', }) descriptorClass = DescriptorGroup def __init__(self, device): self.device = device def handleEvent(self, event): if not event.isDataTransaction(): return setup = SetupPacket(event) # Look up the request name setup.requestName = getattr(self, "%sRequests" % setup.type, Struct.EnumDict())[setup.request] # Look up a corresponding decoder getattr(self, "decode_%s" % setup.requestName, self.decodeGeneric)(setup) def decodeGeneric(self, setup): """Generic decoder for control requests""" setup.event.pushDecoded("%s %s %s(wValue=0x%04x, wIndex=0x%04x)" % (setup.type, setup.recip, setup.requestName, setup.wValue, setup.wIndex)) def decode_SetAddress(self, setup): setup.event.pushDecoded("SetAddress(%d)" % setup.wValue) def decode_SetConfiguration(self, setup): setup.event.pushDecoded("SetConfiguration(%d)" % setup.wValue) self.device.setConfig(setup.wValue) def decode_SetDescriptor(self, setup): # Display the get/set descriptor request itself setup.event.pushDecoded("%s(%s, %s%s)" % ( setup.requestName, self.descriptorClass.descriptorTypes[setup.wValueHigh], setup.wValueLow, ("", ", lang=%04X" % setup.wIndex)[setup.wIndex != 0], )) # Parse out all descriptors descriptors = [] buffer = setup.event.data[8:] while buffer: desc = self.descriptorClass() buffer = desc.decode(buffer) setup.event.appendDecoded("\n%s descriptor:\n%s" % (desc.type, desc)) descriptors.append(desc) self.device.storeDescriptors(descriptors) decode_GetDescriptor = decode_SetDescriptor def decode_SetFeature(self, setup): feature = getattr(self, "%sFeatures" % setup.type, Struct.EnumDict())[setup.wValue] setup.event.pushDecoded("%s %s(%s, %s=0x%02x)" % (setup.type, setup.requestName, feature, setup.recip, setup.wIndex)) decode_ClearFeature = decode_SetFeature def decode_SetInterface(self, setup): setup.event.pushDecoded("SetInterface(alt=%d, iface=%d)" % (setup.wValue, setup.wIndex)) self.device.setInterface(setup.wIndex, setup.wValue)
class DescriptorGroup(Struct.Group): """Parses out USB descriptors into a Struct.Group tree. This class handles any standard descriptor, but subclasses can add class-specific descriptors as needed. """ descriptorTypes = Struct.EnumDict({ 0x01: "device", 0x02: "config", 0x03: "string", 0x04: "interface", 0x05: "endpoint", }) headerStruct = lambda self: ( Struct.UInt8("bLength"), Struct.UInt8("bDescriptorType"), ) struct_device = lambda self: ( Struct.UInt16Hex("bcdUSB"), Struct.UInt8Hex("bDeviceClass"), Struct.UInt8Hex("bDeviceSubClass"), Struct.UInt8Hex("bDeviceProtocol"), Struct.UInt8("bMaxPacketSize0"), Struct.UInt16Hex("idVendor"), Struct.UInt16Hex("idProduct"), Struct.UInt16Hex("bcdDevice"), Struct.UInt8("iManufacturer"), Struct.UInt8("iProduct"), Struct.UInt8("iSerialNumber"), Struct.UInt8("bNumConfigurations"), ) struct_config = lambda self: ( Struct.UInt16("wTotalLength"), Struct.UInt8("bNumInterfaces"), Struct.UInt8("bConfigurationValue"), Struct.UInt8("iConfiguration"), Struct.UInt8Hex("bmAttributes"), Struct.UInt8("MaxPower"), ) struct_string = lambda self: (Struct.Utf16String("string"), ) struct_interface = lambda self: ( Struct.UInt8("bInterfaceNumber"), Struct.UInt8("bAlternateSetting"), Struct.UInt8("bNumEndpoints"), Struct.UInt8Hex("bInterfaceClass"), Struct.UInt8Hex("bInterfaceSubClass"), Struct.UInt8Hex("bInterfaceProtocol"), Struct.UInt8("iInterface"), ) struct_endpoint = lambda self: ( Struct.UInt8Hex("bEndpointAddress"), Struct.UInt8Hex("bmAttributes"), Struct.UInt16("wMaxPacketSize"), Struct.UInt8("bInterval"), ) def __init__(self): Struct.Group.__init__(self, "descriptors") def decode(self, buffer): # Common descriptor header buffer = Struct.Group.decode(self, buffer, self.headerStruct()) # Decode descriptor type self.type = self.descriptorTypes[self.bDescriptorType] # Make sure that we eat exactly the right number of bytes, # according to the descriptor header descriptor = buffer[:self.bLength - 2] buffer = buffer[self.bLength - 2:] # The rest of the decoding is done by a hander, in the form of a child item list. Struct.Group.decode( self, descriptor, getattr(self, "struct_%s" % self.type, lambda: None)()) return buffer
class FX2Decoder(Decode.ControlDecoder): """Decodes the control endpoint on Cypress FX2 chips. This endpoint has vendor-specific commands, implemented in hardware, to read and write RAM. """ vendorRequests = Struct.EnumDict({ 0xA0: 'FirmwareCommand', }) registerInfo = { 0xE600: ('CPUCS', 'Control & Status'), 0xE601: ('IFCONFIG', 'Interface Configuration'), 0xE602: ('PINFLAGSAB', 'FIFO FLAGA and FLAGB Assignments'), 0xE603: ('PINFLAGSCD', 'FIFO FLAGC and FLAGD Assignments'), 0xE604: ('FIFORESET', 'Restore FIFOS to default state'), 0xE605: ('BREAKPT', 'Breakpoint'), 0xE606: ('BPADDRH', 'Breakpoint Address H'), 0xE607: ('BPADDRL', 'Breakpoint Address L'), 0xE608: ('UART230', '230 Kbaud clock for T0,T1,T2'), 0xE609: ('FIFOPINPOLAR', 'FIFO polarities'), 0xE60A: ('REVID', 'Chip Revision'), 0xE60B: ('REVCTL', 'Chip Revision Control'), 0xE610: ('EP1OUTCFG', 'Endpoint 1-OUT Configuration'), 0xE611: ('EP1INCFG', 'Endpoint 1-IN Configuration'), 0xE612: ('EP2CFG', 'Endpoint 2 Configuration'), 0xE613: ('EP4CFG', 'Endpoint 4 Configuration'), 0xE614: ('EP6CFG', 'Endpoint 6 Configuration'), 0xE615: ('EP8CFG', 'Endpoint 8 Configuration'), 0xE618: ('EP2FIFOCFG', 'Endpoint 2 FIFO configuration'), 0xE619: ('EP4FIFOCFG', 'Endpoint 4 FIFO configuration'), 0xE61A: ('EP6FIFOCFG', 'Endpoint 6 FIFO configuration'), 0xE61B: ('EP8FIFOCFG', 'Endpoint 8 FIFO configuration'), 0xE620: ('EP2AUTOINLENH', 'Endpoint 2 Packet Length H (IN only)'), 0xE621: ('EP2AUTOINLENL', 'Endpoint 2 Packet Length L (IN only)'), 0xE622: ('EP4AUTOINLENH', 'Endpoint 4 Packet Length H (IN only)'), 0xE623: ('EP4AUTOINLENL', 'Endpoint 4 Packet Length L (IN only)'), 0xE624: ('EP6AUTOINLENH', 'Endpoint 6 Packet Length H (IN only)'), 0xE625: ('EP6AUTOINLENL', 'Endpoint 6 Packet Length L (IN only)'), 0xE626: ('EP8AUTOINLENH', 'Endpoint 8 Packet Length H (IN only)'), 0xE627: ('EP8AUTOINLENL', 'Endpoint 8 Packet Length L (IN only)'), 0xE630: ('EP2FIFOPFH', 'EP2 Programmable Flag trigger H'), 0xE631: ('EP2FIFOPFL', 'EP2 Programmable Flag trigger L'), 0xE632: ('EP4FIFOPFH', 'EP4 Programmable Flag trigger H'), 0xE633: ('EP4FIFOPFL', 'EP4 Programmable Flag trigger L'), 0xE634: ('EP6FIFOPFH', 'EP6 Programmable Flag trigger H'), 0xE635: ('EP6FIFOPFL', 'EP6 Programmable Flag trigger L'), 0xE636: ('EP8FIFOPFH', 'EP8 Programmable Flag trigger H'), 0xE637: ('EP8FIFOPFL', 'EP8 Programmable Flag trigger L'), 0xE640: ('EP2ISOINPKTS', 'EP2 (if ISO) IN Packets per frame (1-3)'), 0xE641: ('EP4ISOINPKTS', 'EP4 (if ISO) IN Packets per frame (1-3)'), 0xE642: ('EP6ISOINPKTS', 'EP6 (if ISO) IN Packets per frame (1-3)'), 0xE643: ('EP8ISOINPKTS', 'EP8 (if ISO) IN Packets per frame (1-3)'), 0xE648: ('INPKTEND', 'Force IN Packet End'), 0xE649: ('OUTPKTEND', 'Force OUT Packet End'), 0xE650: ('EP2FIFOIE', 'Endpoint 2 Flag Interrupt Enable'), 0xE651: ('EP2FIFOIRQ', 'Endpoint 2 Flag Interrupt Request'), 0xE652: ('EP4FIFOIE', 'Endpoint 4 Flag Interrupt Enable'), 0xE653: ('EP4FIFOIRQ', 'Endpoint 4 Flag Interrupt Request'), 0xE654: ('EP6FIFOIE', 'Endpoint 6 Flag Interrupt Enable'), 0xE655: ('EP6FIFOIRQ', 'Endpoint 6 Flag Interrupt Request'), 0xE656: ('EP8FIFOIE', 'Endpoint 8 Flag Interrupt Enable'), 0xE657: ('EP8FIFOIRQ', 'Endpoint 8 Flag Interrupt Request'), 0xE658: ('IBNIE', 'IN-BULK-NAK Interrupt Enable'), 0xE659: ('IBNIRQ', 'IN-BULK-NAK interrupt Request'), 0xE65A: ('NAKIE', 'Endpoint Ping NAK interrupt Enable'), 0xE65B: ('NAKIRQ', 'Endpoint Ping NAK interrupt Request'), 0xE65C: ('USBIE', 'USB Int Enables'), 0xE65D: ('USBIRQ', 'USB Interrupt Requests'), 0xE65E: ('EPIE', 'Endpoint Interrupt Enables'), 0xE65F: ('EPIRQ', 'Endpoint Interrupt Requests'), 0xE660: ('GPIFIE', 'GPIF Interrupt Enable'), 0xE661: ('GPIFIRQ', 'GPIF Interrupt Request'), 0xE662: ('USBERRIE', 'USB Error Interrupt Enables'), 0xE663: ('USBERRIRQ', 'USB Error Interrupt Requests'), 0xE664: ('ERRCNTLIM', 'USB Error counter and limit'), 0xE665: ('CLRERRCNT', 'Clear Error Counter EC[3..0]'), 0xE666: ('INT2IVEC', 'Interupt 2 (USB) Autovector'), 0xE667: ('INT4IVEC', 'Interupt 4 (FIFOS & GPIF) Autovector'), 0xE668: ('INTSETUP', 'Interrupt 2&4 Setup'), 0xE670: ('PORTACFG', 'I/O PORTA Alternate Configuration'), 0xE671: ('PORTCCFG', 'I/O PORTC Alternate Configuration'), 0xE672: ('PORTECFG', 'I/O PORTE Alternate Configuration'), 0xE678: ('I2CS', 'Control & Status'), 0xE679: ('I2DAT', 'Data'), 0xE67A: ('I2CTL', 'I2C Control'), 0xE67B: ('EXTAUTODAT1', 'Autoptr1 MOVX access'), 0xE67C: ('EXTAUTODAT2', 'Autoptr2 MOVX access'), 0xE680: ('USBCS', 'USB Control & Status'), 0xE681: ('SUSPEND', 'Put chip into suspend'), 0xE682: ('WAKEUPCS', 'Wakeup source and polarity'), 0xE683: ('TOGCTL', 'Toggle Control'), 0xE684: ('USBFRAMEH', 'USB Frame count H'), 0xE685: ('USBFRAMEL', 'USB Frame count L'), 0xE686: ('MICROFRAME', 'Microframe count, 0-7'), 0xE687: ('FNADDR', 'USB Function address'), 0xE68A: ('EP0BCH', 'Endpoint 0 Byte Count H'), 0xE68B: ('EP0BCL', 'Endpoint 0 Byte Count L'), 0xE68D: ('EP1OUTBC', 'Endpoint 1 OUT Byte Count'), 0xE68F: ('EP1INBC', 'Endpoint 1 IN Byte Count'), 0xE690: ('EP2BCH', 'Endpoint 2 Byte Count H'), 0xE691: ('EP2BCL', 'Endpoint 2 Byte Count L'), 0xE694: ('EP4BCH', 'Endpoint 4 Byte Count H'), 0xE695: ('EP4BCL', 'Endpoint 4 Byte Count L'), 0xE698: ('EP6BCH', 'Endpoint 6 Byte Count H'), 0xE699: ('EP6BCL', 'Endpoint 6 Byte Count L'), 0xE69C: ('EP8BCH', 'Endpoint 8 Byte Count H'), 0xE69D: ('EP8BCL', 'Endpoint 8 Byte Count L'), 0xE6A0: ('EP0CS', 'Endpoint Control and Status'), 0xE6A1: ('EP1OUTCS', 'Endpoint 1 OUT Control and Status'), 0xE6A2: ('EP1INCS', 'Endpoint 1 IN Control and Status'), 0xE6A3: ('EP2CS', 'Endpoint 2 Control and Status'), 0xE6A4: ('EP4CS', 'Endpoint 4 Control and Status'), 0xE6A5: ('EP6CS', 'Endpoint 6 Control and Status'), 0xE6A6: ('EP8CS', 'Endpoint 8 Control and Status'), 0xE6A7: ('EP2FIFOFLGS', 'Endpoint 2 Flags'), 0xE6A8: ('EP4FIFOFLGS', 'Endpoint 4 Flags'), 0xE6A9: ('EP6FIFOFLGS', 'Endpoint 6 Flags'), 0xE6AA: ('EP8FIFOFLGS', 'Endpoint 8 Flags'), 0xE6AB: ('EP2FIFOBCH', 'EP2 FIFO total byte count H'), 0xE6AC: ('EP2FIFOBCL', 'EP2 FIFO total byte count L'), 0xE6AD: ('EP4FIFOBCH', 'EP4 FIFO total byte count H'), 0xE6AE: ('EP4FIFOBCL', 'EP4 FIFO total byte count L'), 0xE6AF: ('EP6FIFOBCH', 'EP6 FIFO total byte count H'), 0xE6B0: ('EP6FIFOBCL', 'EP6 FIFO total byte count L'), 0xE6B1: ('EP8FIFOBCH', 'EP8 FIFO total byte count H'), 0xE6B2: ('EP8FIFOBCL', 'EP8 FIFO total byte count L'), 0xE6B3: ('SUDPTRH', 'Setup Data Pointer high address byte'), 0xE6B4: ('SUDPTRL', 'Setup Data Pointer low address byte'), 0xE6B5: ('SUDPTRCTL', 'Setup Data Pointer Auto Mode'), 0xE6B8: ('SETUPDAT[8]', '8 bytes of SETUP data'), 0xE6C0: ('GPIFWFSELECT', 'Waveform Selector'), 0xE6C1: ('GPIFIDLECS', 'GPIF Done, GPIF IDLE drive mode'), 0xE6C2: ('GPIFIDLECTL', 'Inactive Bus, CTL states'), 0xE6C3: ('GPIFCTLCFG', 'CTL OUT pin drive'), 0xE6C4: ('GPIFADRH', 'GPIF Address H'), 0xE6C5: ('GPIFADRL', 'GPIF Address L'), 0xE6CE: ('GPIFTCB3', 'GPIF Transaction Count Byte 3'), 0xE6CF: ('GPIFTCB2', 'GPIF Transaction Count Byte 2'), 0xE6D0: ('GPIFTCB1', 'GPIF Transaction Count Byte 1'), 0xE6D1: ('GPIFTCB0', 'GPIF Transaction Count Byte 0'), 0xE6D0: ('EP2GPIFTCH', 'EP2 GPIF Transaction Count High'), 0xE6D1: ('EP2GPIFTCL', 'EP2 GPIF Transaction Count Low'), 0xE6D2: ('EP2GPIFFLGSEL', 'EP2 GPIF Flag select'), 0xE6D3: ('EP2GPIFPFSTOP', 'Stop GPIF EP2 transaction on prog. flag'), 0xE6D4: ('EP2GPIFTRIG', 'EP2 FIFO Trigger'), 0xE6D8: ('EP4GPIFTCH', 'EP4 GPIF Transaction Count High'), 0xE6D9: ('EP4GPIFTCL', 'EP4 GPIF Transactionr Count Low'), 0xE6DA: ('EP4GPIFFLGSEL', 'EP4 GPIF Flag select'), 0xE6DB: ('EP4GPIFPFSTOP', 'Stop GPIF EP4 transaction on prog. flag'), 0xE6DC: ('EP4GPIFTRIG', 'EP4 FIFO Trigger'), 0xE6E0: ('EP6GPIFTCH', 'EP6 GPIF Transaction Count High'), 0xE6E1: ('EP6GPIFTCL', 'EP6 GPIF Transaction Count Low'), 0xE6E2: ('EP6GPIFFLGSEL', 'EP6 GPIF Flag select'), 0xE6E3: ('EP6GPIFPFSTOP', 'Stop GPIF EP6 transaction on prog. flag'), 0xE6E4: ('EP6GPIFTRIG', 'EP6 FIFO Trigger'), 0xE6E8: ('EP8GPIFTCH', 'EP8 GPIF Transaction Count High'), 0xE6E9: ('EP8GPIFTCL', 'EP8GPIF Transaction Count Low'), 0xE6EA: ('EP8GPIFFLGSEL', 'EP8 GPIF Flag select'), 0xE6EB: ('EP8GPIFPFSTOP', 'Stop GPIF EP8 transaction on prog. flag'), 0xE6EC: ('EP8GPIFTRIG', 'EP8 FIFO Trigger'), 0xE6F0: ('XGPIFSGLDATH', 'GPIF Data H (16-bit mode only)'), 0xE6F1: ('XGPIFSGLDATLX', 'Read/Write GPIF Data L & trigger transac'), 0xE6F2: ('XGPIFSGLDATLNOX', 'Read GPIF Data L, no transac trigger'), 0xE6F3: ('GPIFREADYCFG', 'Internal RDY,Sync/Async, RDY5CFG'), 0xE6F4: ('GPIFREADYSTAT', 'RDY pin states'), 0xE6F5: ('GPIFABORT', 'Abort GPIF cycles'), 0xE6C6: ('FLOWSTATE', 'Defines GPIF flow state'), 0xE6C7: ('FLOWLOGIC', 'Defines flow/hold decision criteria'), 0xE6C8: ('FLOWEQ0CTL', 'CTL states during active flow state'), 0xE6C9: ('FLOWEQ1CTL', 'CTL states during hold flow state'), 0xE6CA: ('FLOWHOLDOFF', ''), 0xE6CB: ('FLOWSTB', 'CTL/RDY Signal to use as master data strobe'), 0xE6CC: ('FLOWSTBEDGE', 'Defines active master strobe edge'), 0xE6CD: ('FLOWSTBHPERIOD', 'Half Period of output master strobe'), 0xE60C: ('GPIFHOLDAMOUNT', 'Data delay shift'), 0xE67D: ('UDMACRCH', 'CRC Upper byte'), 0xE67E: ('UDMACRCL', 'CRC Lower byte'), 0xE67F: ('UDMACRCQUAL', 'UDMA In only, host terminated use only'), 0xE6F8: ('DBUG', 'Debug'), 0xE6F9: ('TESTCFG', 'Test configuration'), 0xE6FA: ('USBTEST', 'USB Test Modes'), 0xE6FB: ('CT1', 'Chirp Test--Override'), 0xE6FC: ('CT2', 'Chirp Test--FSM'), 0xE6FD: ('CT3', 'Chirp Test--Control Signals'), 0xE6FE: ('CT4', 'Chirp Test--Inputs'), } def decode_FirmwareCommand(self, setup): direction = setup.bitmap & 0x80 != 0 address = setup.wValue length = setup.wLength setup.event.pushDecoded("FX2 %s at 0x%04x (%s)" % (('Write', 'Read')[direction], address, self.getAddressDescription(address))) def getAddressDescription(self, address): if address < 0x2000: return "Program Memory" if address < 0xE000: return "INVALID" if address < 0xE200: return "Scratch RAM" if address < 0xE400: return "RESERVED" if address < 0xE480: return "GPIF Waveforms" if address < 0xE600: return "RESERVED" if address < 0xE700: try: return "Register [%s] %s" % self.registerInfo[address] except KeyError: return "Unknown Register" if address < 0xE740: return "UNAVAILABLE" if address < 0xE780: return "EP0 Buffer" if address < 0xE800: return "EP1 Buffer" if address < 0xF000: return "RESERVED" return "EP2/4/6/8 Buffer"