Source code for usb_protocol.types

# -*- coding: utf-8 -*-
#
# This file is part of usb-protocol.
#
""" USB types -- defines enumerations that describe standard USB types """

from enum import IntEnum, IntFlag


[docs] class USBDirection(IntEnum): """ Class representing USB directions. """ OUT = 0 IN = 1
[docs] def is_in(self): return self is self.IN
[docs] def is_out(self): return self is self.OUT
[docs] @classmethod def parse(cls, value): """ Helper that converts a numeric field into a direction. """ return cls(value)
[docs] @classmethod def from_request_type(cls, request_type_int): """ Helper method that extracts the direction from a request_type integer. """ return cls(request_type_int >> 7)
[docs] @classmethod def from_endpoint_address(cls, address): """ Helper method that extracts the direction from an endpoint address. """ return cls(address >> 7)
[docs] def token(self): """ Generates the token corresponding to the given direction. """ return USBPacketID.IN if (self is self.IN) else USBPacketID.OUT
[docs] def reverse(self): """ Returns the reverse of the given direction. """ return self.OUT if (self is self.IN) else self.IN
[docs] def to_endpoint_address(self, endpoint_number): """ Helper method that converts and endpoint_number to an address, given direction. """ if self.is_in(): return endpoint_number | (1 << 7) else: return endpoint_number
[docs] class USBPIDCategory(IntFlag): """ Category constants for each of the groups that PIDs can fall under. """ SPECIAL = 0b00 TOKEN = 0b01 HANDSHAKE = 0b10 DATA = 0b11 MASK = 0b11
[docs] class USBPacketID(IntFlag): """ Enumeration specifying all of the valid USB PIDs we can handle. """ # Token group (lsbs = 0b01). OUT = 0b0001 IN = 0b1001 SOF = 0b0101 SETUP = 0b1101 # Data group (lsbs = 0b11). DATA0 = 0b0011 DATA1 = 0b1011 DATA2 = 0b0111 MDATA = 0b1111 # Handshake group (lsbs = 0b10) ACK = 0b0010 NAK = 0b1010 STALL = 0b1110 NYET = 0b0110 # Special group. PRE = 0b1100 ERR = 0b1100 SPLIT = 0b1000 PING = 0b0100 # Flag representing that the PID seems invalid. PID_INVALID = 0b10000 PID_CORE_MASK = 0b01111
[docs] @classmethod def from_byte(cls, byte, skip_checks=False): """ Creates a PID object from a byte. """ # Convert the raw PID to an integer. pid_as_int = int.from_bytes(byte, byteorder='little') return cls.from_int(pid_as_int, skip_checks=skip_checks)
[docs] @classmethod def from_int(cls, value, skip_checks=True): """ Create a PID object from an integer. """ PID_MASK = 0b1111 INVERTED_PID_SHIFT = 4 # Pull out the PID and its inverse from the byte. pid = cls(value & PID_MASK) inverted_pid = value >> INVERTED_PID_SHIFT # If we're not skipping checks, if not skip_checks: if (pid ^ inverted_pid) != PID_MASK: pid |= cls.PID_INVALID return cls(pid)
[docs] @classmethod def from_name(cls, name): """ Create a PID object from a string representation of its name. """ return cls[name]
[docs] @classmethod def parse(cls, value): """ Attempt to create a PID object from a number, byte, or string. """ if isinstance(value, bytes): return cls.from_byte(value) if isinstance(value, str): return cls.from_name(value) if isinstance(value, int): return cls.from_int(value) return cls(value)
[docs] def category(self): """ Returns the USBPIDCategory that each given PID belongs to. """ return USBPIDCategory(self & USBPIDCategory.MASK)
[docs] def is_data(self): """ Returns true iff the given PID represents a DATA packet. """ return self.category() is USBPIDCategory.DATA
[docs] def is_token(self): """ Returns true iff the given PID represents a token packet. """ return self.category() is USBPIDCategory.TOKEN
[docs] def is_handshake(self): """ Returns true iff the given PID represents a handshake packet. """ return self.category() is USBPIDCategory.HANDSHAKE
[docs] def is_invalid(self): """ Returns true if this object is an attempt to encapsulate an invalid PID. """ return (self & self.PID_INVALID)
[docs] def direction(self): """ Get a USB direction from a PacketID. """ if self is self.SOF: return None if self is self.SETUP or self is self.OUT: return USBDirection.OUT if self is self.IN: return USBDirection.IN raise ValueError("cannot determine the direction of a non-token PID")
[docs] def summarize(self): """ Return a summary of the given packet. """ # By default, get the raw name. core_pid = self & self.PID_CORE_MASK name = core_pid.name if self.is_invalid(): return "{} (check-nibble invalid)".format(name) else: return name
[docs] def byte(self): """ Return the PID's value with its upper nibble. """ inverted_pid = int(self) ^ 0b1111 full_pid = (inverted_pid << 4) | int(self) return full_pid
[docs] class USBRequestRecipient(IntEnum): """ Enumeration that describes each 'recipient' of a USB request field. """ DEVICE = 0 INTERFACE = 1 ENDPOINT = 2 OTHER = 3 RESERVED = 4
[docs] @classmethod def from_integer(cls, value): """ Special factory that correctly handles reserved values. """ # If we have one of the reserved values; indicate so. if 4 <= value < 16: return cls.RESERVED # Otherwise, translate the raw value. return cls(value)
[docs] @classmethod def from_request_type(cls, request_type_int): """ Helper method that extracts the type from a request_type integer. """ MASK = 0b11111 return cls(request_type_int & MASK)
[docs] class USBRequestType(IntEnum): """ Enumeration that describes each possible Type field for a USB request. """ STANDARD = 0 CLASS = 1 VENDOR = 2 RESERVED = 3
[docs] @classmethod def from_request_type(cls, request_type_int): """ Helper method that extracts the type from a request_type integer. """ SHIFT = 5 MASK = 0b11 return cls((request_type_int >> SHIFT) & MASK)
[docs] class USBTransferType(IntEnum): CONTROL = 0 ISOCHRONOUS = 1 BULK = 2 INTERRUPT = 3
[docs] def endpoint_number_from_address(number): return number & 0x7F
LANGUAGE_NAMES = { 0x0436: "Afrikaans", 0x041c: "Albanian", 0x0401: "Arabic (Saudi Arabia)", 0x0801: "Arabic (Iraq)", 0x0c01: "Arabic (Egypt)", 0x1001: "Arabic (Libya)", 0x1401: "Arabic (Algeria)", 0x1801: "Arabic (Morocco)", 0x1c01: "Arabic (Tunisia)", 0x2001: "Arabic (Oman)", 0x2401: "Arabic (Yemen)", 0x2801: "Arabic (Syria)", 0x2c01: "Arabic (Jordan)", 0x3001: "Arabic (Lebanon)", 0x3401: "Arabic (Kuwait)", 0x3801: "Arabic (U.A.E.)", 0x3c01: "Arabic (Bahrain)", 0x4001: "Arabic (Qatar)", 0x042b: "Armenian", 0x044d: "Assamese", 0x042c: "Azeri (Latin)", 0x082c: "Azeri (Cyrillic)", 0x042d: "Basque", 0x0423: "Belarussian", 0x0445: "Bengali", 0x0402: "Bulgarian", 0x0455: "Burmese", 0x0403: "Catalan", 0x0404: "Chinese (Taiwan)", 0x0804: "Chinese (PRC)", 0x0c04: "Chinese (Hong Kong SAR, PRC)", 0x1004: "Chinese (Singapore)", 0x1404: "Chinese (Macau SAR)", 0x041a: "Croatian", 0x0405: "Czech", 0x0406: "Danish", 0x0413: "Dutch (Netherlands)", 0x0813: "Dutch (Belgium)", 0x0409: "English (US)", 0x0809: "English (United Kingdom)", 0x0c09: "English (Australian)", 0x1009: "English (Canadian)", 0x1409: "English (New Zealand)", 0x1809: "English (Ireland)", 0x1c09: "English (South Africa)", 0x2009: "English (Jamaica)", 0x2409: "English (Caribbean)", 0x2809: "English (Belize)", 0x2c09: "English (Trinidad)", 0x3009: "English (Zimbabwe)", 0x3409: "English (Philippines)", 0x0425: "Estonian", 0x0438: "Faeroese", 0x0429: "Farsi", 0x040b: "Finnish", 0x040c: "French (Standard)", 0x080c: "French (Belgian)", 0x0c0c: "French (Canadian)", 0x100c: "French (Switzerland)", 0x140c: "French (Luxembourg)", 0x180c: "French (Monaco)", 0x0437: "Georgian", 0x0407: "German (Standard)", 0x0807: "German (Switzerland)", 0x0c07: "German (Austria)", 0x1007: "German (Luxembourg)", 0x1407: "German (Liechtenstein)", 0x0408: "Greek", 0x0447: "Gujarati", 0x040d: "Hebrew", 0x0439: "Hindi", 0x040e: "Hungarian", 0x040f: "Icelandic", 0x0421: "Indonesian", 0x0410: "Italian (Standard)", 0x0810: "Italian (Switzerland)", 0x0411: "Japanese", 0x044b: "Kannada", 0x0860: "Kashmiri (India)", 0x043f: "Kazakh", 0x0457: "Konkani", 0x0412: "Korean", 0x0812: "Korean (Johab)", 0x0426: "Latvian", 0x0427: "Lithuanian", 0x0827: "Lithuanian (Classic)", 0x042f: "Macedonian", 0x043e: "Malay (Malaysian)", 0x083e: "Malay (Brunei Darussalam)", 0x044c: "Malayalam", 0x0458: "Manipuri", 0x044e: "Marathi", 0x0861: "Nepali (India)", 0x0414: "Norwegian (Bokmal)", 0x0814: "Norwegian (Nynorsk)", 0x0448: "Oriya", 0x0415: "Polish", 0x0416: "Portuguese (Brazil)", 0x0816: "Portuguese (Standard)", 0x0446: "Punjabi", 0x0418: "Romanian", 0x0419: "Russian", 0x044f: "Sanskrit", 0x0c1a: "Serbian (Cyrillic)", 0x081a: "Serbian (Latin)", 0x0459: "Sindhi", 0x041b: "Slovak", 0x0424: "Slovenian", 0x040a: "Spanish (Traditional Sort)", 0x080a: "Spanish (Mexican)", 0x0c0a: "Spanish (Modern Sort)", 0x100a: "Spanish (Guatemala)", 0x140a: "Spanish (Costa Rica)", 0x180a: "Spanish (Panama)", 0x1c0a: "Spanish (Dominican Republic)", 0x200a: "Spanish (Venezuela)", 0x240a: "Spanish (Colombia)", 0x280a: "Spanish (Peru)", 0x2c0a: "Spanish (Argentina)", 0x300a: "Spanish (Ecuador)", 0x340a: "Spanish (Chile)", 0x380a: "Spanish (Uruguay)", 0x3c0a: "Spanish (Paraguay)", 0x400a: "Spanish (Bolivia)", 0x440a: "Spanish (El Salvador)", 0x480a: "Spanish (Honduras)", 0x4c0a: "Spanish (Nicaragua)", 0x500a: "Spanish (Puerto Rico)", 0x0430: "Sutu", 0x0441: "Swahili (Kenya)", 0x041d: "Swedish", 0x081d: "Swedish (Finland)", 0x0449: "Tamil", 0x0444: "Tatar (Tatarstan)", 0x044a: "Telugu", 0x041e: "Thai", 0x041f: "Turkish", 0x0422: "Ukrainian", 0x0420: "Urdu (Pakistan)", 0x0820: "Urdu (India)", 0x0443: "Uzbek (Latin)", 0x0843: "Uzbek (Cyrillic)", 0x042a: "Vietnamese", 0x04ff: "HID (Usage Data Descriptor)", 0xf0ff: "HID (Vendor Defined 1)", 0xf4ff: "HID (Vendor Defined 2)", 0xf8ff: "HID (Vendor Defined 3)", 0xfcff: "HID (Vendor Defined 4)", }
[docs] class LanguageIDs(IntEnum): AFRIKAANS = 0X0436 ALBANIAN = 0X041C ARABIC_SAUDI_ARABIA = 0X0401 ARABIC_IRAQ = 0X0801 ARABIC_EGYPT = 0X0C01 ARABIC_LIBYA = 0X1001 ARABIC_ALGERIA = 0X1401 ARABIC_MOROCCO = 0X1801 ARABIC_TUNISIA = 0X1C01 ARABIC_OMAN = 0X2001 ARABIC_YEMEN = 0X2401 ARABIC_SYRIA = 0X2801 ARABIC_JORDAN = 0X2C01 ARABIC_LEBANON = 0X3001 ARABIC_KUWAIT = 0X3401 ARABIC_UAE = 0X3801 ARABIC_BAHRAIN = 0X3C01 ARABIC_QATAR = 0X4001 ARMENIAN = 0X042B ASSAMESE = 0X044D AZERI_LATIN = 0X042C AZERI_CYRILLIC = 0X082C BASQUE = 0X042D BELARUSSIAN = 0X0423 BENGALI = 0X0445 BULGARIAN = 0X0402 BURMESE = 0X0455 CATALAN = 0X0403 CHINESE_TAIWAN = 0X0404 CHINESE_PRC = 0X0804 CHINESE_HONG_KONG = 0X0C04 CHINESE_SINGAPORE = 0X1004 CHINESE_MACAU_SAR = 0X1404 CROATIAN = 0X041A CZECH = 0X0405 DANISH = 0X0406 DUTCH_NETHERLANDS = 0X0413 DUTCH_BELGIUM = 0X0813 ENGLISH_US = 0X0409 ENGLISH_UNITED_KINGDOM = 0X0809 ENGLISH_AUSTRALIAN = 0X0C09 ENGLISH_CANADIAN = 0X1009 ENGLISH_NEW_ZEALAND = 0X1409 ENGLISH_IRELAND = 0X1809 ENGLISH_SOUTH_AFRICA = 0X1C09 ENGLISH_JAMAICA = 0X2009 ENGLISH_CARIBBEAN = 0X2409 ENGLISH_BELIZE = 0X2809 ENGLISH_TRINIDAD = 0X2C09 ENGLISH_ZIMBABWE = 0X3009 ENGLISH_PHILIPPINES = 0X3409 ESTONIAN = 0X0425 FAEROESE = 0X0438 FARSI = 0X0429 FINNISH = 0X040B FRENCH_STANDARD = 0X040C FRENCH_BELGIAN = 0X080C FRENCH_CANADIAN = 0X0C0C FRENCH_SWITZERLAND = 0X100C FRENCH_LUXEMBOURG = 0X140C FRENCH_MONACO = 0X180C GEORGIAN = 0X0437 GERMAN_STANDARD = 0X0407 GERMAN_SWITZERLAND = 0X0807 GERMAN_AUSTRIA = 0X0C07 GERMAN_LUXEMBOURG = 0X1007 GERMAN_LIECHTENSTEIN = 0X1407 GREEK = 0X0408 GUJARATI = 0X0447 HEBREW = 0X040D HINDI = 0X0439 HUNGARIAN = 0X040E ICELANDIC = 0X040F INDONESIAN = 0X0421 ITALIAN_STANDARD = 0X0410 ITALIAN_SWITZERLAND = 0X0810 JAPANESE = 0X0411 KANNADA = 0X044B KASHMIRI_INDIA = 0X0860 KAZAKH = 0X043F KONKANI = 0X0457 KOREAN = 0X0412 KOREAN_JOHAB = 0X0812 LATVIAN = 0X0426 LITHUANIAN = 0X0427 LITHUANIAN_CLASSIC = 0X0827 MACEDONIAN = 0X042F MALAY_MALAYSIAN = 0X043E MALAY_BRUNEI_DARUSSALAM = 0X083E MALAYALAM = 0X044C MANIPURI = 0X0458 MARATHI = 0X044E NEPALI_INDIA = 0X0861 NORWEGIAN_BOKMAL = 0X0414 NORWEGIAN_NYNORSK = 0X0814 ORIYA = 0X0448 POLISH = 0X0415 PORTUGUESE_BRAZIL = 0X0416 PORTUGUESE_STANDARD = 0X0816 PUNJABI = 0X0446 ROMANIAN = 0X0418 RUSSIAN = 0X0419 SANSKRIT = 0X044F SERBIAN_CYRILLIC = 0X0C1A SERBIAN_LATIN = 0X081A SINDHI = 0X0459 SLOVAK = 0X041B SLOVENIAN = 0X0424 SPANISH_TRADITIONAL_SORT = 0X040A SPANISH_MEXICAN = 0X080A SPANISH_MODERN_SORT = 0X0C0A SPANISH_GUATEMALA = 0X100A SPANISH_COSTA_RICA = 0X140A SPANISH_PANAMA = 0X180A SPANISH_DOMINICAN_REPUBLIC = 0X1C0A SPANISH_VENEZUELA = 0X200A SPANISH_COLOMBIA = 0X240A SPANISH_PERU = 0X280A SPANISH_ARGENTINA = 0X2C0A SPANISH_ECUADOR = 0X300A SPANISH_CHILE = 0X340A SPANISH_URUGUAY = 0X380A SPANISH_PARAGUAY = 0X3C0A SPANISH_BOLIVIA = 0X400A SPANISH_EL_SALVADOR = 0X440A SPANISH_HONDURAS = 0X480A SPANISH_NICARAGUA = 0X4C0A SPANISH_PUERTO_RICO = 0X500A SUTU = 0X0430 SWAHILI_KENYA = 0X0441 SWEDISH = 0X041D SWEDISH_FINLAND = 0X081D TAMIL = 0X0449 TATAR_TATARSTAN = 0X0444 TELUGU = 0X044A THAI = 0X041E TURKISH = 0X041F UKRAINIAN = 0X0422 URDU_PAKISTAN = 0X0420 URDU_INDIA = 0X0820 UZBEK_LATIN = 0X0443 UZBEK_CYRILLIC = 0X0843 VIETNAMESE = 0X042A HID_USAGE_DATA_DESCRIPTOR = 0X04FF HID_VENDOR_DEFINED_1 = 0XF0FF HID_VENDOR_DEFINED_2 = 0XF4FF HID_VENDOR_DEFINED_3 = 0XF8FF HID_VENDOR_DEFINED_4 = 0XFCFF
[docs] class DescriptorTypes(IntEnum): DEVICE = 1 CONFIGURATION = 2 STRING = 3 INTERFACE = 4 ENDPOINT = 5 DEVICE_QUALIFIER = 6 OTHER_SPEED_CONFIGURATION = 7 INTERFACE_POWER = 8 HID = 33 REPORT = 34
[docs] class USBSynchronizationType(IntEnum): NONE = 0x00 ASYNC = 0x01 ADAPTIVE = 0x02 SYNCHRONOUS = 0x03
[docs] class USBUsageType(IntEnum): DATA = 0 FEEDBACK = 1 IMPLICIT_FEEDBACK = 2
[docs] class USBStandardRequests(IntEnum): GET_STATUS = 0 CLEAR_FEATURE = 1 SET_FEATURE = 3 SET_ADDRESS = 5 GET_DESCRIPTOR = 6 SET_DESCRIPTOR = 7 GET_CONFIGURATION = 8 SET_CONFIGURATION = 9 GET_INTERFACE = 10 SET_INTERFACE = 11 SYNCH_FRAME = 12 # USB3 only. SET_ENCRYPTION = 13 GET_ENCRYPTION = 14 SET_HANDSHAKE = 15 GET_HANDSHAKE = 16 SET_CONNECTION = 17 SET_SECURITY_DATA = 18 GET_SECURITY_DATA = 19 SET_WUSB_DATA = 20 LOOPBACK_DATA_WRITE = 21 LOOPBACK_DATA_READ = 22 SET_INTERFACE_DS = 23 SET_SEL = 48 SET_ISOCH_DELAY = 49