#!/usr/bin/env python3
from enum import IntEnum
[docs]class PID(IntEnum):
# USB Packet IDs
"""
>>> bin(PID.SETUP.value)
'0b1101'
>>> PID.SETUP.encode()
'KKKKJJJJJJJJJJJJKKKKKKKKJJJJKKKK'
>>> for p in PID:
... print("%-10s" % p, "%x" % p.value, "%02x" % p.byte(), p.encode(1))
PID.SETUP d 2d KJJJKKJK
PID.OUT 1 e1 KJKJKKKK
PID.IN 9 69 KJKKJJJK
PID.SOF 5 a5 KJJKJJKK
PID.DATA0 3 c3 KKJKJKKK
PID.DATA1 b 4b KKJJKJJK
PID.DATA2 7 87 KKKJKJKK
PID.MDATA f 0f KKKKJKJK
PID.ACK 2 d2 JJKJJKKK
PID.NAK a 5a JJKKKJJK
PID.STALL e 1e JJJJJKJK
PID.NYET 6 96 JJJKKJKK
PID.PRE c 3c JKKKKKJK
PID.SPLIT 8 78 JKJJJJJK
PID.PING 4 b4 JKKJJJKK
PID.RESERVED 0 f0 JKJKKKKK
"""
# Token pids
SETUP = 0b1101 # D
OUT = 0b0001 # 1
IN = 0b1001 # 9
SOF = 0b0101 # 5
# Data pid
DATA0 = 0b0011 # 3
DATA1 = 0b1011 # B
# USB HS only
DATA2 = 0b0111 # B
MDATA = 0b1111 # F
# Handshake pids
ACK = 0b0010 # 2
NAK = 0b1010 # A
STALL = 0b1110 # E
# USB HS only
NYET = 0b0110 # 6
# USB HS only
PRE = 0b1100 # C
ERR = 0b1100 # C
SPLIT = 0b1000 # 8
PING = 0b0100 # 4
RESERVED = 0b0000 # 0
[docs] def byte(self):
v = self.value
return v | ((0b1111 ^ v) << 4)
[docs] def encode(self, cycles=4):
# Prevent cyclic imports by importing here...
from .utils.packet import nrzi, sync, encode_pid
return nrzi(sync()+encode_pid(self.value),cycles)[cycles*len(sync()):]
[docs]class PIDTypes(IntEnum):
"""
>>> # Token PIDs
>>> PIDTypes.token(PID.SETUP), PIDTypes.data(PID.SETUP), PIDTypes.handshake(PID.SETUP)
(True, False, False)
>>> PIDTypes.token(PID.OUT), PIDTypes.data(PID.OUT), PIDTypes.handshake(PID.OUT)
(True, False, False)
>>> PIDTypes.token(PID.IN), PIDTypes.data(PID.IN), PIDTypes.handshake(PID.IN)
(True, False, False)
>>> PIDTypes.token(PID.SOF), PIDTypes.data(PID.SOF), PIDTypes.handshake(PID.SOF)
(True, False, False)
>>> # Data PIDs
>>> PIDTypes.token(PID.DATA0), PIDTypes.data(PID.DATA0), PIDTypes.handshake(PID.DATA0)
(False, True, False)
>>> PIDTypes.token(PID.DATA1), PIDTypes.data(PID.DATA1), PIDTypes.handshake(PID.DATA1)
(False, True, False)
>>> # USB2.0 Data PIDs
>>> PIDTypes.token(PID.DATA2), PIDTypes.data(PID.DATA2), PIDTypes.handshake(PID.DATA2)
(False, True, False)
>>> PIDTypes.token(PID.MDATA), PIDTypes.data(PID.MDATA), PIDTypes.handshake(PID.MDATA)
(False, True, False)
>>> # Handshake PIDs
>>> PIDTypes.token(PID.ACK), PIDTypes.data(PID.ACK), PIDTypes.handshake(PID.ACK)
(False, False, True)
>>> PIDTypes.token(PID.NAK), PIDTypes.data(PID.NAK), PIDTypes.handshake(PID.NAK)
(False, False, True)
>>> PIDTypes.token(PID.STALL), PIDTypes.data(PID.STALL), PIDTypes.handshake(PID.STALL)
(False, False, True)
>>> # USB2.0 Handshake PIDs
>>> PIDTypes.token(PID.NYET), PIDTypes.data(PID.NYET), PIDTypes.handshake(PID.NYET)
(False, False, True)
>>> # Special PIDs
>>> PIDTypes.token(PID.PRE), PIDTypes.data(PID.PRE), PIDTypes.handshake(PID.PRE)
(False, False, False)
"""
TOKEN = 0b0001
DATA = 0b0011
HANDSHAKE = 0b0010
SPECIAL = 0b0000
TYPE_MASK = 0b0011
[docs] @staticmethod
def token(p):
assert isinstance(p, PID), repr(p)
return (p & PIDTypes.TYPE_MASK) == PIDTypes.TOKEN
[docs] @staticmethod
def data(p):
assert isinstance(p, PID), repr(p)
return (p & PIDTypes.TYPE_MASK) == PIDTypes.DATA
[docs] @staticmethod
def handshake(p):
assert isinstance(p, PID), repr(p)
return (p & PIDTypes.TYPE_MASK) == PIDTypes.HANDSHAKE
[docs] @staticmethod
def special(p):
assert isinstance(p, PID), repr(p)
return (p & PIDTypes.TYPE_MASK) == PIDTypes.SPECIAL
if __name__ == "__main__":
import doctest
doctest.testmod()