bumble 0.0.214__py3-none-any.whl → 0.0.215__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bumble/_version.py +16 -3
- bumble/a2dp.py +15 -16
- bumble/apps/auracast.py +13 -38
- bumble/apps/bench.py +9 -10
- bumble/apps/ble_rpa_tool.py +1 -0
- bumble/apps/console.py +22 -25
- bumble/apps/controller_info.py +19 -19
- bumble/apps/controller_loopback.py +2 -2
- bumble/apps/controllers.py +1 -1
- bumble/apps/device_info.py +3 -3
- bumble/apps/gatt_dump.py +1 -1
- bumble/apps/gg_bridge.py +5 -6
- bumble/apps/hci_bridge.py +3 -3
- bumble/apps/l2cap_bridge.py +3 -3
- bumble/apps/lea_unicast/app.py +15 -25
- bumble/apps/pair.py +30 -43
- bumble/apps/pandora_server.py +5 -4
- bumble/apps/player/player.py +19 -22
- bumble/apps/rfcomm_bridge.py +3 -8
- bumble/apps/scan.py +16 -6
- bumble/apps/show.py +3 -4
- bumble/apps/speaker/speaker.py +22 -22
- bumble/apps/unbond.py +2 -1
- bumble/apps/usb_probe.py +1 -2
- bumble/att.py +241 -246
- bumble/audio/io.py +5 -9
- bumble/avc.py +2 -2
- bumble/avctp.py +6 -7
- bumble/avdtp.py +19 -22
- bumble/avrcp.py +1096 -588
- bumble/codecs.py +2 -0
- bumble/controller.py +52 -13
- bumble/core.py +567 -248
- bumble/crypto/__init__.py +2 -2
- bumble/crypto/builtin.py +1 -1
- bumble/crypto/cryptography.py +2 -4
- bumble/data_types.py +1025 -0
- bumble/device.py +280 -278
- bumble/drivers/__init__.py +3 -2
- bumble/drivers/intel.py +3 -4
- bumble/drivers/rtk.py +26 -9
- bumble/gap.py +4 -4
- bumble/gatt.py +3 -2
- bumble/gatt_adapters.py +3 -11
- bumble/gatt_client.py +69 -81
- bumble/gatt_server.py +124 -124
- bumble/hci.py +67 -18
- bumble/helpers.py +19 -26
- bumble/hfp.py +10 -21
- bumble/hid.py +22 -16
- bumble/host.py +181 -103
- bumble/keys.py +5 -3
- bumble/l2cap.py +121 -74
- bumble/link.py +8 -9
- bumble/pairing.py +7 -6
- bumble/pandora/__init__.py +8 -7
- bumble/pandora/config.py +3 -1
- bumble/pandora/device.py +3 -2
- bumble/pandora/host.py +38 -36
- bumble/pandora/l2cap.py +22 -21
- bumble/pandora/security.py +15 -15
- bumble/pandora/utils.py +5 -3
- bumble/profiles/aics.py +11 -11
- bumble/profiles/ams.py +7 -8
- bumble/profiles/ancs.py +6 -7
- bumble/profiles/ascs.py +4 -9
- bumble/profiles/asha.py +8 -12
- bumble/profiles/bap.py +11 -23
- bumble/profiles/bass.py +2 -7
- bumble/profiles/battery_service.py +3 -4
- bumble/profiles/cap.py +1 -2
- bumble/profiles/csip.py +2 -6
- bumble/profiles/device_information_service.py +2 -2
- bumble/profiles/gap.py +4 -4
- bumble/profiles/gatt_service.py +1 -4
- bumble/profiles/gmap.py +5 -5
- bumble/profiles/hap.py +62 -59
- bumble/profiles/heart_rate_service.py +5 -4
- bumble/profiles/le_audio.py +3 -1
- bumble/profiles/mcp.py +3 -7
- bumble/profiles/pacs.py +3 -6
- bumble/profiles/pbp.py +2 -0
- bumble/profiles/tmap.py +2 -3
- bumble/profiles/vcs.py +2 -8
- bumble/profiles/vocs.py +8 -8
- bumble/rfcomm.py +11 -14
- bumble/rtp.py +1 -0
- bumble/sdp.py +10 -8
- bumble/smp.py +142 -153
- bumble/snoop.py +5 -5
- bumble/tools/generate_company_id_list.py +1 -0
- bumble/tools/intel_fw_download.py +3 -3
- bumble/tools/intel_util.py +4 -4
- bumble/tools/rtk_fw_download.py +6 -3
- bumble/tools/rtk_util.py +24 -7
- bumble/transport/__init__.py +19 -15
- bumble/transport/android_emulator.py +8 -13
- bumble/transport/android_netsim.py +19 -18
- bumble/transport/common.py +12 -15
- bumble/transport/file.py +1 -1
- bumble/transport/hci_socket.py +4 -6
- bumble/transport/pty.py +5 -6
- bumble/transport/pyusb.py +7 -10
- bumble/transport/serial.py +2 -1
- bumble/transport/tcp_client.py +2 -2
- bumble/transport/tcp_server.py +11 -14
- bumble/transport/udp.py +3 -3
- bumble/transport/unix.py +67 -1
- bumble/transport/usb.py +6 -6
- bumble/transport/vhci.py +0 -1
- bumble/transport/ws_client.py +2 -1
- bumble/transport/ws_server.py +3 -2
- bumble/utils.py +20 -5
- bumble/vendor/android/hci.py +1 -2
- bumble/vendor/zephyr/hci.py +0 -1
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/METADATA +2 -1
- bumble-0.0.215.dist-info/RECORD +183 -0
- bumble-0.0.214.dist-info/RECORD +0 -182
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/WHEEL +0 -0
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/licenses/LICENSE +0 -0
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/top_level.txt +0 -0
bumble/l2cap.py
CHANGED
|
@@ -16,32 +16,32 @@
|
|
|
16
16
|
# Imports
|
|
17
17
|
# -----------------------------------------------------------------------------
|
|
18
18
|
from __future__ import annotations
|
|
19
|
+
|
|
19
20
|
import asyncio
|
|
20
21
|
import dataclasses
|
|
21
22
|
import enum
|
|
22
23
|
import logging
|
|
23
24
|
import struct
|
|
24
|
-
|
|
25
25
|
from collections import deque
|
|
26
|
+
from collections.abc import Sequence
|
|
26
27
|
from typing import (
|
|
27
|
-
|
|
28
|
-
Callable,
|
|
28
|
+
TYPE_CHECKING,
|
|
29
29
|
Any,
|
|
30
|
-
|
|
30
|
+
Callable,
|
|
31
|
+
ClassVar,
|
|
31
32
|
Iterable,
|
|
33
|
+
Optional,
|
|
32
34
|
SupportsBytes,
|
|
33
35
|
TypeVar,
|
|
34
|
-
|
|
35
|
-
TYPE_CHECKING,
|
|
36
|
+
Union,
|
|
36
37
|
)
|
|
37
38
|
|
|
38
|
-
from bumble import utils
|
|
39
|
-
from bumble import hci
|
|
39
|
+
from bumble import hci, utils
|
|
40
40
|
from bumble.colors import color
|
|
41
41
|
from bumble.core import (
|
|
42
|
-
InvalidStateError,
|
|
43
42
|
InvalidArgumentError,
|
|
44
43
|
InvalidPacketError,
|
|
44
|
+
InvalidStateError,
|
|
45
45
|
OutOfResourcesError,
|
|
46
46
|
ProtocolError,
|
|
47
47
|
)
|
|
@@ -112,6 +112,10 @@ class CommandCode(hci.SpecableEnum):
|
|
|
112
112
|
L2CAP_LE_CREDIT_BASED_CONNECTION_REQUEST = 0x14
|
|
113
113
|
L2CAP_LE_CREDIT_BASED_CONNECTION_RESPONSE = 0x15
|
|
114
114
|
L2CAP_LE_FLOW_CONTROL_CREDIT = 0x16
|
|
115
|
+
L2CAP_CREDIT_BASED_CONNECTION_REQUEST = 0x17
|
|
116
|
+
L2CAP_CREDIT_BASED_CONNECTION_RESPONSE = 0x18
|
|
117
|
+
L2CAP_CREDIT_BASED_RECONFIGURE_REQUEST = 0x19
|
|
118
|
+
L2CAP_CREDIT_BASED_RECONFIGURE_RESPONSE = 0x1A
|
|
115
119
|
|
|
116
120
|
L2CAP_CONNECTION_PARAMETERS_ACCEPTED_RESULT = 0x0000
|
|
117
121
|
L2CAP_CONNECTION_PARAMETERS_REJECTED_RESULT = 0x0001
|
|
@@ -595,6 +599,109 @@ class L2CAP_LE_Flow_Control_Credit(L2CAP_Control_Frame):
|
|
|
595
599
|
credits: int = dataclasses.field(metadata=hci.metadata(2))
|
|
596
600
|
|
|
597
601
|
|
|
602
|
+
# -----------------------------------------------------------------------------
|
|
603
|
+
@L2CAP_Control_Frame.subclass
|
|
604
|
+
@dataclasses.dataclass
|
|
605
|
+
class L2CAP_Credit_Based_Connection_Request(L2CAP_Control_Frame):
|
|
606
|
+
'''
|
|
607
|
+
See Bluetooth spec @ Vol 3, Part A - 4.25 L2CAP_CREDIT_BASED_CONNECTION_REQ (0x17).
|
|
608
|
+
'''
|
|
609
|
+
|
|
610
|
+
@classmethod
|
|
611
|
+
def parse_cid_list(cls, data: bytes, offset: int) -> tuple[int, list[int]]:
|
|
612
|
+
count = (len(data) - offset) // 2
|
|
613
|
+
return len(data), list(struct.unpack_from("<" + ("H" * count), data, offset))
|
|
614
|
+
|
|
615
|
+
@classmethod
|
|
616
|
+
def serialize_cid_list(cls, cids: Sequence[int]) -> bytes:
|
|
617
|
+
return b"".join([struct.pack("<H", cid) for cid in cids])
|
|
618
|
+
|
|
619
|
+
CID_METADATA: ClassVar[dict[str, Any]] = hci.metadata(
|
|
620
|
+
{
|
|
621
|
+
'parser': lambda data, offset: L2CAP_Credit_Based_Connection_Request.parse_cid_list(
|
|
622
|
+
data, offset
|
|
623
|
+
),
|
|
624
|
+
'serializer': lambda value: L2CAP_Credit_Based_Connection_Request.serialize_cid_list(
|
|
625
|
+
value
|
|
626
|
+
),
|
|
627
|
+
}
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
spsm: int = dataclasses.field(metadata=hci.metadata(2))
|
|
631
|
+
mtu: int = dataclasses.field(metadata=hci.metadata(2))
|
|
632
|
+
mps: int = dataclasses.field(metadata=hci.metadata(2))
|
|
633
|
+
initial_credits: int = dataclasses.field(metadata=hci.metadata(2))
|
|
634
|
+
source_cid: Sequence[int] = dataclasses.field(metadata=CID_METADATA)
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
# -----------------------------------------------------------------------------
|
|
638
|
+
@L2CAP_Control_Frame.subclass
|
|
639
|
+
@dataclasses.dataclass
|
|
640
|
+
class L2CAP_Credit_Based_Connection_Response(L2CAP_Control_Frame):
|
|
641
|
+
'''
|
|
642
|
+
See Bluetooth spec @ Vol 3, Part A - 4.26 L2CAP_CREDIT_BASED_CONNECTION_RSP (0x18).
|
|
643
|
+
'''
|
|
644
|
+
|
|
645
|
+
class Result(hci.SpecableEnum):
|
|
646
|
+
ALL_CONNECTIONS_SUCCESSFUL = 0x0000
|
|
647
|
+
ALL_CONNECTIONS_REFUSED_SPSM_NOT_SUPPORTED = 0x0002
|
|
648
|
+
SOME_CONNECTIONS_REFUSED_INSUFFICIENT_RESOURCES_AVAILABLE = 0x0004
|
|
649
|
+
ALL_CONNECTIONS_REFUSED_INSUFFICIENT_AUTHENTICATION = 0x0005
|
|
650
|
+
ALL_CONNECTIONS_REFUSED_INSUFFICIENT_AUTHORIZATION = 0x0006
|
|
651
|
+
ALL_CONNECTIONS_REFUSED_ENCRYPTION_KEY_SIZE_TOO_SHORT = 0x0007
|
|
652
|
+
ALL_CONNECTIONS_REFUSED_INSUFFICIENT_ENCRYPTION = 0x0008
|
|
653
|
+
SOME_CONNECTIONS_REFUSED_INVALID_SOURCE_CID = 0x0009
|
|
654
|
+
SOME_CONNECTIONS_REFUSED_SOURCE_CID_ALREADY_ALLOCATED = 0x000A
|
|
655
|
+
ALL_CONNECTIONS_REFUSED_UNACCEPTABLE_PARAMETERS = 0x000B
|
|
656
|
+
ALL_CONNECTIONS_REFUSED_INVALID_PARAMETERS = 0x000C
|
|
657
|
+
ALL_CONNECTIONS_PENDING_NO_FURTHER_INFORMATION_AVAILABLE = 0x000D
|
|
658
|
+
ALL_CONNECTIONS_PENDING_AUTHENTICATION_PENDING = 0x000E
|
|
659
|
+
ALL_CONNECTIONS_PENDING_AUTHORIZATION_PENDING = 0x000F
|
|
660
|
+
|
|
661
|
+
mtu: int = dataclasses.field(metadata=hci.metadata(2))
|
|
662
|
+
mps: int = dataclasses.field(metadata=hci.metadata(2))
|
|
663
|
+
initial_credits: int = dataclasses.field(metadata=hci.metadata(2))
|
|
664
|
+
result: int = dataclasses.field(metadata=Result.type_metadata(2))
|
|
665
|
+
destination_cid: Sequence[int] = dataclasses.field(
|
|
666
|
+
metadata=L2CAP_Credit_Based_Connection_Request.CID_METADATA
|
|
667
|
+
)
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
# -----------------------------------------------------------------------------
|
|
671
|
+
@L2CAP_Control_Frame.subclass
|
|
672
|
+
@dataclasses.dataclass
|
|
673
|
+
class L2CAP_Credit_Based_Reconfigure_Request(L2CAP_Control_Frame):
|
|
674
|
+
'''
|
|
675
|
+
See Bluetooth spec @ Vol 3, Part A - 4.27 L2CAP_CREDIT_BASED_RECONFIGURE_REQ (0x19).
|
|
676
|
+
'''
|
|
677
|
+
|
|
678
|
+
mtu: int = dataclasses.field(metadata=hci.metadata(2))
|
|
679
|
+
mps: int = dataclasses.field(metadata=hci.metadata(2))
|
|
680
|
+
destination_cid: Sequence[int] = dataclasses.field(
|
|
681
|
+
metadata=L2CAP_Credit_Based_Connection_Request.CID_METADATA
|
|
682
|
+
)
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
# -----------------------------------------------------------------------------
|
|
686
|
+
@L2CAP_Control_Frame.subclass
|
|
687
|
+
@dataclasses.dataclass
|
|
688
|
+
class L2CAP_Credit_Based_Reconfigure_Response(L2CAP_Control_Frame):
|
|
689
|
+
'''
|
|
690
|
+
See Bluetooth spec @ Vol 3, Part A - 4.28 L2CAP_CREDIT_BASED_RECONFIGURE_RSP (0x1A).
|
|
691
|
+
'''
|
|
692
|
+
|
|
693
|
+
class Result(hci.SpecableEnum):
|
|
694
|
+
RECONFIGURATION_SUCCESSFUL = 0x0000
|
|
695
|
+
RECONFIGURATION_FAILED_REDUCTION_IN_SIZE_OF_MTU_NOT_ALLOWED = 0x0001
|
|
696
|
+
RECONFIGURATION_FAILED_REDUCTION_IN_SIZE_OF_MPS_NOT_ALLOWED_FOR_MORE_THAN_ONE_CHANNEL_AT_A_TIME = (
|
|
697
|
+
0x0002
|
|
698
|
+
)
|
|
699
|
+
RECONFIGURATION_FAILED_ONE_OR_MORE_DESTINATION_CIDS_INVALID = 0x0003
|
|
700
|
+
RECONFIGURATION_FAILED_OTHER_UNACCEPTABLE_PARAMETERS = 0x0004
|
|
701
|
+
|
|
702
|
+
result: int = dataclasses.field(metadata=Result.type_metadata(2))
|
|
703
|
+
|
|
704
|
+
|
|
598
705
|
# -----------------------------------------------------------------------------
|
|
599
706
|
class ClassicChannel(utils.EventEmitter):
|
|
600
707
|
class State(enum.IntEnum):
|
|
@@ -1424,16 +1531,6 @@ class ChannelManager:
|
|
|
1424
1531
|
if cid in self.fixed_channels:
|
|
1425
1532
|
del self.fixed_channels[cid]
|
|
1426
1533
|
|
|
1427
|
-
@utils.deprecated("Please use create_classic_server")
|
|
1428
|
-
def register_server(
|
|
1429
|
-
self,
|
|
1430
|
-
psm: int,
|
|
1431
|
-
server: Callable[[ClassicChannel], Any],
|
|
1432
|
-
) -> int:
|
|
1433
|
-
return self.create_classic_server(
|
|
1434
|
-
handler=server, spec=ClassicChannelSpec(psm=psm)
|
|
1435
|
-
).psm
|
|
1436
|
-
|
|
1437
1534
|
def create_classic_server(
|
|
1438
1535
|
self,
|
|
1439
1536
|
spec: ClassicChannelSpec,
|
|
@@ -1470,22 +1567,6 @@ class ChannelManager:
|
|
|
1470
1567
|
|
|
1471
1568
|
return self.servers[spec.psm]
|
|
1472
1569
|
|
|
1473
|
-
@utils.deprecated("Please use create_le_credit_based_server()")
|
|
1474
|
-
def register_le_coc_server(
|
|
1475
|
-
self,
|
|
1476
|
-
psm: int,
|
|
1477
|
-
server: Callable[[LeCreditBasedChannel], Any],
|
|
1478
|
-
max_credits: int,
|
|
1479
|
-
mtu: int,
|
|
1480
|
-
mps: int,
|
|
1481
|
-
) -> int:
|
|
1482
|
-
return self.create_le_credit_based_server(
|
|
1483
|
-
spec=LeCreditBasedChannelSpec(
|
|
1484
|
-
psm=None if psm == 0 else psm, mtu=mtu, mps=mps, max_credits=max_credits
|
|
1485
|
-
),
|
|
1486
|
-
handler=server,
|
|
1487
|
-
).psm
|
|
1488
|
-
|
|
1489
1570
|
def create_le_credit_based_server(
|
|
1490
1571
|
self,
|
|
1491
1572
|
spec: LeCreditBasedChannelSpec,
|
|
@@ -1587,8 +1668,8 @@ class ChannelManager:
|
|
|
1587
1668
|
if handler:
|
|
1588
1669
|
try:
|
|
1589
1670
|
handler(connection, cid, control_frame)
|
|
1590
|
-
except Exception
|
|
1591
|
-
logger.
|
|
1671
|
+
except Exception:
|
|
1672
|
+
logger.exception(color("!!! Exception in handler:", "red"))
|
|
1592
1673
|
self.send_control_frame(
|
|
1593
1674
|
connection,
|
|
1594
1675
|
cid,
|
|
@@ -1598,7 +1679,7 @@ class ChannelManager:
|
|
|
1598
1679
|
data=b'',
|
|
1599
1680
|
),
|
|
1600
1681
|
)
|
|
1601
|
-
raise
|
|
1682
|
+
raise
|
|
1602
1683
|
else:
|
|
1603
1684
|
logger.error(color('Channel Manager command not handled???', 'red'))
|
|
1604
1685
|
self.send_control_frame(
|
|
@@ -2038,17 +2119,6 @@ class ChannelManager:
|
|
|
2038
2119
|
if channel.source_cid in connection_channels:
|
|
2039
2120
|
del connection_channels[channel.source_cid]
|
|
2040
2121
|
|
|
2041
|
-
@utils.deprecated("Please use create_le_credit_based_channel()")
|
|
2042
|
-
async def open_le_coc(
|
|
2043
|
-
self, connection: Connection, psm: int, max_credits: int, mtu: int, mps: int
|
|
2044
|
-
) -> LeCreditBasedChannel:
|
|
2045
|
-
return await self.create_le_credit_based_channel(
|
|
2046
|
-
connection=connection,
|
|
2047
|
-
spec=LeCreditBasedChannelSpec(
|
|
2048
|
-
psm=psm, max_credits=max_credits, mtu=mtu, mps=mps
|
|
2049
|
-
),
|
|
2050
|
-
)
|
|
2051
|
-
|
|
2052
2122
|
async def create_le_credit_based_channel(
|
|
2053
2123
|
self,
|
|
2054
2124
|
connection: Connection,
|
|
@@ -2084,8 +2154,8 @@ class ChannelManager:
|
|
|
2084
2154
|
# Connect
|
|
2085
2155
|
try:
|
|
2086
2156
|
await channel.connect()
|
|
2087
|
-
except Exception
|
|
2088
|
-
logger.
|
|
2157
|
+
except Exception:
|
|
2158
|
+
logger.exception('connection failed')
|
|
2089
2159
|
del connection_channels[source_cid]
|
|
2090
2160
|
raise
|
|
2091
2161
|
|
|
@@ -2095,12 +2165,6 @@ class ChannelManager:
|
|
|
2095
2165
|
|
|
2096
2166
|
return channel
|
|
2097
2167
|
|
|
2098
|
-
@utils.deprecated("Please use create_classic_channel()")
|
|
2099
|
-
async def connect(self, connection: Connection, psm: int) -> ClassicChannel:
|
|
2100
|
-
return await self.create_classic_channel(
|
|
2101
|
-
connection=connection, spec=ClassicChannelSpec(psm=psm)
|
|
2102
|
-
)
|
|
2103
|
-
|
|
2104
2168
|
async def create_classic_channel(
|
|
2105
2169
|
self, connection: Connection, spec: ClassicChannelSpec
|
|
2106
2170
|
) -> ClassicChannel:
|
|
@@ -2137,20 +2201,3 @@ class ChannelManager:
|
|
|
2137
2201
|
raise e
|
|
2138
2202
|
|
|
2139
2203
|
return channel
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
# -----------------------------------------------------------------------------
|
|
2143
|
-
# Deprecated Classes
|
|
2144
|
-
# -----------------------------------------------------------------------------
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
class Channel(ClassicChannel):
|
|
2148
|
-
@utils.deprecated("Please use ClassicChannel")
|
|
2149
|
-
def __init__(self, *args, **kwargs) -> None:
|
|
2150
|
-
super().__init__(*args, **kwargs)
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
class LeConnectionOrientedChannel(LeCreditBasedChannel):
|
|
2154
|
-
@utils.deprecated("Please use LeCreditBasedChannel")
|
|
2155
|
-
def __init__(self, *args, **kwargs) -> None:
|
|
2156
|
-
super().__init__(*args, **kwargs)
|
bumble/link.py
CHANGED
|
@@ -12,25 +12,24 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
import asyncio
|
|
16
|
+
|
|
15
17
|
# -----------------------------------------------------------------------------
|
|
16
18
|
# Imports
|
|
17
19
|
# -----------------------------------------------------------------------------
|
|
18
20
|
import logging
|
|
19
|
-
import
|
|
21
|
+
from typing import Optional
|
|
20
22
|
|
|
21
|
-
from bumble import core
|
|
23
|
+
from bumble import controller, core
|
|
22
24
|
from bumble.hci import (
|
|
23
|
-
Address,
|
|
24
|
-
Role,
|
|
25
|
-
HCI_SUCCESS,
|
|
26
25
|
HCI_CONNECTION_ACCEPT_TIMEOUT_ERROR,
|
|
27
|
-
HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
28
26
|
HCI_PAGE_TIMEOUT_ERROR,
|
|
27
|
+
HCI_SUCCESS,
|
|
28
|
+
HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
29
|
+
Address,
|
|
29
30
|
HCI_Connection_Complete_Event,
|
|
31
|
+
Role,
|
|
30
32
|
)
|
|
31
|
-
from bumble import controller
|
|
32
|
-
|
|
33
|
-
from typing import Optional
|
|
34
33
|
|
|
35
34
|
# -----------------------------------------------------------------------------
|
|
36
35
|
# Logging
|
bumble/pairing.py
CHANGED
|
@@ -16,27 +16,28 @@
|
|
|
16
16
|
# Imports
|
|
17
17
|
# -----------------------------------------------------------------------------
|
|
18
18
|
from __future__ import annotations
|
|
19
|
+
|
|
19
20
|
import enum
|
|
20
|
-
from dataclasses import dataclass
|
|
21
21
|
import secrets
|
|
22
|
+
from dataclasses import dataclass
|
|
22
23
|
from typing import Optional
|
|
23
24
|
|
|
24
25
|
from bumble import hci
|
|
26
|
+
from bumble.core import AdvertisingData, LeRole
|
|
25
27
|
from bumble.smp import (
|
|
26
|
-
SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY,
|
|
27
|
-
SMP_KEYBOARD_ONLY_IO_CAPABILITY,
|
|
28
28
|
SMP_DISPLAY_ONLY_IO_CAPABILITY,
|
|
29
29
|
SMP_DISPLAY_YES_NO_IO_CAPABILITY,
|
|
30
|
-
SMP_KEYBOARD_DISPLAY_IO_CAPABILITY,
|
|
31
30
|
SMP_ENC_KEY_DISTRIBUTION_FLAG,
|
|
32
31
|
SMP_ID_KEY_DISTRIBUTION_FLAG,
|
|
33
|
-
|
|
32
|
+
SMP_KEYBOARD_DISPLAY_IO_CAPABILITY,
|
|
33
|
+
SMP_KEYBOARD_ONLY_IO_CAPABILITY,
|
|
34
34
|
SMP_LINK_KEY_DISTRIBUTION_FLAG,
|
|
35
|
+
SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY,
|
|
36
|
+
SMP_SIGN_KEY_DISTRIBUTION_FLAG,
|
|
35
37
|
OobContext,
|
|
36
38
|
OobLegacyContext,
|
|
37
39
|
OobSharedData,
|
|
38
40
|
)
|
|
39
|
-
from bumble.core import AdvertisingData, LeRole
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
# -----------------------------------------------------------------------------
|
bumble/pandora/__init__.py
CHANGED
|
@@ -19,21 +19,22 @@ This module implement the Pandora Bluetooth test APIs for the Bumble stack.
|
|
|
19
19
|
|
|
20
20
|
__version__ = "0.0.1"
|
|
21
21
|
|
|
22
|
+
from typing import Callable, List, Optional
|
|
23
|
+
|
|
22
24
|
import grpc
|
|
23
25
|
import grpc.aio
|
|
24
|
-
|
|
25
|
-
from bumble.pandora.config import Config
|
|
26
|
-
from bumble.pandora.device import PandoraDevice
|
|
27
|
-
from bumble.pandora.host import HostService
|
|
28
|
-
from bumble.pandora.l2cap import L2CAPService
|
|
29
|
-
from bumble.pandora.security import SecurityService, SecurityStorageService
|
|
30
26
|
from pandora.host_grpc_aio import add_HostServicer_to_server
|
|
31
27
|
from pandora.l2cap_grpc_aio import add_L2CAPServicer_to_server
|
|
32
28
|
from pandora.security_grpc_aio import (
|
|
33
29
|
add_SecurityServicer_to_server,
|
|
34
30
|
add_SecurityStorageServicer_to_server,
|
|
35
31
|
)
|
|
36
|
-
|
|
32
|
+
|
|
33
|
+
from bumble.pandora.config import Config
|
|
34
|
+
from bumble.pandora.device import PandoraDevice
|
|
35
|
+
from bumble.pandora.host import HostService
|
|
36
|
+
from bumble.pandora.l2cap import L2CAPService
|
|
37
|
+
from bumble.pandora.security import SecurityService, SecurityStorageService
|
|
37
38
|
|
|
38
39
|
# public symbols
|
|
39
40
|
__all__ = [
|
bumble/pandora/config.py
CHANGED
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
from dataclasses import dataclass
|
|
18
18
|
from typing import Any
|
|
19
19
|
|
|
20
|
+
from bumble.pairing import PairingConfig, PairingDelegate
|
|
21
|
+
|
|
20
22
|
|
|
21
23
|
@dataclass
|
|
22
24
|
class Config:
|
bumble/pandora/device.py
CHANGED
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
"""Generic & dependency free Bumble (reference) device."""
|
|
16
16
|
|
|
17
17
|
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import Any, Optional
|
|
20
|
+
|
|
18
21
|
from bumble import transport
|
|
19
22
|
from bumble.core import (
|
|
20
23
|
BT_GENERIC_AUDIO_SERVICE,
|
|
@@ -32,8 +35,6 @@ from bumble.sdp import (
|
|
|
32
35
|
DataElement,
|
|
33
36
|
ServiceAttribute,
|
|
34
37
|
)
|
|
35
|
-
from typing import Any, Optional
|
|
36
|
-
|
|
37
38
|
|
|
38
39
|
# Default rootcanal HCI TCP address
|
|
39
40
|
ROOTCANAL_HCI_ADDRESS = "localhost:6402"
|
bumble/pandora/host.py
CHANGED
|
@@ -13,51 +13,23 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
|
+
|
|
16
17
|
import asyncio
|
|
17
|
-
import bumble.device
|
|
18
|
-
import grpc
|
|
19
|
-
import grpc.aio
|
|
20
18
|
import logging
|
|
21
19
|
import struct
|
|
20
|
+
from typing import AsyncGenerator, Optional, cast
|
|
22
21
|
|
|
23
|
-
import
|
|
24
|
-
|
|
25
|
-
from bumble.pandora.config import Config
|
|
26
|
-
from bumble.core import (
|
|
27
|
-
PhysicalTransport,
|
|
28
|
-
UUID,
|
|
29
|
-
AdvertisingData,
|
|
30
|
-
Appearance,
|
|
31
|
-
ConnectionError,
|
|
32
|
-
)
|
|
33
|
-
from bumble.device import (
|
|
34
|
-
DEVICE_DEFAULT_SCAN_INTERVAL,
|
|
35
|
-
DEVICE_DEFAULT_SCAN_WINDOW,
|
|
36
|
-
Advertisement,
|
|
37
|
-
AdvertisingParameters,
|
|
38
|
-
AdvertisingEventProperties,
|
|
39
|
-
AdvertisingType,
|
|
40
|
-
Device,
|
|
41
|
-
)
|
|
42
|
-
from bumble.gatt import Service
|
|
43
|
-
from bumble.hci import (
|
|
44
|
-
HCI_CONNECTION_ALREADY_EXISTS_ERROR,
|
|
45
|
-
HCI_PAGE_TIMEOUT_ERROR,
|
|
46
|
-
HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
|
|
47
|
-
Address,
|
|
48
|
-
Phy,
|
|
49
|
-
Role,
|
|
50
|
-
OwnAddressType,
|
|
51
|
-
)
|
|
22
|
+
import grpc
|
|
23
|
+
import grpc.aio
|
|
52
24
|
from google.protobuf import any_pb2 # pytype: disable=pyi-error
|
|
53
25
|
from google.protobuf import empty_pb2 # pytype: disable=pyi-error
|
|
54
|
-
from pandora.host_grpc_aio import HostServicer
|
|
55
26
|
from pandora import host_pb2
|
|
27
|
+
from pandora.host_grpc_aio import HostServicer
|
|
56
28
|
from pandora.host_pb2 import (
|
|
29
|
+
DISCOVERABLE_GENERAL,
|
|
30
|
+
DISCOVERABLE_LIMITED,
|
|
57
31
|
NOT_CONNECTABLE,
|
|
58
32
|
NOT_DISCOVERABLE,
|
|
59
|
-
DISCOVERABLE_LIMITED,
|
|
60
|
-
DISCOVERABLE_GENERAL,
|
|
61
33
|
PRIMARY_1M,
|
|
62
34
|
PRIMARY_CODED,
|
|
63
35
|
SECONDARY_1M,
|
|
@@ -85,7 +57,37 @@ from pandora.host_pb2 import (
|
|
|
85
57
|
WaitConnectionResponse,
|
|
86
58
|
WaitDisconnectionRequest,
|
|
87
59
|
)
|
|
88
|
-
|
|
60
|
+
|
|
61
|
+
import bumble.device
|
|
62
|
+
import bumble.utils
|
|
63
|
+
from bumble.core import (
|
|
64
|
+
UUID,
|
|
65
|
+
AdvertisingData,
|
|
66
|
+
Appearance,
|
|
67
|
+
ConnectionError,
|
|
68
|
+
PhysicalTransport,
|
|
69
|
+
)
|
|
70
|
+
from bumble.device import (
|
|
71
|
+
DEVICE_DEFAULT_SCAN_INTERVAL,
|
|
72
|
+
DEVICE_DEFAULT_SCAN_WINDOW,
|
|
73
|
+
Advertisement,
|
|
74
|
+
AdvertisingEventProperties,
|
|
75
|
+
AdvertisingParameters,
|
|
76
|
+
AdvertisingType,
|
|
77
|
+
Device,
|
|
78
|
+
)
|
|
79
|
+
from bumble.gatt import Service
|
|
80
|
+
from bumble.hci import (
|
|
81
|
+
HCI_CONNECTION_ALREADY_EXISTS_ERROR,
|
|
82
|
+
HCI_PAGE_TIMEOUT_ERROR,
|
|
83
|
+
HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
|
|
84
|
+
Address,
|
|
85
|
+
OwnAddressType,
|
|
86
|
+
Phy,
|
|
87
|
+
Role,
|
|
88
|
+
)
|
|
89
|
+
from bumble.pandora import utils
|
|
90
|
+
from bumble.pandora.config import Config
|
|
89
91
|
|
|
90
92
|
PRIMARY_PHY_MAP: dict[int, PrimaryPhy] = {
|
|
91
93
|
# Default value reported by Bumble for legacy Advertising reports.
|
bumble/pandora/l2cap.py
CHANGED
|
@@ -12,31 +12,21 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
from __future__ import annotations
|
|
15
|
+
|
|
15
16
|
import asyncio
|
|
16
|
-
import grpc
|
|
17
17
|
import json
|
|
18
18
|
import logging
|
|
19
|
+
from asyncio import Future
|
|
20
|
+
from asyncio import Queue as AsyncQueue
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
from typing import AsyncGenerator, Optional, Union
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
from bumble.pandora import utils
|
|
23
|
-
from bumble.pandora.config import Config
|
|
24
|
-
from bumble.core import OutOfResourcesError, InvalidArgumentError
|
|
25
|
-
from bumble.device import Device
|
|
26
|
-
from bumble.l2cap import (
|
|
27
|
-
ClassicChannel,
|
|
28
|
-
ClassicChannelServer,
|
|
29
|
-
ClassicChannelSpec,
|
|
30
|
-
LeCreditBasedChannel,
|
|
31
|
-
LeCreditBasedChannelServer,
|
|
32
|
-
LeCreditBasedChannelSpec,
|
|
33
|
-
)
|
|
24
|
+
import grpc
|
|
34
25
|
from google.protobuf import any_pb2, empty_pb2 # pytype: disable=pyi-error
|
|
35
26
|
from pandora.l2cap_grpc_aio import L2CAPServicer # pytype: disable=pyi-error
|
|
36
|
-
from pandora.l2cap_pb2 import
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Channel as PandoraChannel,
|
|
27
|
+
from pandora.l2cap_pb2 import COMMAND_NOT_UNDERSTOOD, INVALID_CID_IN_REQUEST
|
|
28
|
+
from pandora.l2cap_pb2 import Channel as PandoraChannel # pytype: disable=pyi-error
|
|
29
|
+
from pandora.l2cap_pb2 import (
|
|
40
30
|
ConnectRequest,
|
|
41
31
|
ConnectResponse,
|
|
42
32
|
CreditBasedChannelRequest,
|
|
@@ -51,8 +41,19 @@ from pandora.l2cap_pb2 import ( # pytype: disable=pyi-error
|
|
|
51
41
|
WaitDisconnectionRequest,
|
|
52
42
|
WaitDisconnectionResponse,
|
|
53
43
|
)
|
|
54
|
-
|
|
55
|
-
from
|
|
44
|
+
|
|
45
|
+
from bumble.core import InvalidArgumentError, OutOfResourcesError
|
|
46
|
+
from bumble.device import Device
|
|
47
|
+
from bumble.l2cap import (
|
|
48
|
+
ClassicChannel,
|
|
49
|
+
ClassicChannelServer,
|
|
50
|
+
ClassicChannelSpec,
|
|
51
|
+
LeCreditBasedChannel,
|
|
52
|
+
LeCreditBasedChannelServer,
|
|
53
|
+
LeCreditBasedChannelSpec,
|
|
54
|
+
)
|
|
55
|
+
from bumble.pandora import utils
|
|
56
|
+
from bumble.pandora.config import Config
|
|
56
57
|
|
|
57
58
|
L2capChannel = Union[ClassicChannel, LeCreditBasedChannel]
|
|
58
59
|
|
bumble/pandora/security.py
CHANGED
|
@@ -13,24 +13,14 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
|
+
|
|
16
17
|
import asyncio
|
|
17
18
|
import contextlib
|
|
18
|
-
from collections.abc import Awaitable
|
|
19
|
-
import grpc
|
|
20
19
|
import logging
|
|
20
|
+
from collections.abc import Awaitable
|
|
21
|
+
from typing import Any, AsyncGenerator, AsyncIterator, Callable, Optional, Union
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
from bumble.pandora.config import Config
|
|
24
|
-
from bumble import hci
|
|
25
|
-
from bumble.core import (
|
|
26
|
-
PhysicalTransport,
|
|
27
|
-
ProtocolError,
|
|
28
|
-
InvalidArgumentError,
|
|
29
|
-
)
|
|
30
|
-
import bumble.utils
|
|
31
|
-
from bumble.device import Connection as BumbleConnection, Device
|
|
32
|
-
from bumble.hci import HCI_Error, Role
|
|
33
|
-
from bumble.pairing import PairingConfig, PairingDelegate as BasePairingDelegate
|
|
23
|
+
import grpc
|
|
34
24
|
from google.protobuf import any_pb2 # pytype: disable=pyi-error
|
|
35
25
|
from google.protobuf import empty_pb2 # pytype: disable=pyi-error
|
|
36
26
|
from google.protobuf import wrappers_pb2 # pytype: disable=pyi-error
|
|
@@ -57,7 +47,17 @@ from pandora.security_pb2 import (
|
|
|
57
47
|
WaitSecurityRequest,
|
|
58
48
|
WaitSecurityResponse,
|
|
59
49
|
)
|
|
60
|
-
|
|
50
|
+
|
|
51
|
+
import bumble.utils
|
|
52
|
+
from bumble import hci
|
|
53
|
+
from bumble.core import InvalidArgumentError, PhysicalTransport, ProtocolError
|
|
54
|
+
from bumble.device import Connection as BumbleConnection
|
|
55
|
+
from bumble.device import Device
|
|
56
|
+
from bumble.hci import HCI_Error, Role
|
|
57
|
+
from bumble.pairing import PairingConfig
|
|
58
|
+
from bumble.pairing import PairingDelegate as BasePairingDelegate
|
|
59
|
+
from bumble.pandora import utils
|
|
60
|
+
from bumble.pandora.config import Config
|
|
61
61
|
|
|
62
62
|
|
|
63
63
|
class PairingDelegate(BasePairingDelegate):
|
bumble/pandora/utils.py
CHANGED
|
@@ -13,16 +13,18 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
|
+
|
|
16
17
|
import contextlib
|
|
17
18
|
import functools
|
|
18
|
-
import grpc
|
|
19
19
|
import inspect
|
|
20
20
|
import logging
|
|
21
|
+
from typing import Any, Generator, MutableMapping, Optional
|
|
22
|
+
|
|
23
|
+
import grpc
|
|
24
|
+
from google.protobuf.message import Message # pytype: disable=pyi-error
|
|
21
25
|
|
|
22
26
|
from bumble.device import Device
|
|
23
27
|
from bumble.hci import Address, AddressType
|
|
24
|
-
from google.protobuf.message import Message # pytype: disable=pyi-error
|
|
25
|
-
from typing import Any, Generator, MutableMapping, Optional
|
|
26
28
|
|
|
27
29
|
ADDRESS_TYPES: dict[str, AddressType] = {
|
|
28
30
|
"public": Address.PUBLIC_DEVICE_ADDRESS,
|
bumble/profiles/aics.py
CHANGED
|
@@ -18,26 +18,27 @@
|
|
|
18
18
|
# Imports
|
|
19
19
|
# -----------------------------------------------------------------------------
|
|
20
20
|
from __future__ import annotations
|
|
21
|
+
|
|
21
22
|
import logging
|
|
22
23
|
import struct
|
|
23
|
-
|
|
24
24
|
from dataclasses import dataclass
|
|
25
25
|
from typing import Optional
|
|
26
26
|
|
|
27
|
-
from bumble
|
|
27
|
+
from bumble import utils
|
|
28
28
|
from bumble.att import ATT_Error
|
|
29
|
+
from bumble.device import Connection
|
|
29
30
|
from bumble.gatt import (
|
|
30
|
-
|
|
31
|
-
Characteristic,
|
|
32
|
-
TemplateService,
|
|
33
|
-
CharacteristicValue,
|
|
31
|
+
GATT_AUDIO_INPUT_CONTROL_POINT_CHARACTERISTIC,
|
|
34
32
|
GATT_AUDIO_INPUT_CONTROL_SERVICE,
|
|
33
|
+
GATT_AUDIO_INPUT_DESCRIPTION_CHARACTERISTIC,
|
|
35
34
|
GATT_AUDIO_INPUT_STATE_CHARACTERISTIC,
|
|
36
|
-
GATT_GAIN_SETTINGS_ATTRIBUTE_CHARACTERISTIC,
|
|
37
|
-
GATT_AUDIO_INPUT_TYPE_CHARACTERISTIC,
|
|
38
35
|
GATT_AUDIO_INPUT_STATUS_CHARACTERISTIC,
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
GATT_AUDIO_INPUT_TYPE_CHARACTERISTIC,
|
|
37
|
+
GATT_GAIN_SETTINGS_ATTRIBUTE_CHARACTERISTIC,
|
|
38
|
+
Attribute,
|
|
39
|
+
Characteristic,
|
|
40
|
+
CharacteristicValue,
|
|
41
|
+
TemplateService,
|
|
41
42
|
)
|
|
42
43
|
from bumble.gatt_adapters import (
|
|
43
44
|
CharacteristicProxy,
|
|
@@ -48,7 +49,6 @@ from bumble.gatt_adapters import (
|
|
|
48
49
|
UTF8CharacteristicProxyAdapter,
|
|
49
50
|
)
|
|
50
51
|
from bumble.gatt_client import ProfileServiceProxy, ServiceProxy
|
|
51
|
-
from bumble import utils
|
|
52
52
|
|
|
53
53
|
# -----------------------------------------------------------------------------
|
|
54
54
|
# Logging
|