# File generated from , with the command: # /home/henrichataing/Projects/github/google/pdl/pdl-compiler/scripts/generate_python_backend.py # /!\ Do not edit by hand. from dataclasses import dataclass, field, fields from typing import Optional, List, Tuple, Union import enum import inspect import math @dataclass class Packet: payload: Optional[bytes] = field(repr=False, default_factory=bytes, compare=False) @classmethod def parse_all(cls, span: bytes) -> 'Packet': packet, remain = getattr(cls, 'parse')(span) if len(remain) > 0: raise Exception('Unexpected parsing remainder') return packet @property def size(self) -> int: pass def show(self, prefix: str = ''): print(f'{self.__class__.__name__}') def print_val(p: str, pp: str, name: str, align: int, typ, val): if name == 'payload': pass # Scalar fields. elif typ is int: print(f'{p}{name:{align}} = {val} (0x{val:x})') # Byte fields. elif typ is bytes: print(f'{p}{name:{align}} = [', end='') line = '' n_pp = '' for (idx, b) in enumerate(val): if idx > 0 and idx % 8 == 0: print(f'{n_pp}{line}') line = '' n_pp = pp + (' ' * (align + 4)) line += f' {b:02x}' print(f'{n_pp}{line} ]') # Enum fields. elif inspect.isclass(typ) and issubclass(typ, enum.IntEnum): print(f'{p}{name:{align}} = {typ.__name__}::{val.name} (0x{val:x})') # Struct fields. elif inspect.isclass(typ) and issubclass(typ, globals().get('Packet')): print(f'{p}{name:{align}} = ', end='') val.show(prefix=pp) # Array fields. elif getattr(typ, '__origin__', None) == list: print(f'{p}{name:{align}}') last = len(val) - 1 align = 5 for (idx, elt) in enumerate(val): n_p = pp + ('├── ' if idx != last else '└── ') n_pp = pp + ('│ ' if idx != last else ' ') print_val(n_p, n_pp, f'[{idx}]', align, typ.__args__[0], val[idx]) # Custom fields. elif inspect.isclass(typ): print(f'{p}{name:{align}} = {repr(val)}') else: print(f'{p}{name:{align}} = ##{typ}##') last = len(fields(self)) - 1 align = max(len(f.name) for f in fields(self) if f.name != 'payload') for (idx, f) in enumerate(fields(self)): p = prefix + ('├── ' if idx != last else '└── ') pp = prefix + ('│ ' if idx != last else ' ') val = getattr(self, f.name) print_val(p, pp, f.name, align, f.type, val) class Technology(enum.IntEnum): NFC_A = 0x0 NFC_B = 0x1 NFC_F = 0x2 NFC_V = 0x3 RAW = 0x7 @staticmethod def from_int(v: int) -> Union[int, 'Technology']: try: return Technology(v) except ValueError as exn: raise exn class Protocol(enum.IntEnum): UNDETERMINED = 0x0 T1T = 0x1 T2T = 0x2 T3T = 0x3 ISO_DEP = 0x4 NFC_DEP = 0x5 T5T = 0x6 NDEF = 0x7 @staticmethod def from_int(v: int) -> Union[int, 'Protocol']: try: return Protocol(v) except ValueError as exn: raise exn class RfPacketType(enum.IntEnum): DATA = 0x0 POLL_COMMAND = 0x1 POLL_RESPONSE = 0x2 SELECT_COMMAND = 0x3 SELECT_RESPONSE = 0x4 DEACTIVATE_NOTIFICATION = 0x5 @staticmethod def from_int(v: int) -> Union[int, 'RfPacketType']: try: return RfPacketType(v) except ValueError as exn: raise exn @dataclass class RfPacket(Packet): sender: int = field(kw_only=True, default=0) receiver: int = field(kw_only=True, default=0) technology: Technology = field(kw_only=True, default=Technology.NFC_A) protocol: Protocol = field(kw_only=True, default=Protocol.UNDETERMINED) packet_type: RfPacketType = field(kw_only=True, default=RfPacketType.DATA) def __post_init__(self): pass @staticmethod def parse(span: bytes) -> Tuple['RfPacket', bytes]: fields = {'payload': None} if len(span) < 7: raise Exception('Invalid packet size') value_ = int.from_bytes(span[0:2], byteorder='little') fields['sender'] = value_ value_ = int.from_bytes(span[2:4], byteorder='little') fields['receiver'] = value_ fields['technology'] = Technology.from_int(span[4]) fields['protocol'] = Protocol.from_int(span[5]) fields['packet_type'] = RfPacketType.from_int(span[6]) span = span[7:] payload = span span = bytes([]) fields['payload'] = payload try: return PollCommand.parse(fields.copy(), payload) except Exception as exn: pass try: return NfcAPollResponse.parse(fields.copy(), payload) except Exception as exn: pass try: return T4ATSelectCommand.parse(fields.copy(), payload) except Exception as exn: pass try: return T4ATSelectResponse.parse(fields.copy(), payload) except Exception as exn: pass try: return NfcDepSelectCommand.parse(fields.copy(), payload) except Exception as exn: pass try: return NfcDepSelectResponse.parse(fields.copy(), payload) except Exception as exn: pass try: return SelectCommand.parse(fields.copy(), payload) except Exception as exn: pass try: return DeactivateNotification.parse(fields.copy(), payload) except Exception as exn: pass try: return Data.parse(fields.copy(), payload) except Exception as exn: pass return RfPacket(**fields), span def serialize(self, payload: bytes = None) -> bytes: _span = bytearray() if self.sender > 65535: print(f"Invalid value for field RfPacket::sender: {self.sender} > 65535; the value will be truncated") self.sender &= 65535 _span.extend(int.to_bytes((self.sender << 0), length=2, byteorder='little')) if self.receiver > 65535: print(f"Invalid value for field RfPacket::receiver: {self.receiver} > 65535; the value will be truncated") self.receiver &= 65535 _span.extend(int.to_bytes((self.receiver << 0), length=2, byteorder='little')) _span.append((self.technology << 0)) _span.append((self.protocol << 0)) _span.append((self.packet_type << 0)) _span.extend(payload or self.payload or []) return bytes(_span) @property def size(self) -> int: return len(self.payload) + 7 @dataclass class PollCommand(RfPacket): data : bytearray = field(kw_only=True, default_factory=bytearray) def __post_init__(self): self.packet_type = RfPacketType.POLL_COMMAND @staticmethod def parse(fields: dict, span: bytes) -> Tuple['PollCommand', bytes]: if fields['packet_type'] != RfPacketType.POLL_COMMAND: raise Exception("Invalid constraint field values") data = span[0:] fields['data'] = data return PollCommand(**fields), span def serialize(self, payload: bytes = None) -> bytes: _span = bytearray() _span.extend(self.data) return RfPacket.serialize(self, payload = bytes(_span)) @property def size(self) -> int: return len(self.data) @dataclass class NfcAPollResponse(RfPacket): nfcid1: bytearray = field(kw_only=True, default_factory=bytearray) int_protocol: int = field(kw_only=True, default=0) bit_frame_sdd: int = field(kw_only=True, default=0) def __post_init__(self): self.technology = Technology.NFC_A self.packet_type = RfPacketType.POLL_RESPONSE @staticmethod def parse(fields: dict, span: bytes) -> Tuple['NfcAPollResponse', bytes]: if fields['technology'] != Technology.NFC_A or fields['packet_type'] != RfPacketType.POLL_RESPONSE: raise Exception("Invalid constraint field values") if len(span) < 1: raise Exception('Invalid packet size') nfcid1_size = span[0] span = span[1:] if len(span) < nfcid1_size: raise Exception('Invalid packet size') fields['nfcid1'] = list(span[:nfcid1_size]) span = span[nfcid1_size:] if len(span) < 2: raise Exception('Invalid packet size') fields['int_protocol'] = (span[0] >> 0) & 0x3 fields['bit_frame_sdd'] = span[1] span = span[2:] return NfcAPollResponse(**fields), span def serialize(self, payload: bytes = None) -> bytes: _span = bytearray() _span.append(((len(self.nfcid1) * 1) << 0)) _span.extend(self.nfcid1) if self.int_protocol > 3: print(f"Invalid value for field NfcAPollResponse::int_protocol: {self.int_protocol} > 3; the value will be truncated") self.int_protocol &= 3 _span.append((self.int_protocol << 0)) if self.bit_frame_sdd > 255: print(f"Invalid value for field NfcAPollResponse::bit_frame_sdd: {self.bit_frame_sdd} > 255; the value will be truncated") self.bit_frame_sdd &= 255 _span.append((self.bit_frame_sdd << 0)) return RfPacket.serialize(self, payload = bytes(_span)) @property def size(self) -> int: return len(self.nfcid1) * 1 + 3 @dataclass class T4ATSelectCommand(RfPacket): param: int = field(kw_only=True, default=0) def __post_init__(self): self.technology = Technology.NFC_A self.protocol = Protocol.ISO_DEP self.packet_type = RfPacketType.SELECT_COMMAND @staticmethod def parse(fields: dict, span: bytes) -> Tuple['T4ATSelectCommand', bytes]: if fields['technology'] != Technology.NFC_A or fields['protocol'] != Protocol.ISO_DEP or fields['packet_type'] != RfPacketType.SELECT_COMMAND: raise Exception("Invalid constraint field values") if len(span) < 1: raise Exception('Invalid packet size') fields['param'] = span[0] span = span[1:] return T4ATSelectCommand(**fields), span def serialize(self, payload: bytes = None) -> bytes: _span = bytearray() if self.param > 255: print(f"Invalid value for field T4ATSelectCommand::param: {self.param} > 255; the value will be truncated") self.param &= 255 _span.append((self.param << 0)) return RfPacket.serialize(self, payload = bytes(_span)) @property def size(self) -> int: return 1 @dataclass class T4ATSelectResponse(RfPacket): rats_response: bytearray = field(kw_only=True, default_factory=bytearray) def __post_init__(self): self.technology = Technology.NFC_A self.protocol = Protocol.ISO_DEP self.packet_type = RfPacketType.SELECT_RESPONSE @staticmethod def parse(fields: dict, span: bytes) -> Tuple['T4ATSelectResponse', bytes]: if fields['technology'] != Technology.NFC_A or fields['protocol'] != Protocol.ISO_DEP or fields['packet_type'] != RfPacketType.SELECT_RESPONSE: raise Exception("Invalid constraint field values") if len(span) < 1: raise Exception('Invalid packet size') rats_response_size = span[0] span = span[1:] if len(span) < rats_response_size: raise Exception('Invalid packet size') fields['rats_response'] = list(span[:rats_response_size]) span = span[rats_response_size:] return T4ATSelectResponse(**fields), span def serialize(self, payload: bytes = None) -> bytes: _span = bytearray() _span.append(((len(self.rats_response) * 1) << 0)) _span.extend(self.rats_response) return RfPacket.serialize(self, payload = bytes(_span)) @property def size(self) -> int: return len(self.rats_response) * 1 + 1 @dataclass class NfcDepSelectCommand(RfPacket): lr: int = field(kw_only=True, default=0) def __post_init__(self): self.protocol = Protocol.NFC_DEP self.packet_type = RfPacketType.SELECT_COMMAND @staticmethod def parse(fields: dict, span: bytes) -> Tuple['NfcDepSelectCommand', bytes]: if fields['protocol'] != Protocol.NFC_DEP or fields['packet_type'] != RfPacketType.SELECT_COMMAND: raise Exception("Invalid constraint field values") if len(span) < 1: raise Exception('Invalid packet size') fields['lr'] = (span[0] >> 0) & 0x3 span = span[1:] return NfcDepSelectCommand(**fields), span def serialize(self, payload: bytes = None) -> bytes: _span = bytearray() if self.lr > 3: print(f"Invalid value for field NfcDepSelectCommand::lr: {self.lr} > 3; the value will be truncated") self.lr &= 3 _span.append((self.lr << 0)) return RfPacket.serialize(self, payload = bytes(_span)) @property def size(self) -> int: return 1 @dataclass class NfcDepSelectResponse(RfPacket): atr_response: bytearray = field(kw_only=True, default_factory=bytearray) def __post_init__(self): self.protocol = Protocol.NFC_DEP self.packet_type = RfPacketType.SELECT_RESPONSE @staticmethod def parse(fields: dict, span: bytes) -> Tuple['NfcDepSelectResponse', bytes]: if fields['protocol'] != Protocol.NFC_DEP or fields['packet_type'] != RfPacketType.SELECT_RESPONSE: raise Exception("Invalid constraint field values") if len(span) < 1: raise Exception('Invalid packet size') atr_response_size = span[0] span = span[1:] if len(span) < atr_response_size: raise Exception('Invalid packet size') fields['atr_response'] = list(span[:atr_response_size]) span = span[atr_response_size:] return NfcDepSelectResponse(**fields), span def serialize(self, payload: bytes = None) -> bytes: _span = bytearray() _span.append(((len(self.atr_response) * 1) << 0)) _span.extend(self.atr_response) return RfPacket.serialize(self, payload = bytes(_span)) @property def size(self) -> int: return len(self.atr_response) * 1 + 1 @dataclass class SelectCommand(RfPacket): def __post_init__(self): self.packet_type = RfPacketType.SELECT_COMMAND @staticmethod def parse(fields: dict, span: bytes) -> Tuple['SelectCommand', bytes]: if fields['packet_type'] != RfPacketType.SELECT_COMMAND: raise Exception("Invalid constraint field values") return SelectCommand(**fields), span def serialize(self, payload: bytes = None) -> bytes: _span = bytearray() return RfPacket.serialize(self, payload = bytes(_span)) @property def size(self) -> int: return 0 class DeactivateType(enum.IntEnum): IDLE_MODE = 0x0 SLEEP_MODE = 0x1 SLEEP_AF_MODE = 0x2 DISCOVERY = 0x3 @staticmethod def from_int(v: int) -> Union[int, 'DeactivateType']: try: return DeactivateType(v) except ValueError as exn: raise exn class DeactivateReason(enum.IntEnum): DH_REQUEST = 0x0 ENDPOINT_REQUEST = 0x1 RF_LINK_LOSS = 0x2 NFC_B_BAD_AFI = 0x3 DH_REQUEST_FAILED = 0x4 @staticmethod def from_int(v: int) -> Union[int, 'DeactivateReason']: try: return DeactivateReason(v) except ValueError as exn: raise exn @dataclass class DeactivateNotification(RfPacket): type_: DeactivateType = field(kw_only=True, default=DeactivateType.IDLE_MODE) reason: DeactivateReason = field(kw_only=True, default=DeactivateReason.DH_REQUEST) def __post_init__(self): self.packet_type = RfPacketType.DEACTIVATE_NOTIFICATION @staticmethod def parse(fields: dict, span: bytes) -> Tuple['DeactivateNotification', bytes]: if fields['packet_type'] != RfPacketType.DEACTIVATE_NOTIFICATION: raise Exception("Invalid constraint field values") if len(span) < 2: raise Exception('Invalid packet size') fields['type_'] = DeactivateType.from_int(span[0]) fields['reason'] = DeactivateReason.from_int(span[1]) span = span[2:] return DeactivateNotification(**fields), span def serialize(self, payload: bytes = None) -> bytes: _span = bytearray() _span.append((self.type_ << 0)) _span.append((self.reason << 0)) return RfPacket.serialize(self, payload = bytes(_span)) @property def size(self) -> int: return 2 @dataclass class Data(RfPacket): data: bytearray = field(kw_only=True, default_factory=bytearray) def __post_init__(self): self.packet_type = RfPacketType.DATA @staticmethod def parse(fields: dict, span: bytes) -> Tuple['Data', bytes]: if fields['packet_type'] != RfPacketType.DATA: raise Exception("Invalid constraint field values") fields['data'] = list(span) span = bytes() return Data(**fields), span def serialize(self, payload: bytes = None) -> bytes: _span = bytearray() _span.extend(self.data) return RfPacket.serialize(self, payload = bytes(_span)) @property def size(self) -> int: return len(self.data) * 1