# Copyright 2023 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from dataclasses import dataclass, field from typing import Tuple @dataclass(init=False) class Address: address: bytes = field(default=bytes([0, 0, 0, 0, 0, 0])) def __init__(self, address=None): if not address: self.address = bytes([0, 0, 0, 0, 0, 0]) elif isinstance(address, Address): self.address = address.address elif isinstance(address, str): self.address = bytes([int(b, 16) for b in address.split(':')]) elif isinstance(address, (bytes, list)) and len(address) == 6: self.address = bytes(address) elif isinstance(address, bytes): address = address.decode('utf-8') self.address = bytes([int(b, 16) for b in address.split(':')]) else: raise Exception(f'unsupported address type: {address}') def parse(span: bytes) -> Tuple['Address', bytes]: assert len(span) >= 6 return (Address(bytes(reversed(span[:6]))), span[6:]) def parse_all(span: bytes) -> 'Address': assert len(span) == 6 return Address(bytes(reversed(span))) def serialize(self) -> bytes: return bytes(reversed(self.address)) def is_resolvable(self) -> bool: return (self.address[0] & 0xc0) == 0x40 def is_non_resolvable(self) -> bool: return (self.address[0] & 0xc0) == 0x00 def is_static_identity(self) -> bool: return (self.address[0] & 0xc0) == 0xc0 def __repr__(self) -> str: return ':'.join([f'{b:02x}' for b in self.address]) @property def size(self) -> int: return 6 @dataclass class ClassOfDevice: class_of_device: int = 0 def parse(span: bytes) -> Tuple['Address', bytes]: assert len(span) >= 3 return (ClassOfDevice(int.from_bytes(span[:3], byteorder='little')), span[3:]) def parse_all(span: bytes) -> 'Address': assert len(span) == 3 return ClassOfDevice(int.from_bytes(span, byteorder='little')) def serialize(self) -> bytes: return int.to_bytes(self.class_of_device, length=3, byteorder='little') @property def size(self) -> int: return 3