summaryrefslogtreecommitdiff
path: root/tools/rootcanal/py/bluetooth.py
blob: d216bbe5495e25e3b859eae2c41f05452cd91c91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# 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