1# File generated from <stdin>, with the command: 2# /home/henrichataing/Projects/github/google/pdl/pdl-compiler/scripts/generate_python_backend.py 3# /!\ Do not edit by hand. 4from dataclasses import dataclass, field, fields 5from typing import Optional, List, Tuple, Union 6import enum 7import inspect 8import math 9 10@dataclass 11class Packet: 12 payload: Optional[bytes] = field(repr=False, default_factory=bytes, compare=False) 13 14 @classmethod 15 def parse_all(cls, span: bytes) -> 'Packet': 16 packet, remain = getattr(cls, 'parse')(span) 17 if len(remain) > 0: 18 raise Exception('Unexpected parsing remainder') 19 return packet 20 21 @property 22 def size(self) -> int: 23 pass 24 25 def show(self, prefix: str = ''): 26 print(f'{self.__class__.__name__}') 27 28 def print_val(p: str, pp: str, name: str, align: int, typ, val): 29 if name == 'payload': 30 pass 31 32 # Scalar fields. 33 elif typ is int: 34 print(f'{p}{name:{align}} = {val} (0x{val:x})') 35 36 # Byte fields. 37 elif typ is bytes: 38 print(f'{p}{name:{align}} = [', end='') 39 line = '' 40 n_pp = '' 41 for (idx, b) in enumerate(val): 42 if idx > 0 and idx % 8 == 0: 43 print(f'{n_pp}{line}') 44 line = '' 45 n_pp = pp + (' ' * (align + 4)) 46 line += f' {b:02x}' 47 print(f'{n_pp}{line} ]') 48 49 # Enum fields. 50 elif inspect.isclass(typ) and issubclass(typ, enum.IntEnum): 51 print(f'{p}{name:{align}} = {typ.__name__}::{val.name} (0x{val:x})') 52 53 # Struct fields. 54 elif inspect.isclass(typ) and issubclass(typ, globals().get('Packet')): 55 print(f'{p}{name:{align}} = ', end='') 56 val.show(prefix=pp) 57 58 # Array fields. 59 elif getattr(typ, '__origin__', None) == list: 60 print(f'{p}{name:{align}}') 61 last = len(val) - 1 62 align = 5 63 for (idx, elt) in enumerate(val): 64 n_p = pp + ('├── ' if idx != last else '└── ') 65 n_pp = pp + ('│ ' if idx != last else ' ') 66 print_val(n_p, n_pp, f'[{idx}]', align, typ.__args__[0], val[idx]) 67 68 # Custom fields. 69 elif inspect.isclass(typ): 70 print(f'{p}{name:{align}} = {repr(val)}') 71 72 else: 73 print(f'{p}{name:{align}} = ##{typ}##') 74 75 last = len(fields(self)) - 1 76 align = max(len(f.name) for f in fields(self) if f.name != 'payload') 77 78 for (idx, f) in enumerate(fields(self)): 79 p = prefix + ('├── ' if idx != last else '└── ') 80 pp = prefix + ('│ ' if idx != last else ' ') 81 val = getattr(self, f.name) 82 83 print_val(p, pp, f.name, align, f.type, val) 84 85class Technology(enum.IntEnum): 86 NFC_A = 0x0 87 NFC_B = 0x1 88 NFC_F = 0x2 89 NFC_V = 0x3 90 RAW = 0x7 91 92 @staticmethod 93 def from_int(v: int) -> Union[int, 'Technology']: 94 try: 95 return Technology(v) 96 except ValueError as exn: 97 raise exn 98 99 100class Protocol(enum.IntEnum): 101 UNDETERMINED = 0x0 102 T1T = 0x1 103 T2T = 0x2 104 T3T = 0x3 105 ISO_DEP = 0x4 106 NFC_DEP = 0x5 107 T5T = 0x6 108 NDEF = 0x7 109 110 @staticmethod 111 def from_int(v: int) -> Union[int, 'Protocol']: 112 try: 113 return Protocol(v) 114 except ValueError as exn: 115 raise exn 116 117 118class RfPacketType(enum.IntEnum): 119 DATA = 0x0 120 POLL_COMMAND = 0x1 121 POLL_RESPONSE = 0x2 122 SELECT_COMMAND = 0x3 123 SELECT_RESPONSE = 0x4 124 DEACTIVATE_NOTIFICATION = 0x5 125 126 @staticmethod 127 def from_int(v: int) -> Union[int, 'RfPacketType']: 128 try: 129 return RfPacketType(v) 130 except ValueError as exn: 131 raise exn 132 133 134@dataclass 135class RfPacket(Packet): 136 sender: int = field(kw_only=True, default=0) 137 receiver: int = field(kw_only=True, default=0) 138 technology: Technology = field(kw_only=True, default=Technology.NFC_A) 139 protocol: Protocol = field(kw_only=True, default=Protocol.UNDETERMINED) 140 packet_type: RfPacketType = field(kw_only=True, default=RfPacketType.DATA) 141 142 def __post_init__(self): 143 pass 144 145 @staticmethod 146 def parse(span: bytes) -> Tuple['RfPacket', bytes]: 147 fields = {'payload': None} 148 if len(span) < 7: 149 raise Exception('Invalid packet size') 150 value_ = int.from_bytes(span[0:2], byteorder='little') 151 fields['sender'] = value_ 152 value_ = int.from_bytes(span[2:4], byteorder='little') 153 fields['receiver'] = value_ 154 fields['technology'] = Technology.from_int(span[4]) 155 fields['protocol'] = Protocol.from_int(span[5]) 156 fields['packet_type'] = RfPacketType.from_int(span[6]) 157 span = span[7:] 158 payload = span 159 span = bytes([]) 160 fields['payload'] = payload 161 try: 162 return PollCommand.parse(fields.copy(), payload) 163 except Exception as exn: 164 pass 165 try: 166 return NfcAPollResponse.parse(fields.copy(), payload) 167 except Exception as exn: 168 pass 169 try: 170 return T4ATSelectCommand.parse(fields.copy(), payload) 171 except Exception as exn: 172 pass 173 try: 174 return T4ATSelectResponse.parse(fields.copy(), payload) 175 except Exception as exn: 176 pass 177 try: 178 return NfcDepSelectCommand.parse(fields.copy(), payload) 179 except Exception as exn: 180 pass 181 try: 182 return NfcDepSelectResponse.parse(fields.copy(), payload) 183 except Exception as exn: 184 pass 185 try: 186 return SelectCommand.parse(fields.copy(), payload) 187 except Exception as exn: 188 pass 189 try: 190 return DeactivateNotification.parse(fields.copy(), payload) 191 except Exception as exn: 192 pass 193 try: 194 return Data.parse(fields.copy(), payload) 195 except Exception as exn: 196 pass 197 return RfPacket(**fields), span 198 199 def serialize(self, payload: bytes = None) -> bytes: 200 _span = bytearray() 201 if self.sender > 65535: 202 print(f"Invalid value for field RfPacket::sender: {self.sender} > 65535; the value will be truncated") 203 self.sender &= 65535 204 _span.extend(int.to_bytes((self.sender << 0), length=2, byteorder='little')) 205 if self.receiver > 65535: 206 print(f"Invalid value for field RfPacket::receiver: {self.receiver} > 65535; the value will be truncated") 207 self.receiver &= 65535 208 _span.extend(int.to_bytes((self.receiver << 0), length=2, byteorder='little')) 209 _span.append((self.technology << 0)) 210 _span.append((self.protocol << 0)) 211 _span.append((self.packet_type << 0)) 212 _span.extend(payload or self.payload or []) 213 return bytes(_span) 214 215 @property 216 def size(self) -> int: 217 return len(self.payload) + 7 218 219@dataclass 220class PollCommand(RfPacket): 221 data : bytearray = field(kw_only=True, default_factory=bytearray) 222 223 def __post_init__(self): 224 self.packet_type = RfPacketType.POLL_COMMAND 225 226 @staticmethod 227 def parse(fields: dict, span: bytes) -> Tuple['PollCommand', bytes]: 228 if fields['packet_type'] != RfPacketType.POLL_COMMAND: 229 raise Exception("Invalid constraint field values") 230 data = span[0:] 231 fields['data'] = data 232 return PollCommand(**fields), span 233 234 def serialize(self, payload: bytes = None) -> bytes: 235 _span = bytearray() 236 _span.extend(self.data) 237 return RfPacket.serialize(self, payload = bytes(_span)) 238 239 @property 240 def size(self) -> int: 241 return len(self.data) 242 243@dataclass 244class NfcAPollResponse(RfPacket): 245 nfcid1: bytearray = field(kw_only=True, default_factory=bytearray) 246 int_protocol: int = field(kw_only=True, default=0) 247 bit_frame_sdd: int = field(kw_only=True, default=0) 248 249 def __post_init__(self): 250 self.technology = Technology.NFC_A 251 self.packet_type = RfPacketType.POLL_RESPONSE 252 253 @staticmethod 254 def parse(fields: dict, span: bytes) -> Tuple['NfcAPollResponse', bytes]: 255 if fields['technology'] != Technology.NFC_A or fields['packet_type'] != RfPacketType.POLL_RESPONSE: 256 raise Exception("Invalid constraint field values") 257 if len(span) < 1: 258 raise Exception('Invalid packet size') 259 nfcid1_size = span[0] 260 span = span[1:] 261 if len(span) < nfcid1_size: 262 raise Exception('Invalid packet size') 263 fields['nfcid1'] = list(span[:nfcid1_size]) 264 span = span[nfcid1_size:] 265 if len(span) < 2: 266 raise Exception('Invalid packet size') 267 fields['int_protocol'] = (span[0] >> 0) & 0x3 268 fields['bit_frame_sdd'] = span[1] 269 span = span[2:] 270 return NfcAPollResponse(**fields), span 271 272 def serialize(self, payload: bytes = None) -> bytes: 273 _span = bytearray() 274 _span.append(((len(self.nfcid1) * 1) << 0)) 275 _span.extend(self.nfcid1) 276 if self.int_protocol > 3: 277 print(f"Invalid value for field NfcAPollResponse::int_protocol: {self.int_protocol} > 3; the value will be truncated") 278 self.int_protocol &= 3 279 _span.append((self.int_protocol << 0)) 280 if self.bit_frame_sdd > 255: 281 print(f"Invalid value for field NfcAPollResponse::bit_frame_sdd: {self.bit_frame_sdd} > 255; the value will be truncated") 282 self.bit_frame_sdd &= 255 283 _span.append((self.bit_frame_sdd << 0)) 284 return RfPacket.serialize(self, payload = bytes(_span)) 285 286 @property 287 def size(self) -> int: 288 return len(self.nfcid1) * 1 + 3 289 290@dataclass 291class T4ATSelectCommand(RfPacket): 292 param: int = field(kw_only=True, default=0) 293 294 def __post_init__(self): 295 self.technology = Technology.NFC_A 296 self.protocol = Protocol.ISO_DEP 297 self.packet_type = RfPacketType.SELECT_COMMAND 298 299 @staticmethod 300 def parse(fields: dict, span: bytes) -> Tuple['T4ATSelectCommand', bytes]: 301 if fields['technology'] != Technology.NFC_A or fields['protocol'] != Protocol.ISO_DEP or fields['packet_type'] != RfPacketType.SELECT_COMMAND: 302 raise Exception("Invalid constraint field values") 303 if len(span) < 1: 304 raise Exception('Invalid packet size') 305 fields['param'] = span[0] 306 span = span[1:] 307 return T4ATSelectCommand(**fields), span 308 309 def serialize(self, payload: bytes = None) -> bytes: 310 _span = bytearray() 311 if self.param > 255: 312 print(f"Invalid value for field T4ATSelectCommand::param: {self.param} > 255; the value will be truncated") 313 self.param &= 255 314 _span.append((self.param << 0)) 315 return RfPacket.serialize(self, payload = bytes(_span)) 316 317 @property 318 def size(self) -> int: 319 return 1 320 321@dataclass 322class T4ATSelectResponse(RfPacket): 323 rats_response: bytearray = field(kw_only=True, default_factory=bytearray) 324 325 def __post_init__(self): 326 self.technology = Technology.NFC_A 327 self.protocol = Protocol.ISO_DEP 328 self.packet_type = RfPacketType.SELECT_RESPONSE 329 330 @staticmethod 331 def parse(fields: dict, span: bytes) -> Tuple['T4ATSelectResponse', bytes]: 332 if fields['technology'] != Technology.NFC_A or fields['protocol'] != Protocol.ISO_DEP or fields['packet_type'] != RfPacketType.SELECT_RESPONSE: 333 raise Exception("Invalid constraint field values") 334 if len(span) < 1: 335 raise Exception('Invalid packet size') 336 rats_response_size = span[0] 337 span = span[1:] 338 if len(span) < rats_response_size: 339 raise Exception('Invalid packet size') 340 fields['rats_response'] = list(span[:rats_response_size]) 341 span = span[rats_response_size:] 342 return T4ATSelectResponse(**fields), span 343 344 def serialize(self, payload: bytes = None) -> bytes: 345 _span = bytearray() 346 _span.append(((len(self.rats_response) * 1) << 0)) 347 _span.extend(self.rats_response) 348 return RfPacket.serialize(self, payload = bytes(_span)) 349 350 @property 351 def size(self) -> int: 352 return len(self.rats_response) * 1 + 1 353 354@dataclass 355class NfcDepSelectCommand(RfPacket): 356 lr: int = field(kw_only=True, default=0) 357 358 def __post_init__(self): 359 self.protocol = Protocol.NFC_DEP 360 self.packet_type = RfPacketType.SELECT_COMMAND 361 362 @staticmethod 363 def parse(fields: dict, span: bytes) -> Tuple['NfcDepSelectCommand', bytes]: 364 if fields['protocol'] != Protocol.NFC_DEP or fields['packet_type'] != RfPacketType.SELECT_COMMAND: 365 raise Exception("Invalid constraint field values") 366 if len(span) < 1: 367 raise Exception('Invalid packet size') 368 fields['lr'] = (span[0] >> 0) & 0x3 369 span = span[1:] 370 return NfcDepSelectCommand(**fields), span 371 372 def serialize(self, payload: bytes = None) -> bytes: 373 _span = bytearray() 374 if self.lr > 3: 375 print(f"Invalid value for field NfcDepSelectCommand::lr: {self.lr} > 3; the value will be truncated") 376 self.lr &= 3 377 _span.append((self.lr << 0)) 378 return RfPacket.serialize(self, payload = bytes(_span)) 379 380 @property 381 def size(self) -> int: 382 return 1 383 384@dataclass 385class NfcDepSelectResponse(RfPacket): 386 atr_response: bytearray = field(kw_only=True, default_factory=bytearray) 387 388 def __post_init__(self): 389 self.protocol = Protocol.NFC_DEP 390 self.packet_type = RfPacketType.SELECT_RESPONSE 391 392 @staticmethod 393 def parse(fields: dict, span: bytes) -> Tuple['NfcDepSelectResponse', bytes]: 394 if fields['protocol'] != Protocol.NFC_DEP or fields['packet_type'] != RfPacketType.SELECT_RESPONSE: 395 raise Exception("Invalid constraint field values") 396 if len(span) < 1: 397 raise Exception('Invalid packet size') 398 atr_response_size = span[0] 399 span = span[1:] 400 if len(span) < atr_response_size: 401 raise Exception('Invalid packet size') 402 fields['atr_response'] = list(span[:atr_response_size]) 403 span = span[atr_response_size:] 404 return NfcDepSelectResponse(**fields), span 405 406 def serialize(self, payload: bytes = None) -> bytes: 407 _span = bytearray() 408 _span.append(((len(self.atr_response) * 1) << 0)) 409 _span.extend(self.atr_response) 410 return RfPacket.serialize(self, payload = bytes(_span)) 411 412 @property 413 def size(self) -> int: 414 return len(self.atr_response) * 1 + 1 415 416@dataclass 417class SelectCommand(RfPacket): 418 419 420 def __post_init__(self): 421 self.packet_type = RfPacketType.SELECT_COMMAND 422 423 @staticmethod 424 def parse(fields: dict, span: bytes) -> Tuple['SelectCommand', bytes]: 425 if fields['packet_type'] != RfPacketType.SELECT_COMMAND: 426 raise Exception("Invalid constraint field values") 427 return SelectCommand(**fields), span 428 429 def serialize(self, payload: bytes = None) -> bytes: 430 _span = bytearray() 431 return RfPacket.serialize(self, payload = bytes(_span)) 432 433 @property 434 def size(self) -> int: 435 return 0 436 437class DeactivateType(enum.IntEnum): 438 IDLE_MODE = 0x0 439 SLEEP_MODE = 0x1 440 SLEEP_AF_MODE = 0x2 441 DISCOVERY = 0x3 442 443 @staticmethod 444 def from_int(v: int) -> Union[int, 'DeactivateType']: 445 try: 446 return DeactivateType(v) 447 except ValueError as exn: 448 raise exn 449 450 451class DeactivateReason(enum.IntEnum): 452 DH_REQUEST = 0x0 453 ENDPOINT_REQUEST = 0x1 454 RF_LINK_LOSS = 0x2 455 NFC_B_BAD_AFI = 0x3 456 DH_REQUEST_FAILED = 0x4 457 458 @staticmethod 459 def from_int(v: int) -> Union[int, 'DeactivateReason']: 460 try: 461 return DeactivateReason(v) 462 except ValueError as exn: 463 raise exn 464 465 466@dataclass 467class DeactivateNotification(RfPacket): 468 type_: DeactivateType = field(kw_only=True, default=DeactivateType.IDLE_MODE) 469 reason: DeactivateReason = field(kw_only=True, default=DeactivateReason.DH_REQUEST) 470 471 def __post_init__(self): 472 self.packet_type = RfPacketType.DEACTIVATE_NOTIFICATION 473 474 @staticmethod 475 def parse(fields: dict, span: bytes) -> Tuple['DeactivateNotification', bytes]: 476 if fields['packet_type'] != RfPacketType.DEACTIVATE_NOTIFICATION: 477 raise Exception("Invalid constraint field values") 478 if len(span) < 2: 479 raise Exception('Invalid packet size') 480 fields['type_'] = DeactivateType.from_int(span[0]) 481 fields['reason'] = DeactivateReason.from_int(span[1]) 482 span = span[2:] 483 return DeactivateNotification(**fields), span 484 485 def serialize(self, payload: bytes = None) -> bytes: 486 _span = bytearray() 487 _span.append((self.type_ << 0)) 488 _span.append((self.reason << 0)) 489 return RfPacket.serialize(self, payload = bytes(_span)) 490 491 @property 492 def size(self) -> int: 493 return 2 494 495@dataclass 496class Data(RfPacket): 497 data: bytearray = field(kw_only=True, default_factory=bytearray) 498 499 def __post_init__(self): 500 self.packet_type = RfPacketType.DATA 501 502 @staticmethod 503 def parse(fields: dict, span: bytes) -> Tuple['Data', bytes]: 504 if fields['packet_type'] != RfPacketType.DATA: 505 raise Exception("Invalid constraint field values") 506 fields['data'] = list(span) 507 span = bytes() 508 return Data(**fields), span 509 510 def serialize(self, payload: bytes = None) -> bytes: 511 _span = bytearray() 512 _span.extend(self.data) 513 return RfPacket.serialize(self, payload = bytes(_span)) 514 515 @property 516 def size(self) -> int: 517 return len(self.data) * 1 518