bumble 0.0.187__py3-none-any.whl → 0.0.189__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 +2 -2
- bumble/a2dp.py +2 -0
- bumble/apps/bench.py +17 -12
- bumble/apps/speaker/speaker.py +1 -0
- bumble/apps/unbond.py +1 -0
- bumble/att.py +1 -1
- bumble/avdtp.py +12 -6
- bumble/avrcp.py +5 -3
- bumble/controller.py +9 -9
- bumble/device.py +28 -30
- bumble/drivers/intel.py +36 -4
- bumble/gap.py +1 -0
- bumble/gatt.py +8 -6
- bumble/gatt_client.py +1 -3
- bumble/gatt_server.py +3 -3
- bumble/hci.py +11 -9
- bumble/hfp.py +20 -13
- bumble/hid.py +1 -0
- bumble/keys.py +4 -4
- bumble/pandora/host.py +37 -24
- bumble/pandora/security.py +3 -3
- bumble/profiles/bap.py +38 -1
- bumble/profiles/device_information_service.py +2 -2
- bumble/sdp.py +12 -8
- bumble/smp.py +3 -3
- bumble/tools/rtk_fw_download.py +2 -1
- bumble/transport/common.py +2 -4
- bumble/transport/pyusb.py +15 -2
- bumble/transport/usb.py +11 -1
- bumble/utils.py +10 -8
- {bumble-0.0.187.dist-info → bumble-0.0.189.dist-info}/METADATA +10 -10
- {bumble-0.0.187.dist-info → bumble-0.0.189.dist-info}/RECORD +36 -36
- {bumble-0.0.187.dist-info → bumble-0.0.189.dist-info}/LICENSE +0 -0
- {bumble-0.0.187.dist-info → bumble-0.0.189.dist-info}/WHEEL +0 -0
- {bumble-0.0.187.dist-info → bumble-0.0.189.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.187.dist-info → bumble-0.0.189.dist-info}/top_level.txt +0 -0
bumble/_version.py
CHANGED
bumble/a2dp.py
CHANGED
|
@@ -652,7 +652,9 @@ class SbcPacketSource:
|
|
|
652
652
|
|
|
653
653
|
# Prepare for next packets
|
|
654
654
|
sequence_number += 1
|
|
655
|
+
sequence_number &= 0xFFFF
|
|
655
656
|
timestamp += sum((frame.sample_count for frame in frames))
|
|
657
|
+
timestamp &= 0xFFFFFFFF
|
|
656
658
|
frames = [frame]
|
|
657
659
|
frames_size = len(frame.payload)
|
|
658
660
|
else:
|
bumble/apps/bench.py
CHANGED
|
@@ -509,9 +509,11 @@ class Ping:
|
|
|
509
509
|
packet = struct.pack(
|
|
510
510
|
'>bbI',
|
|
511
511
|
PacketType.SEQUENCE,
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
512
|
+
(
|
|
513
|
+
PACKET_FLAG_LAST
|
|
514
|
+
if self.current_packet_index == self.tx_packet_count - 1
|
|
515
|
+
else 0
|
|
516
|
+
),
|
|
515
517
|
self.current_packet_index,
|
|
516
518
|
) + bytes(self.tx_packet_size - 6)
|
|
517
519
|
logging.info(color(f'Sending packet {self.current_packet_index}', 'yellow'))
|
|
@@ -1062,9 +1064,9 @@ class Central(Connection.Listener):
|
|
|
1062
1064
|
|
|
1063
1065
|
if self.phy not in (None, HCI_LE_1M_PHY):
|
|
1064
1066
|
# Add an connections parameters entry for this PHY.
|
|
1065
|
-
self.connection_parameter_preferences[
|
|
1066
|
-
|
|
1067
|
-
|
|
1067
|
+
self.connection_parameter_preferences[self.phy] = (
|
|
1068
|
+
connection_parameter_preferences
|
|
1069
|
+
)
|
|
1068
1070
|
else:
|
|
1069
1071
|
self.connection_parameter_preferences = None
|
|
1070
1072
|
|
|
@@ -1232,6 +1234,7 @@ class Peripheral(Device.Listener, Connection.Listener):
|
|
|
1232
1234
|
'cyan',
|
|
1233
1235
|
)
|
|
1234
1236
|
)
|
|
1237
|
+
|
|
1235
1238
|
await self.connected.wait()
|
|
1236
1239
|
logging.info(color('### Connected', 'cyan'))
|
|
1237
1240
|
|
|
@@ -1591,8 +1594,8 @@ def central(
|
|
|
1591
1594
|
mode_factory = create_mode_factory(ctx, 'gatt-client')
|
|
1592
1595
|
classic = ctx.obj['classic']
|
|
1593
1596
|
|
|
1594
|
-
|
|
1595
|
-
Central(
|
|
1597
|
+
async def run_central():
|
|
1598
|
+
await Central(
|
|
1596
1599
|
transport,
|
|
1597
1600
|
peripheral_address,
|
|
1598
1601
|
classic,
|
|
@@ -1604,7 +1607,8 @@ def central(
|
|
|
1604
1607
|
encrypt or authenticate,
|
|
1605
1608
|
ctx.obj['extended_data_length'],
|
|
1606
1609
|
).run()
|
|
1607
|
-
|
|
1610
|
+
|
|
1611
|
+
asyncio.run(run_central())
|
|
1608
1612
|
|
|
1609
1613
|
|
|
1610
1614
|
@bench.command()
|
|
@@ -1615,15 +1619,16 @@ def peripheral(ctx, transport):
|
|
|
1615
1619
|
role_factory = create_role_factory(ctx, 'receiver')
|
|
1616
1620
|
mode_factory = create_mode_factory(ctx, 'gatt-server')
|
|
1617
1621
|
|
|
1618
|
-
|
|
1619
|
-
Peripheral(
|
|
1622
|
+
async def run_peripheral():
|
|
1623
|
+
await Peripheral(
|
|
1620
1624
|
transport,
|
|
1621
1625
|
ctx.obj['classic'],
|
|
1622
1626
|
ctx.obj['extended_data_length'],
|
|
1623
1627
|
role_factory,
|
|
1624
1628
|
mode_factory,
|
|
1625
1629
|
).run()
|
|
1626
|
-
|
|
1630
|
+
|
|
1631
|
+
asyncio.run(run_peripheral())
|
|
1627
1632
|
|
|
1628
1633
|
|
|
1629
1634
|
def main():
|
bumble/apps/speaker/speaker.py
CHANGED
|
@@ -76,6 +76,7 @@ logger = logging.getLogger(__name__)
|
|
|
76
76
|
# -----------------------------------------------------------------------------
|
|
77
77
|
DEFAULT_UI_PORT = 7654
|
|
78
78
|
|
|
79
|
+
|
|
79
80
|
# -----------------------------------------------------------------------------
|
|
80
81
|
class AudioExtractor:
|
|
81
82
|
@staticmethod
|
bumble/apps/unbond.py
CHANGED
|
@@ -24,6 +24,7 @@ from bumble.device import Device
|
|
|
24
24
|
from bumble.keys import JsonKeyStore
|
|
25
25
|
from bumble.transport import open_transport
|
|
26
26
|
|
|
27
|
+
|
|
27
28
|
# -----------------------------------------------------------------------------
|
|
28
29
|
async def unbond_with_keystore(keystore, address):
|
|
29
30
|
if address is None:
|
bumble/att.py
CHANGED
bumble/avdtp.py
CHANGED
|
@@ -325,8 +325,8 @@ class MediaPacket:
|
|
|
325
325
|
self.padding = padding
|
|
326
326
|
self.extension = extension
|
|
327
327
|
self.marker = marker
|
|
328
|
-
self.sequence_number = sequence_number
|
|
329
|
-
self.timestamp = timestamp
|
|
328
|
+
self.sequence_number = sequence_number & 0xFFFF
|
|
329
|
+
self.timestamp = timestamp & 0xFFFFFFFF
|
|
330
330
|
self.ssrc = ssrc
|
|
331
331
|
self.csrc_list = csrc_list
|
|
332
332
|
self.payload_type = payload_type
|
|
@@ -341,7 +341,12 @@ class MediaPacket:
|
|
|
341
341
|
| len(self.csrc_list),
|
|
342
342
|
self.marker << 7 | self.payload_type,
|
|
343
343
|
]
|
|
344
|
-
) + struct.pack(
|
|
344
|
+
) + struct.pack(
|
|
345
|
+
'>HII',
|
|
346
|
+
self.sequence_number,
|
|
347
|
+
self.timestamp,
|
|
348
|
+
self.ssrc,
|
|
349
|
+
)
|
|
345
350
|
for csrc in self.csrc_list:
|
|
346
351
|
header += struct.pack('>I', csrc)
|
|
347
352
|
return header + self.payload
|
|
@@ -1545,9 +1550,10 @@ class Protocol(EventEmitter):
|
|
|
1545
1550
|
|
|
1546
1551
|
assert False # Should never reach this
|
|
1547
1552
|
|
|
1548
|
-
async def get_capabilities(
|
|
1549
|
-
|
|
1550
|
-
|
|
1553
|
+
async def get_capabilities(self, seid: int) -> Union[
|
|
1554
|
+
Get_Capabilities_Response,
|
|
1555
|
+
Get_All_Capabilities_Response,
|
|
1556
|
+
]:
|
|
1551
1557
|
if self.version > (1, 2):
|
|
1552
1558
|
return await self.send_command(Get_All_Capabilities_Command(seid))
|
|
1553
1559
|
|
bumble/avrcp.py
CHANGED
|
@@ -1745,9 +1745,11 @@ class Protocol(pyee.EventEmitter):
|
|
|
1745
1745
|
avc.CommandFrame.CommandType.CONTROL,
|
|
1746
1746
|
avc.Frame.SubunitType.PANEL,
|
|
1747
1747
|
0,
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1748
|
+
(
|
|
1749
|
+
avc.PassThroughFrame.StateFlag.PRESSED
|
|
1750
|
+
if pressed
|
|
1751
|
+
else avc.PassThroughFrame.StateFlag.RELEASED
|
|
1752
|
+
),
|
|
1751
1753
|
key,
|
|
1752
1754
|
b'',
|
|
1753
1755
|
)
|
bumble/controller.py
CHANGED
|
@@ -134,15 +134,15 @@ class Controller:
|
|
|
134
134
|
self.hci_sink = None
|
|
135
135
|
self.link = link
|
|
136
136
|
|
|
137
|
-
self.central_connections: Dict[
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
self.peripheral_connections: Dict[
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
self.classic_connections: Dict[
|
|
144
|
-
|
|
145
|
-
|
|
137
|
+
self.central_connections: Dict[Address, Connection] = (
|
|
138
|
+
{}
|
|
139
|
+
) # Connections where this controller is the central
|
|
140
|
+
self.peripheral_connections: Dict[Address, Connection] = (
|
|
141
|
+
{}
|
|
142
|
+
) # Connections where this controller is the peripheral
|
|
143
|
+
self.classic_connections: Dict[Address, Connection] = (
|
|
144
|
+
{}
|
|
145
|
+
) # Connections in BR/EDR
|
|
146
146
|
self.central_cis_links: Dict[int, CisLink] = {} # CIS links by handle
|
|
147
147
|
self.peripheral_cis_links: Dict[int, CisLink] = {} # CIS links by handle
|
|
148
148
|
|
bumble/device.py
CHANGED
|
@@ -276,12 +276,12 @@ class Advertisement:
|
|
|
276
276
|
data_bytes: bytes = b''
|
|
277
277
|
|
|
278
278
|
# Constants
|
|
279
|
-
TX_POWER_NOT_AVAILABLE: ClassVar[
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
RSSI_NOT_AVAILABLE: ClassVar[
|
|
283
|
-
|
|
284
|
-
|
|
279
|
+
TX_POWER_NOT_AVAILABLE: ClassVar[int] = (
|
|
280
|
+
HCI_LE_Extended_Advertising_Report_Event.TX_POWER_INFORMATION_NOT_AVAILABLE
|
|
281
|
+
)
|
|
282
|
+
RSSI_NOT_AVAILABLE: ClassVar[int] = (
|
|
283
|
+
HCI_LE_Extended_Advertising_Report_Event.RSSI_NOT_AVAILABLE
|
|
284
|
+
)
|
|
285
285
|
|
|
286
286
|
def __post_init__(self) -> None:
|
|
287
287
|
self.data = AdvertisingData.from_bytes(self.data_bytes)
|
|
@@ -558,7 +558,9 @@ class AdvertisingParameters:
|
|
|
558
558
|
)
|
|
559
559
|
primary_advertising_interval_min: int = DEVICE_DEFAULT_ADVERTISING_INTERVAL
|
|
560
560
|
primary_advertising_interval_max: int = DEVICE_DEFAULT_ADVERTISING_INTERVAL
|
|
561
|
-
primary_advertising_channel_map:
|
|
561
|
+
primary_advertising_channel_map: (
|
|
562
|
+
HCI_LE_Set_Extended_Advertising_Parameters_Command.ChannelMap
|
|
563
|
+
) = (
|
|
562
564
|
AdvertisingChannelMap.CHANNEL_37
|
|
563
565
|
| AdvertisingChannelMap.CHANNEL_38
|
|
564
566
|
| AdvertisingChannelMap.CHANNEL_39
|
|
@@ -1138,14 +1140,12 @@ class Connection(CompositeEventEmitter):
|
|
|
1138
1140
|
@overload
|
|
1139
1141
|
async def create_l2cap_channel(
|
|
1140
1142
|
self, spec: l2cap.ClassicChannelSpec
|
|
1141
|
-
) -> l2cap.ClassicChannel:
|
|
1142
|
-
...
|
|
1143
|
+
) -> l2cap.ClassicChannel: ...
|
|
1143
1144
|
|
|
1144
1145
|
@overload
|
|
1145
1146
|
async def create_l2cap_channel(
|
|
1146
1147
|
self, spec: l2cap.LeCreditBasedChannelSpec
|
|
1147
|
-
) -> l2cap.LeCreditBasedChannel:
|
|
1148
|
-
...
|
|
1148
|
+
) -> l2cap.LeCreditBasedChannel: ...
|
|
1149
1149
|
|
|
1150
1150
|
async def create_l2cap_channel(
|
|
1151
1151
|
self, spec: Union[l2cap.ClassicChannelSpec, l2cap.LeCreditBasedChannelSpec]
|
|
@@ -1723,16 +1723,14 @@ class Device(CompositeEventEmitter):
|
|
|
1723
1723
|
self,
|
|
1724
1724
|
connection: Connection,
|
|
1725
1725
|
spec: l2cap.ClassicChannelSpec,
|
|
1726
|
-
) -> l2cap.ClassicChannel:
|
|
1727
|
-
...
|
|
1726
|
+
) -> l2cap.ClassicChannel: ...
|
|
1728
1727
|
|
|
1729
1728
|
@overload
|
|
1730
1729
|
async def create_l2cap_channel(
|
|
1731
1730
|
self,
|
|
1732
1731
|
connection: Connection,
|
|
1733
1732
|
spec: l2cap.LeCreditBasedChannelSpec,
|
|
1734
|
-
) -> l2cap.LeCreditBasedChannel:
|
|
1735
|
-
...
|
|
1733
|
+
) -> l2cap.LeCreditBasedChannel: ...
|
|
1736
1734
|
|
|
1737
1735
|
async def create_l2cap_channel(
|
|
1738
1736
|
self,
|
|
@@ -1753,16 +1751,14 @@ class Device(CompositeEventEmitter):
|
|
|
1753
1751
|
self,
|
|
1754
1752
|
spec: l2cap.ClassicChannelSpec,
|
|
1755
1753
|
handler: Optional[Callable[[l2cap.ClassicChannel], Any]] = None,
|
|
1756
|
-
) -> l2cap.ClassicChannelServer:
|
|
1757
|
-
...
|
|
1754
|
+
) -> l2cap.ClassicChannelServer: ...
|
|
1758
1755
|
|
|
1759
1756
|
@overload
|
|
1760
1757
|
def create_l2cap_server(
|
|
1761
1758
|
self,
|
|
1762
1759
|
spec: l2cap.LeCreditBasedChannelSpec,
|
|
1763
1760
|
handler: Optional[Callable[[l2cap.LeCreditBasedChannel], Any]] = None,
|
|
1764
|
-
) -> l2cap.LeCreditBasedChannelServer:
|
|
1765
|
-
...
|
|
1761
|
+
) -> l2cap.LeCreditBasedChannelServer: ...
|
|
1766
1762
|
|
|
1767
1763
|
def create_l2cap_server(
|
|
1768
1764
|
self,
|
|
@@ -3289,17 +3285,19 @@ class Device(CompositeEventEmitter):
|
|
|
3289
3285
|
|
|
3290
3286
|
handler = self.on(
|
|
3291
3287
|
'remote_name',
|
|
3292
|
-
lambda address, remote_name:
|
|
3293
|
-
|
|
3294
|
-
|
|
3288
|
+
lambda address, remote_name: (
|
|
3289
|
+
pending_name.set_result(remote_name)
|
|
3290
|
+
if address == peer_address
|
|
3291
|
+
else None
|
|
3292
|
+
),
|
|
3295
3293
|
)
|
|
3296
3294
|
failure_handler = self.on(
|
|
3297
3295
|
'remote_name_failure',
|
|
3298
|
-
lambda address, error_code:
|
|
3299
|
-
HCI_Error(error_code)
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3296
|
+
lambda address, error_code: (
|
|
3297
|
+
pending_name.set_exception(HCI_Error(error_code))
|
|
3298
|
+
if address == peer_address
|
|
3299
|
+
else None
|
|
3300
|
+
),
|
|
3303
3301
|
)
|
|
3304
3302
|
|
|
3305
3303
|
try:
|
|
@@ -3475,9 +3473,9 @@ class Device(CompositeEventEmitter):
|
|
|
3475
3473
|
LE features supported by the remote device.
|
|
3476
3474
|
"""
|
|
3477
3475
|
with closing(EventWatcher()) as watcher:
|
|
3478
|
-
read_feature_future: asyncio.Future[
|
|
3479
|
-
|
|
3480
|
-
|
|
3476
|
+
read_feature_future: asyncio.Future[LeFeatureMask] = (
|
|
3477
|
+
asyncio.get_running_loop().create_future()
|
|
3478
|
+
)
|
|
3481
3479
|
|
|
3482
3480
|
def on_le_remote_features(handle: int, features: int):
|
|
3483
3481
|
if handle == connection.handle:
|
bumble/drivers/intel.py
CHANGED
|
@@ -29,6 +29,17 @@ from bumble.hci import (
|
|
|
29
29
|
# -----------------------------------------------------------------------------
|
|
30
30
|
logger = logging.getLogger(__name__)
|
|
31
31
|
|
|
32
|
+
# -----------------------------------------------------------------------------
|
|
33
|
+
# Constant
|
|
34
|
+
# -----------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
INTEL_USB_PRODUCTS = {
|
|
37
|
+
# Intel AX210
|
|
38
|
+
(0x8087, 0x0032),
|
|
39
|
+
# Intel BE200
|
|
40
|
+
(0x8087, 0x0036),
|
|
41
|
+
}
|
|
42
|
+
|
|
32
43
|
# -----------------------------------------------------------------------------
|
|
33
44
|
# HCI Commands
|
|
34
45
|
# -----------------------------------------------------------------------------
|
|
@@ -52,13 +63,34 @@ class Driver(common.Driver):
|
|
|
52
63
|
def __init__(self, host):
|
|
53
64
|
self.host = host
|
|
54
65
|
|
|
66
|
+
@staticmethod
|
|
67
|
+
def check(host):
|
|
68
|
+
driver = host.hci_metadata.get("driver")
|
|
69
|
+
if driver == "intel":
|
|
70
|
+
return True
|
|
71
|
+
|
|
72
|
+
vendor_id = host.hci_metadata.get("vendor_id")
|
|
73
|
+
product_id = host.hci_metadata.get("product_id")
|
|
74
|
+
|
|
75
|
+
if vendor_id is None or product_id is None:
|
|
76
|
+
logger.debug("USB metadata not sufficient")
|
|
77
|
+
return False
|
|
78
|
+
|
|
79
|
+
if (vendor_id, product_id) not in INTEL_USB_PRODUCTS:
|
|
80
|
+
logger.debug(
|
|
81
|
+
f"USB device ({vendor_id:04X}, {product_id:04X}) " "not in known list"
|
|
82
|
+
)
|
|
83
|
+
return False
|
|
84
|
+
|
|
85
|
+
return True
|
|
86
|
+
|
|
55
87
|
@classmethod
|
|
56
|
-
async def for_host(cls, host): # type: ignore
|
|
88
|
+
async def for_host(cls, host, force=False): # type: ignore
|
|
57
89
|
# Only instantiate this driver if explicitly selected
|
|
58
|
-
if
|
|
59
|
-
return
|
|
90
|
+
if not force and not cls.check(host):
|
|
91
|
+
return None
|
|
60
92
|
|
|
61
|
-
return
|
|
93
|
+
return cls(host)
|
|
62
94
|
|
|
63
95
|
async def init_controller(self):
|
|
64
96
|
self.host.ready = True
|
bumble/gap.py
CHANGED
|
@@ -36,6 +36,7 @@ logger = logging.getLogger(__name__)
|
|
|
36
36
|
# Classes
|
|
37
37
|
# -----------------------------------------------------------------------------
|
|
38
38
|
|
|
39
|
+
|
|
39
40
|
# -----------------------------------------------------------------------------
|
|
40
41
|
class GenericAccessService(Service):
|
|
41
42
|
def __init__(self, device_name, appearance=(0, 0)):
|
bumble/gatt.py
CHANGED
|
@@ -342,9 +342,11 @@ class Service(Attribute):
|
|
|
342
342
|
uuid = UUID(uuid)
|
|
343
343
|
|
|
344
344
|
super().__init__(
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
345
|
+
(
|
|
346
|
+
GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE
|
|
347
|
+
if primary
|
|
348
|
+
else GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE
|
|
349
|
+
),
|
|
348
350
|
Attribute.READABLE,
|
|
349
351
|
uuid.to_pdu_bytes(),
|
|
350
352
|
)
|
|
@@ -560,9 +562,9 @@ class CharacteristicAdapter:
|
|
|
560
562
|
|
|
561
563
|
def __init__(self, characteristic: Union[Characteristic, AttributeProxy]):
|
|
562
564
|
self.wrapped_characteristic = characteristic
|
|
563
|
-
self.subscribers: Dict[
|
|
564
|
-
|
|
565
|
-
|
|
565
|
+
self.subscribers: Dict[Callable, Callable] = (
|
|
566
|
+
{}
|
|
567
|
+
) # Map from subscriber to proxy subscriber
|
|
566
568
|
|
|
567
569
|
if isinstance(characteristic, Characteristic):
|
|
568
570
|
self.read_value = self.read_encoded_value
|
bumble/gatt_client.py
CHANGED
|
@@ -352,9 +352,7 @@ class Client:
|
|
|
352
352
|
if c.uuid == uuid
|
|
353
353
|
]
|
|
354
354
|
|
|
355
|
-
def get_attribute_grouping(
|
|
356
|
-
self, attribute_handle: int
|
|
357
|
-
) -> Optional[
|
|
355
|
+
def get_attribute_grouping(self, attribute_handle: int) -> Optional[
|
|
358
356
|
Union[
|
|
359
357
|
ServiceProxy,
|
|
360
358
|
Tuple[ServiceProxy, CharacteristicProxy],
|
bumble/gatt_server.py
CHANGED
|
@@ -445,9 +445,9 @@ class Server(EventEmitter):
|
|
|
445
445
|
assert self.pending_confirmations[connection.handle] is None
|
|
446
446
|
|
|
447
447
|
# Create a future value to hold the eventual response
|
|
448
|
-
pending_confirmation = self.pending_confirmations[
|
|
449
|
-
|
|
450
|
-
|
|
448
|
+
pending_confirmation = self.pending_confirmations[connection.handle] = (
|
|
449
|
+
asyncio.get_running_loop().create_future()
|
|
450
|
+
)
|
|
451
451
|
|
|
452
452
|
try:
|
|
453
453
|
self.send_gatt_pdu(connection.handle, indication.to_bytes())
|
bumble/hci.py
CHANGED
|
@@ -4249,9 +4249,11 @@ class HCI_LE_Set_Extended_Scan_Parameters_Command(HCI_Command):
|
|
|
4249
4249
|
fields.append(
|
|
4250
4250
|
(
|
|
4251
4251
|
f'{scanning_phy_str}.scan_type: ',
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4252
|
+
(
|
|
4253
|
+
'PASSIVE'
|
|
4254
|
+
if self.scan_types[i] == self.PASSIVE_SCANNING
|
|
4255
|
+
else 'ACTIVE'
|
|
4256
|
+
),
|
|
4255
4257
|
)
|
|
4256
4258
|
)
|
|
4257
4259
|
fields.append(
|
|
@@ -5010,9 +5012,9 @@ class HCI_LE_Advertising_Report_Event(HCI_LE_Meta_Event):
|
|
|
5010
5012
|
return f'{color(self.subevent_name(self.subevent_code), "magenta")}:\n{reports}'
|
|
5011
5013
|
|
|
5012
5014
|
|
|
5013
|
-
HCI_LE_Meta_Event.subevent_classes[
|
|
5014
|
-
|
|
5015
|
-
|
|
5015
|
+
HCI_LE_Meta_Event.subevent_classes[HCI_LE_ADVERTISING_REPORT_EVENT] = (
|
|
5016
|
+
HCI_LE_Advertising_Report_Event
|
|
5017
|
+
)
|
|
5016
5018
|
|
|
5017
5019
|
|
|
5018
5020
|
# -----------------------------------------------------------------------------
|
|
@@ -5264,9 +5266,9 @@ class HCI_LE_Extended_Advertising_Report_Event(HCI_LE_Meta_Event):
|
|
|
5264
5266
|
return f'{color(self.subevent_name(self.subevent_code), "magenta")}:\n{reports}'
|
|
5265
5267
|
|
|
5266
5268
|
|
|
5267
|
-
HCI_LE_Meta_Event.subevent_classes[
|
|
5268
|
-
|
|
5269
|
-
|
|
5269
|
+
HCI_LE_Meta_Event.subevent_classes[HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT] = (
|
|
5270
|
+
HCI_LE_Extended_Advertising_Report_Event
|
|
5271
|
+
)
|
|
5270
5272
|
|
|
5271
5273
|
|
|
5272
5274
|
# -----------------------------------------------------------------------------
|
bumble/hfp.py
CHANGED
|
@@ -22,7 +22,8 @@ import dataclasses
|
|
|
22
22
|
import enum
|
|
23
23
|
import traceback
|
|
24
24
|
import pyee
|
|
25
|
-
from typing import Dict, List, Union, Set, Any, Optional, TYPE_CHECKING
|
|
25
|
+
from typing import Dict, List, Union, Set, Any, Optional, Type, TYPE_CHECKING
|
|
26
|
+
from typing_extensions import Self
|
|
26
27
|
|
|
27
28
|
from bumble import at
|
|
28
29
|
from bumble import rfcomm
|
|
@@ -417,17 +418,21 @@ class AtResponseType(enum.Enum):
|
|
|
417
418
|
MULTIPLE = 2
|
|
418
419
|
|
|
419
420
|
|
|
421
|
+
@dataclasses.dataclass
|
|
420
422
|
class AtResponse:
|
|
421
423
|
code: str
|
|
422
424
|
parameters: list
|
|
423
425
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
+
@classmethod
|
|
427
|
+
def parse_from(cls: Type[Self], buffer: bytearray) -> Self:
|
|
428
|
+
code_and_parameters = buffer.split(b':')
|
|
426
429
|
parameters = (
|
|
427
430
|
code_and_parameters[1] if len(code_and_parameters) > 1 else bytearray()
|
|
428
431
|
)
|
|
429
|
-
|
|
430
|
-
|
|
432
|
+
return cls(
|
|
433
|
+
code=code_and_parameters[0].decode(),
|
|
434
|
+
parameters=at.parse_parameters(parameters),
|
|
435
|
+
)
|
|
431
436
|
|
|
432
437
|
|
|
433
438
|
@dataclasses.dataclass
|
|
@@ -530,7 +535,7 @@ class HfProtocol(pyee.EventEmitter):
|
|
|
530
535
|
|
|
531
536
|
# Isolate the AT response code and parameters.
|
|
532
537
|
raw_response = self.read_buffer[header + 2 : trailer]
|
|
533
|
-
response = AtResponse(raw_response)
|
|
538
|
+
response = AtResponse.parse_from(raw_response)
|
|
534
539
|
logger.debug(f"<<< {raw_response.decode()}")
|
|
535
540
|
|
|
536
541
|
# Consume the response bytes.
|
|
@@ -1006,7 +1011,9 @@ class EscoParameters:
|
|
|
1006
1011
|
transmit_coding_format: CodingFormat
|
|
1007
1012
|
receive_coding_format: CodingFormat
|
|
1008
1013
|
packet_type: HCI_Enhanced_Setup_Synchronous_Connection_Command.PacketType
|
|
1009
|
-
retransmission_effort:
|
|
1014
|
+
retransmission_effort: (
|
|
1015
|
+
HCI_Enhanced_Setup_Synchronous_Connection_Command.RetransmissionEffort
|
|
1016
|
+
)
|
|
1010
1017
|
max_latency: int
|
|
1011
1018
|
|
|
1012
1019
|
# Common
|
|
@@ -1014,12 +1021,12 @@ class EscoParameters:
|
|
|
1014
1021
|
output_coding_format: CodingFormat = CodingFormat(CodecID.LINEAR_PCM)
|
|
1015
1022
|
input_coded_data_size: int = 16
|
|
1016
1023
|
output_coded_data_size: int = 16
|
|
1017
|
-
input_pcm_data_format:
|
|
1018
|
-
HCI_Enhanced_Setup_Synchronous_Connection_Command.PcmDataFormat
|
|
1019
|
-
)
|
|
1020
|
-
output_pcm_data_format:
|
|
1021
|
-
HCI_Enhanced_Setup_Synchronous_Connection_Command.PcmDataFormat
|
|
1022
|
-
)
|
|
1024
|
+
input_pcm_data_format: (
|
|
1025
|
+
HCI_Enhanced_Setup_Synchronous_Connection_Command.PcmDataFormat
|
|
1026
|
+
) = HCI_Enhanced_Setup_Synchronous_Connection_Command.PcmDataFormat.TWOS_COMPLEMENT
|
|
1027
|
+
output_pcm_data_format: (
|
|
1028
|
+
HCI_Enhanced_Setup_Synchronous_Connection_Command.PcmDataFormat
|
|
1029
|
+
) = HCI_Enhanced_Setup_Synchronous_Connection_Command.PcmDataFormat.TWOS_COMPLEMENT
|
|
1023
1030
|
input_pcm_sample_payload_msb_position: int = 0
|
|
1024
1031
|
output_pcm_sample_payload_msb_position: int = 0
|
|
1025
1032
|
input_data_path: HCI_Enhanced_Setup_Synchronous_Connection_Command.DataPath = (
|
bumble/hid.py
CHANGED
bumble/keys.py
CHANGED
|
@@ -128,10 +128,10 @@ class PairingKeys:
|
|
|
128
128
|
|
|
129
129
|
def print(self, prefix=''):
|
|
130
130
|
keys_dict = self.to_dict()
|
|
131
|
-
for
|
|
131
|
+
for container_property, value in keys_dict.items():
|
|
132
132
|
if isinstance(value, dict):
|
|
133
133
|
print(f'{prefix}{color(container_property, "cyan")}:')
|
|
134
|
-
for
|
|
134
|
+
for key_property, key_value in value.items():
|
|
135
135
|
print(f'{prefix} {color(key_property, "green")}: {key_value}')
|
|
136
136
|
else:
|
|
137
137
|
print(f'{prefix}{color(container_property, "cyan")}: {value}')
|
|
@@ -158,7 +158,7 @@ class KeyStore:
|
|
|
158
158
|
async def get_resolving_keys(self):
|
|
159
159
|
all_keys = await self.get_all()
|
|
160
160
|
resolving_keys = []
|
|
161
|
-
for
|
|
161
|
+
for name, keys in all_keys:
|
|
162
162
|
if keys.irk is not None:
|
|
163
163
|
if keys.address_type is None:
|
|
164
164
|
address_type = Address.RANDOM_DEVICE_ADDRESS
|
|
@@ -171,7 +171,7 @@ class KeyStore:
|
|
|
171
171
|
async def print(self, prefix=''):
|
|
172
172
|
entries = await self.get_all()
|
|
173
173
|
separator = ''
|
|
174
|
-
for
|
|
174
|
+
for name, keys in entries:
|
|
175
175
|
print(separator + prefix + color(name, 'yellow'))
|
|
176
176
|
keys.print(prefix=prefix + ' ')
|
|
177
177
|
separator = '\n'
|
bumble/pandora/host.py
CHANGED
|
@@ -54,6 +54,8 @@ from pandora import host_pb2
|
|
|
54
54
|
from pandora.host_pb2 import (
|
|
55
55
|
NOT_CONNECTABLE,
|
|
56
56
|
NOT_DISCOVERABLE,
|
|
57
|
+
DISCOVERABLE_LIMITED,
|
|
58
|
+
DISCOVERABLE_GENERAL,
|
|
57
59
|
PRIMARY_1M,
|
|
58
60
|
PRIMARY_CODED,
|
|
59
61
|
SECONDARY_1M,
|
|
@@ -69,6 +71,7 @@ from pandora.host_pb2 import (
|
|
|
69
71
|
ConnectResponse,
|
|
70
72
|
DataTypes,
|
|
71
73
|
DisconnectRequest,
|
|
74
|
+
DiscoverabilityMode,
|
|
72
75
|
InquiryResponse,
|
|
73
76
|
PrimaryPhy,
|
|
74
77
|
ReadLocalAddressResponse,
|
|
@@ -284,9 +287,9 @@ class HostService(HostServicer):
|
|
|
284
287
|
self.log.debug(f"WaitDisconnection: {connection_handle}")
|
|
285
288
|
|
|
286
289
|
if connection := self.device.lookup_connection(connection_handle):
|
|
287
|
-
disconnection_future: asyncio.Future[
|
|
288
|
-
|
|
289
|
-
|
|
290
|
+
disconnection_future: asyncio.Future[None] = (
|
|
291
|
+
asyncio.get_running_loop().create_future()
|
|
292
|
+
)
|
|
290
293
|
|
|
291
294
|
def on_disconnection(_: None) -> None:
|
|
292
295
|
disconnection_future.set_result(None)
|
|
@@ -367,9 +370,9 @@ class HostService(HostServicer):
|
|
|
367
370
|
scan_response_data=scan_response_data,
|
|
368
371
|
)
|
|
369
372
|
|
|
370
|
-
pending_connection: asyncio.Future[
|
|
371
|
-
|
|
372
|
-
|
|
373
|
+
pending_connection: asyncio.Future[bumble.device.Connection] = (
|
|
374
|
+
asyncio.get_running_loop().create_future()
|
|
375
|
+
)
|
|
373
376
|
|
|
374
377
|
if request.connectable:
|
|
375
378
|
|
|
@@ -483,14 +486,10 @@ class HostService(HostServicer):
|
|
|
483
486
|
target_bytes = bytes(reversed(request.target))
|
|
484
487
|
if request.target_variant() == "public":
|
|
485
488
|
target = Address(target_bytes, Address.PUBLIC_DEVICE_ADDRESS)
|
|
486
|
-
advertising_type =
|
|
487
|
-
AdvertisingType.DIRECTED_CONNECTABLE_HIGH_DUTY
|
|
488
|
-
) # FIXME: HIGH_DUTY ?
|
|
489
|
+
advertising_type = AdvertisingType.DIRECTED_CONNECTABLE_LOW_DUTY
|
|
489
490
|
else:
|
|
490
491
|
target = Address(target_bytes, Address.RANDOM_DEVICE_ADDRESS)
|
|
491
|
-
advertising_type =
|
|
492
|
-
AdvertisingType.DIRECTED_CONNECTABLE_HIGH_DUTY
|
|
493
|
-
) # FIXME: HIGH_DUTY ?
|
|
492
|
+
advertising_type = AdvertisingType.DIRECTED_CONNECTABLE_LOW_DUTY
|
|
494
493
|
|
|
495
494
|
if request.connectable:
|
|
496
495
|
|
|
@@ -517,9 +516,9 @@ class HostService(HostServicer):
|
|
|
517
516
|
await asyncio.sleep(1)
|
|
518
517
|
continue
|
|
519
518
|
|
|
520
|
-
pending_connection: asyncio.Future[
|
|
521
|
-
|
|
522
|
-
|
|
519
|
+
pending_connection: asyncio.Future[bumble.device.Connection] = (
|
|
520
|
+
asyncio.get_running_loop().create_future()
|
|
521
|
+
)
|
|
523
522
|
|
|
524
523
|
self.log.debug('Wait for LE connection...')
|
|
525
524
|
connection = await pending_connection
|
|
@@ -564,12 +563,14 @@ class HostService(HostServicer):
|
|
|
564
563
|
legacy=request.legacy,
|
|
565
564
|
active=not request.passive,
|
|
566
565
|
own_address_type=request.own_address_type,
|
|
567
|
-
scan_interval=
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
566
|
+
scan_interval=(
|
|
567
|
+
int(request.interval)
|
|
568
|
+
if request.interval
|
|
569
|
+
else DEVICE_DEFAULT_SCAN_INTERVAL
|
|
570
|
+
),
|
|
571
|
+
scan_window=(
|
|
572
|
+
int(request.window) if request.window else DEVICE_DEFAULT_SCAN_WINDOW
|
|
573
|
+
),
|
|
573
574
|
scanning_phys=scanning_phys,
|
|
574
575
|
)
|
|
575
576
|
|
|
@@ -783,9 +784,11 @@ class HostService(HostServicer):
|
|
|
783
784
|
*struct.pack('<H', dt.peripheral_connection_interval_min),
|
|
784
785
|
*struct.pack(
|
|
785
786
|
'<H',
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
787
|
+
(
|
|
788
|
+
dt.peripheral_connection_interval_max
|
|
789
|
+
if dt.peripheral_connection_interval_max
|
|
790
|
+
else dt.peripheral_connection_interval_min
|
|
791
|
+
),
|
|
789
792
|
),
|
|
790
793
|
]
|
|
791
794
|
),
|
|
@@ -867,6 +870,16 @@ class HostService(HostServicer):
|
|
|
867
870
|
)
|
|
868
871
|
)
|
|
869
872
|
|
|
873
|
+
flag_map = {
|
|
874
|
+
NOT_DISCOVERABLE: 0x00,
|
|
875
|
+
DISCOVERABLE_LIMITED: AdvertisingData.LE_LIMITED_DISCOVERABLE_MODE_FLAG,
|
|
876
|
+
DISCOVERABLE_GENERAL: AdvertisingData.LE_GENERAL_DISCOVERABLE_MODE_FLAG,
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
if dt.le_discoverability_mode:
|
|
880
|
+
flags = flag_map[dt.le_discoverability_mode]
|
|
881
|
+
ad_structures.append((AdvertisingData.FLAGS, flags.to_bytes(1, 'big')))
|
|
882
|
+
|
|
870
883
|
return AdvertisingData(ad_structures)
|
|
871
884
|
|
|
872
885
|
def pack_data_types(self, ad: AdvertisingData) -> DataTypes:
|
bumble/pandora/security.py
CHANGED
|
@@ -383,9 +383,9 @@ class SecurityService(SecurityServicer):
|
|
|
383
383
|
connection.transport
|
|
384
384
|
] == request.level_variant()
|
|
385
385
|
|
|
386
|
-
wait_for_security: asyncio.Future[
|
|
387
|
-
|
|
388
|
-
|
|
386
|
+
wait_for_security: asyncio.Future[str] = (
|
|
387
|
+
asyncio.get_running_loop().create_future()
|
|
388
|
+
)
|
|
389
389
|
authenticate_task: Optional[asyncio.Future[None]] = None
|
|
390
390
|
pair_task: Optional[asyncio.Future[None]] = None
|
|
391
391
|
|
bumble/profiles/bap.py
CHANGED
|
@@ -24,8 +24,9 @@ import enum
|
|
|
24
24
|
import struct
|
|
25
25
|
import functools
|
|
26
26
|
import logging
|
|
27
|
-
from typing import Optional, List, Union, Type, Dict, Any, Tuple
|
|
27
|
+
from typing import Optional, List, Union, Type, Dict, Any, Tuple
|
|
28
28
|
|
|
29
|
+
from bumble import core
|
|
29
30
|
from bumble import colors
|
|
30
31
|
from bumble import device
|
|
31
32
|
from bumble import hci
|
|
@@ -228,6 +229,14 @@ class SupportedFrameDuration(enum.IntFlag):
|
|
|
228
229
|
DURATION_10000_US_PREFERRED = 0b0010
|
|
229
230
|
|
|
230
231
|
|
|
232
|
+
class AnnouncementType(enum.IntEnum):
|
|
233
|
+
'''Basic Audio Profile, 3.5.3. Additional Audio Stream Control Service requirements'''
|
|
234
|
+
|
|
235
|
+
# fmt: off
|
|
236
|
+
GENERAL = 0x00
|
|
237
|
+
TARGETED = 0x01
|
|
238
|
+
|
|
239
|
+
|
|
231
240
|
# -----------------------------------------------------------------------------
|
|
232
241
|
# ASE Operations
|
|
233
242
|
# -----------------------------------------------------------------------------
|
|
@@ -453,6 +462,34 @@ class AudioRole(enum.IntEnum):
|
|
|
453
462
|
SOURCE = hci.HCI_LE_Setup_ISO_Data_Path_Command.Direction.HOST_TO_CONTROLLER
|
|
454
463
|
|
|
455
464
|
|
|
465
|
+
@dataclasses.dataclass
|
|
466
|
+
class UnicastServerAdvertisingData:
|
|
467
|
+
"""Advertising Data for ASCS."""
|
|
468
|
+
|
|
469
|
+
announcement_type: AnnouncementType = AnnouncementType.TARGETED
|
|
470
|
+
available_audio_contexts: ContextType = ContextType.MEDIA
|
|
471
|
+
metadata: bytes = b''
|
|
472
|
+
|
|
473
|
+
def __bytes__(self) -> bytes:
|
|
474
|
+
return bytes(
|
|
475
|
+
core.AdvertisingData(
|
|
476
|
+
[
|
|
477
|
+
(
|
|
478
|
+
core.AdvertisingData.SERVICE_DATA_16_BIT_UUID,
|
|
479
|
+
struct.pack(
|
|
480
|
+
'<2sBIB',
|
|
481
|
+
gatt.GATT_AUDIO_STREAM_CONTROL_SERVICE.to_bytes(),
|
|
482
|
+
self.announcement_type,
|
|
483
|
+
self.available_audio_contexts,
|
|
484
|
+
len(self.metadata),
|
|
485
|
+
)
|
|
486
|
+
+ self.metadata,
|
|
487
|
+
)
|
|
488
|
+
]
|
|
489
|
+
)
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
|
|
456
493
|
# -----------------------------------------------------------------------------
|
|
457
494
|
# Utils
|
|
458
495
|
# -----------------------------------------------------------------------------
|
|
@@ -59,7 +59,7 @@ class DeviceInformationService(TemplateService):
|
|
|
59
59
|
firmware_revision: Optional[str] = None,
|
|
60
60
|
software_revision: Optional[str] = None,
|
|
61
61
|
system_id: Optional[Tuple[int, int]] = None, # (OUI, Manufacturer ID)
|
|
62
|
-
ieee_regulatory_certification_data_list: Optional[bytes] = None
|
|
62
|
+
ieee_regulatory_certification_data_list: Optional[bytes] = None,
|
|
63
63
|
# TODO: pnp_id
|
|
64
64
|
):
|
|
65
65
|
characteristics = [
|
|
@@ -107,7 +107,7 @@ class DeviceInformationServiceProxy(ProfileServiceProxy):
|
|
|
107
107
|
def __init__(self, service_proxy):
|
|
108
108
|
self.service_proxy = service_proxy
|
|
109
109
|
|
|
110
|
-
for
|
|
110
|
+
for field, uuid in (
|
|
111
111
|
('manufacturer_name', GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC),
|
|
112
112
|
('model_number', GATT_MODEL_NUMBER_STRING_CHARACTERISTIC),
|
|
113
113
|
('serial_number', GATT_SERIAL_NUMBER_STRING_CHARACTERISTIC),
|
bumble/sdp.py
CHANGED
|
@@ -825,11 +825,13 @@ class Client:
|
|
|
825
825
|
)
|
|
826
826
|
attribute_id_list = DataElement.sequence(
|
|
827
827
|
[
|
|
828
|
-
|
|
829
|
-
|
|
828
|
+
(
|
|
829
|
+
DataElement.unsigned_integer(
|
|
830
|
+
attribute_id[0], value_size=attribute_id[1]
|
|
831
|
+
)
|
|
832
|
+
if isinstance(attribute_id, tuple)
|
|
833
|
+
else DataElement.unsigned_integer_16(attribute_id)
|
|
830
834
|
)
|
|
831
|
-
if isinstance(attribute_id, tuple)
|
|
832
|
-
else DataElement.unsigned_integer_16(attribute_id)
|
|
833
835
|
for attribute_id in attribute_ids
|
|
834
836
|
]
|
|
835
837
|
)
|
|
@@ -881,11 +883,13 @@ class Client:
|
|
|
881
883
|
|
|
882
884
|
attribute_id_list = DataElement.sequence(
|
|
883
885
|
[
|
|
884
|
-
|
|
885
|
-
|
|
886
|
+
(
|
|
887
|
+
DataElement.unsigned_integer(
|
|
888
|
+
attribute_id[0], value_size=attribute_id[1]
|
|
889
|
+
)
|
|
890
|
+
if isinstance(attribute_id, tuple)
|
|
891
|
+
else DataElement.unsigned_integer_16(attribute_id)
|
|
886
892
|
)
|
|
887
|
-
if isinstance(attribute_id, tuple)
|
|
888
|
-
else DataElement.unsigned_integer_16(attribute_id)
|
|
889
893
|
for attribute_id in attribute_ids
|
|
890
894
|
]
|
|
891
895
|
)
|
bumble/smp.py
CHANGED
|
@@ -737,9 +737,9 @@ class Session:
|
|
|
737
737
|
|
|
738
738
|
# Create a future that can be used to wait for the session to complete
|
|
739
739
|
if self.is_initiator:
|
|
740
|
-
self.pairing_result: Optional[
|
|
741
|
-
asyncio.
|
|
742
|
-
|
|
740
|
+
self.pairing_result: Optional[asyncio.Future[None]] = (
|
|
741
|
+
asyncio.get_running_loop().create_future()
|
|
742
|
+
)
|
|
743
743
|
else:
|
|
744
744
|
self.pairing_result = None
|
|
745
745
|
|
bumble/tools/rtk_fw_download.py
CHANGED
|
@@ -49,6 +49,7 @@ LINUX_FROM_SCRATCH_SOURCE = (
|
|
|
49
49
|
False,
|
|
50
50
|
)
|
|
51
51
|
|
|
52
|
+
|
|
52
53
|
# -----------------------------------------------------------------------------
|
|
53
54
|
# Functions
|
|
54
55
|
# -----------------------------------------------------------------------------
|
|
@@ -111,7 +112,7 @@ def main(output_dir, source, single, force, parse):
|
|
|
111
112
|
for driver_info in rtk.Driver.DRIVER_INFOS
|
|
112
113
|
]
|
|
113
114
|
|
|
114
|
-
for
|
|
115
|
+
for fw_name, config_name, config_needed in images:
|
|
115
116
|
print(color("---", "yellow"))
|
|
116
117
|
fw_image_out = output_dir / fw_name
|
|
117
118
|
if not force and fw_image_out.exists():
|
bumble/transport/common.py
CHANGED
|
@@ -59,15 +59,13 @@ class TransportLostError(Exception):
|
|
|
59
59
|
# Typing Protocols
|
|
60
60
|
# -----------------------------------------------------------------------------
|
|
61
61
|
class TransportSink(Protocol):
|
|
62
|
-
def on_packet(self, packet: bytes) -> None:
|
|
63
|
-
...
|
|
62
|
+
def on_packet(self, packet: bytes) -> None: ...
|
|
64
63
|
|
|
65
64
|
|
|
66
65
|
class TransportSource(Protocol):
|
|
67
66
|
terminated: asyncio.Future[None]
|
|
68
67
|
|
|
69
|
-
def set_packet_sink(self, sink: TransportSink) -> None:
|
|
70
|
-
...
|
|
68
|
+
def set_packet_sink(self, sink: TransportSink) -> None: ...
|
|
71
69
|
|
|
72
70
|
|
|
73
71
|
# -----------------------------------------------------------------------------
|
bumble/transport/pyusb.py
CHANGED
|
@@ -113,9 +113,10 @@ async def open_pyusb_transport(spec: str) -> Transport:
|
|
|
113
113
|
self.loop.call_soon_threadsafe(self.stop_event.set)
|
|
114
114
|
|
|
115
115
|
class UsbPacketSource(asyncio.Protocol, ParserSource):
|
|
116
|
-
def __init__(self, device, sco_enabled):
|
|
116
|
+
def __init__(self, device, metadata, sco_enabled):
|
|
117
117
|
super().__init__()
|
|
118
118
|
self.device = device
|
|
119
|
+
self.metadata = metadata
|
|
119
120
|
self.loop = asyncio.get_running_loop()
|
|
120
121
|
self.queue = asyncio.Queue()
|
|
121
122
|
self.dequeue_task = None
|
|
@@ -216,6 +217,15 @@ async def open_pyusb_transport(spec: str) -> Transport:
|
|
|
216
217
|
if ':' in spec:
|
|
217
218
|
vendor_id, product_id = spec.split(':')
|
|
218
219
|
device = usb_find(idVendor=int(vendor_id, 16), idProduct=int(product_id, 16))
|
|
220
|
+
elif '-' in spec:
|
|
221
|
+
|
|
222
|
+
def device_path(device):
|
|
223
|
+
if device.port_numbers:
|
|
224
|
+
return f'{device.bus}-{".".join(map(str, device.port_numbers))}'
|
|
225
|
+
else:
|
|
226
|
+
return str(device.bus)
|
|
227
|
+
|
|
228
|
+
device = usb_find(custom_match=lambda device: device_path(device) == spec)
|
|
219
229
|
else:
|
|
220
230
|
device_index = int(spec)
|
|
221
231
|
devices = list(
|
|
@@ -235,6 +245,9 @@ async def open_pyusb_transport(spec: str) -> Transport:
|
|
|
235
245
|
raise ValueError('device not found')
|
|
236
246
|
logger.debug(f'USB Device: {device}')
|
|
237
247
|
|
|
248
|
+
# Collect the metadata
|
|
249
|
+
device_metadata = {'vendor_id': device.idVendor, 'product_id': device.idProduct}
|
|
250
|
+
|
|
238
251
|
# Detach the kernel driver if needed
|
|
239
252
|
if device.is_kernel_driver_active(0):
|
|
240
253
|
logger.debug("detaching kernel driver")
|
|
@@ -289,7 +302,7 @@ async def open_pyusb_transport(spec: str) -> Transport:
|
|
|
289
302
|
# except usb.USBError:
|
|
290
303
|
# logger.warning('failed to set alternate setting')
|
|
291
304
|
|
|
292
|
-
packet_source = UsbPacketSource(device, sco_enabled)
|
|
305
|
+
packet_source = UsbPacketSource(device, device_metadata, sco_enabled)
|
|
293
306
|
packet_sink = UsbPacketSink(device)
|
|
294
307
|
packet_source.start()
|
|
295
308
|
packet_sink.start()
|
bumble/transport/usb.py
CHANGED
|
@@ -396,6 +396,16 @@ async def open_usb_transport(spec: str) -> Transport:
|
|
|
396
396
|
break
|
|
397
397
|
device_index -= 1
|
|
398
398
|
device.close()
|
|
399
|
+
elif '-' in spec:
|
|
400
|
+
|
|
401
|
+
def device_path(device):
|
|
402
|
+
return f'{device.getBusNumber()}-{".".join(map(str, device.getPortNumberList()))}'
|
|
403
|
+
|
|
404
|
+
for device in context.getDeviceIterator(skip_on_error=True):
|
|
405
|
+
if device_path(device) == spec:
|
|
406
|
+
found = device
|
|
407
|
+
break
|
|
408
|
+
device.close()
|
|
399
409
|
else:
|
|
400
410
|
# Look for a compatible device by index
|
|
401
411
|
def device_is_bluetooth_hci(device):
|
|
@@ -439,7 +449,7 @@ async def open_usb_transport(spec: str) -> Transport:
|
|
|
439
449
|
# Look for the first interface with the right class and endpoints
|
|
440
450
|
def find_endpoints(device):
|
|
441
451
|
# pylint: disable-next=too-many-nested-blocks
|
|
442
|
-
for
|
|
452
|
+
for configuration_index, configuration in enumerate(device):
|
|
443
453
|
interface = None
|
|
444
454
|
for interface in configuration:
|
|
445
455
|
setting = None
|
bumble/utils.py
CHANGED
|
@@ -117,12 +117,12 @@ class EventWatcher:
|
|
|
117
117
|
self.handlers = []
|
|
118
118
|
|
|
119
119
|
@overload
|
|
120
|
-
def on(
|
|
121
|
-
|
|
120
|
+
def on(
|
|
121
|
+
self, emitter: EventEmitter, event: str
|
|
122
|
+
) -> Callable[[_Handler], _Handler]: ...
|
|
122
123
|
|
|
123
124
|
@overload
|
|
124
|
-
def on(self, emitter: EventEmitter, event: str, handler: _Handler) -> _Handler:
|
|
125
|
-
...
|
|
125
|
+
def on(self, emitter: EventEmitter, event: str, handler: _Handler) -> _Handler: ...
|
|
126
126
|
|
|
127
127
|
def on(
|
|
128
128
|
self, emitter: EventEmitter, event: str, handler: Optional[_Handler] = None
|
|
@@ -144,12 +144,14 @@ class EventWatcher:
|
|
|
144
144
|
return wrapper if handler is None else wrapper(handler)
|
|
145
145
|
|
|
146
146
|
@overload
|
|
147
|
-
def once(
|
|
148
|
-
|
|
147
|
+
def once(
|
|
148
|
+
self, emitter: EventEmitter, event: str
|
|
149
|
+
) -> Callable[[_Handler], _Handler]: ...
|
|
149
150
|
|
|
150
151
|
@overload
|
|
151
|
-
def once(
|
|
152
|
-
|
|
152
|
+
def once(
|
|
153
|
+
self, emitter: EventEmitter, event: str, handler: _Handler
|
|
154
|
+
) -> _Handler: ...
|
|
153
155
|
|
|
154
156
|
def once(
|
|
155
157
|
self, emitter: EventEmitter, event: str, handler: Optional[_Handler] = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: bumble
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.189
|
|
4
4
|
Summary: Bluetooth Stack for Apps, Emulation, Test and Experimentation
|
|
5
5
|
Home-page: https://github.com/google/bumble
|
|
6
6
|
Author: Google
|
|
@@ -11,14 +11,14 @@ License-File: LICENSE
|
|
|
11
11
|
Requires-Dist: pyee >=8.2.2
|
|
12
12
|
Requires-Dist: aiohttp ~=3.8 ; platform_system != "Emscripten"
|
|
13
13
|
Requires-Dist: appdirs >=1.4 ; platform_system != "Emscripten"
|
|
14
|
-
Requires-Dist: bt-test-interfaces >=0.0.
|
|
15
|
-
Requires-Dist: click
|
|
14
|
+
Requires-Dist: bt-test-interfaces >=0.0.6 ; platform_system != "Emscripten"
|
|
15
|
+
Requires-Dist: click >=8.1.3 ; platform_system != "Emscripten"
|
|
16
16
|
Requires-Dist: cryptography ==39 ; platform_system != "Emscripten"
|
|
17
|
-
Requires-Dist: grpcio
|
|
17
|
+
Requires-Dist: grpcio >=1.62.1 ; platform_system != "Emscripten"
|
|
18
18
|
Requires-Dist: humanize >=4.6.0 ; platform_system != "Emscripten"
|
|
19
19
|
Requires-Dist: libusb1 >=2.0.1 ; platform_system != "Emscripten"
|
|
20
20
|
Requires-Dist: libusb-package ==1.0.26.1 ; platform_system != "Emscripten"
|
|
21
|
-
Requires-Dist: platformdirs
|
|
21
|
+
Requires-Dist: platformdirs >=3.10.0 ; platform_system != "Emscripten"
|
|
22
22
|
Requires-Dist: prompt-toolkit >=3.0.16 ; platform_system != "Emscripten"
|
|
23
23
|
Requires-Dist: prettytable >=3.6.0 ; platform_system != "Emscripten"
|
|
24
24
|
Requires-Dist: protobuf >=3.12.4 ; platform_system != "Emscripten"
|
|
@@ -28,13 +28,13 @@ Requires-Dist: pyusb >=1.2 ; platform_system != "Emscripten"
|
|
|
28
28
|
Requires-Dist: websockets >=12.0 ; platform_system != "Emscripten"
|
|
29
29
|
Requires-Dist: cryptography >=39.0 ; platform_system == "Emscripten"
|
|
30
30
|
Provides-Extra: avatar
|
|
31
|
-
Requires-Dist: pandora-avatar ==0.0.
|
|
32
|
-
Requires-Dist: rootcanal ==1.
|
|
31
|
+
Requires-Dist: pandora-avatar ==0.0.9 ; extra == 'avatar'
|
|
32
|
+
Requires-Dist: rootcanal ==1.10.0 ; (python_version >= "3.10") and extra == 'avatar'
|
|
33
33
|
Provides-Extra: build
|
|
34
34
|
Requires-Dist: build >=0.7 ; extra == 'build'
|
|
35
35
|
Provides-Extra: development
|
|
36
|
-
Requires-Dist: black ==
|
|
37
|
-
Requires-Dist: grpcio-tools >=1.
|
|
36
|
+
Requires-Dist: black ==24.3 ; extra == 'development'
|
|
37
|
+
Requires-Dist: grpcio-tools >=1.62.1 ; extra == 'development'
|
|
38
38
|
Requires-Dist: invoke >=1.7.3 ; extra == 'development'
|
|
39
39
|
Requires-Dist: mypy ==1.8.0 ; extra == 'development'
|
|
40
40
|
Requires-Dist: nox >=2022 ; extra == 'development'
|
|
@@ -49,7 +49,7 @@ Requires-Dist: mkdocs-material >=8.5.6 ; extra == 'documentation'
|
|
|
49
49
|
Requires-Dist: mkdocstrings[python] >=0.19.0 ; extra == 'documentation'
|
|
50
50
|
Provides-Extra: test
|
|
51
51
|
Requires-Dist: pytest >=8.0 ; extra == 'test'
|
|
52
|
-
Requires-Dist: pytest-asyncio
|
|
52
|
+
Requires-Dist: pytest-asyncio >=0.21.1 ; extra == 'test'
|
|
53
53
|
Requires-Dist: pytest-html >=3.2.0 ; extra == 'test'
|
|
54
54
|
Requires-Dist: coverage >=6.4 ; extra == 'test'
|
|
55
55
|
|
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
bumble/__init__.py,sha256=Q8jkz6rgl95IMAeInQVt_2GLoJl3DcEP2cxtrQ-ho5c,110
|
|
2
|
-
bumble/_version.py,sha256=
|
|
3
|
-
bumble/a2dp.py,sha256=
|
|
2
|
+
bumble/_version.py,sha256=bCEkYMBue4ua8AyxuKuU6A3V7W7mXkBLwaxWaDR8mGM,415
|
|
3
|
+
bumble/a2dp.py,sha256=VEeAOCfT1ZqpwnEgel6DJ32vxR8jYX3IAaBfCqPdWO8,22675
|
|
4
4
|
bumble/at.py,sha256=kdrcsx2C8Rg61EWESD2QHwpZntkXkRBJLrPn9auv9K8,2961
|
|
5
|
-
bumble/att.py,sha256=
|
|
5
|
+
bumble/att.py,sha256=TGzhhBKCQPA_P_eDDSNASJVfa3dCr-QzzrRB3GekrI0,32366
|
|
6
6
|
bumble/avc.py,sha256=O6ujcmWHMgH821aCLidXN23QFPMAjJ2B50oCu0HxaO0,16188
|
|
7
7
|
bumble/avctp.py,sha256=W_CgqSRV7Z8xOAz8Q4BZGuuZUHEEJjmioSVg1iDINtM,9881
|
|
8
|
-
bumble/avdtp.py,sha256=
|
|
9
|
-
bumble/avrcp.py,sha256=
|
|
8
|
+
bumble/avdtp.py,sha256=RmQiDYeKNitR9jkSXcCzCXacrK_Kbiyt1klO3iylr8Q,77322
|
|
9
|
+
bumble/avrcp.py,sha256=MKyJkyYmL-M1H_Pi4fr8HABXi-E-F9mBOQpbv_Ilysc,69327
|
|
10
10
|
bumble/bridge.py,sha256=T6es5oS1dy8QgkxQ8iOD-YcZ0SWOv8jaqC7TGxqodk4,3003
|
|
11
11
|
bumble/codecs.py,sha256=Vc7FOo6d-6VCgDI0ibnLmX8vCZ4-jtX_-0vEUM-yOrI,15343
|
|
12
12
|
bumble/colors.py,sha256=9H-qzGgMr-YoWdIFpcGPaiRvTvkCzz7FPIkpwqKyKug,3033
|
|
13
13
|
bumble/company_ids.py,sha256=B68e2QPsDeRYP9jjbGs4GGDwEkGxcXGTsON_CHA0uuI,118528
|
|
14
|
-
bumble/controller.py,sha256=
|
|
14
|
+
bumble/controller.py,sha256=XkYTQb2J5MhH_dGfnFkrLXdChFD2s1wSvqXaHQFeo48,59688
|
|
15
15
|
bumble/core.py,sha256=l71AacyuFijZJH-kBYB41riW9SEsRtlVIPYyhnhPwmc,53132
|
|
16
16
|
bumble/crypto.py,sha256=L6z3dn9-dgKYRtOM6O3F6n6Ju4PwTM3LAFJtCg_ie78,9382
|
|
17
17
|
bumble/decoder.py,sha256=N9nMvuVhuwpnfw7EDVuNe9uYY6B6c3RY2dh8RhRPC1U,9608
|
|
18
|
-
bumble/device.py,sha256=
|
|
19
|
-
bumble/gap.py,sha256=
|
|
20
|
-
bumble/gatt.py,sha256=
|
|
21
|
-
bumble/gatt_client.py,sha256=
|
|
22
|
-
bumble/gatt_server.py,sha256=
|
|
23
|
-
bumble/hci.py,sha256=
|
|
18
|
+
bumble/device.py,sha256=XvAdIoGcYZIdlJzJNHRA_4nPYiJF1GRQZAp8HflKe60,167653
|
|
19
|
+
bumble/gap.py,sha256=dRU2_TWvqTDx80hxeSbXlWIeWvptWH4_XbItG5y948Q,2138
|
|
20
|
+
bumble/gatt.py,sha256=W7h8hEyxM8fu3HbAKYJ2HStb8NM7T98UICVnf4G9HDo,38447
|
|
21
|
+
bumble/gatt_client.py,sha256=UUOLszwNBbOG0x2nFuIAK2llAysj0zK4euXJxb2gVSo,42523
|
|
22
|
+
bumble/gatt_server.py,sha256=uPYbn2-y0MLnyR8xxpOf18gPua_Q49pSlMR1zxEnU-Q,37118
|
|
23
|
+
bumble/hci.py,sha256=3MYwWLuuolxY9xMitm5tOHpqvGKqtsReZ6QUfI1DcVA,267323
|
|
24
24
|
bumble/helpers.py,sha256=m0w4UgFFNDEnXwHrDyfRlcBObdVed2fqXGL0lvR3c8s,12733
|
|
25
|
-
bumble/hfp.py,sha256=
|
|
26
|
-
bumble/hid.py,sha256=
|
|
25
|
+
bumble/hfp.py,sha256=n8UPUvxPBBpNjQ9NNlQxhr2yY_qhVkSsyBat39fORyc,41808
|
|
26
|
+
bumble/hid.py,sha256=Dd4rsmkRxcxt1IjoozJdu9Qd-QWruKJfsiYqTT89NDk,20590
|
|
27
27
|
bumble/host.py,sha256=tLFay8cdJIHl92UyVTvChKQXUh9QEFI3Ib6unYJLLHw,46909
|
|
28
|
-
bumble/keys.py,sha256=
|
|
28
|
+
bumble/keys.py,sha256=58BMWd8LocY0bazVQ-qw3DKrOxgilhYaKBkmJRcNPp4,12593
|
|
29
29
|
bumble/l2cap.py,sha256=8m_1Kv6Tk-M-DilkAz_OXx0XsiLUhXycEZjUkICwyj0,81064
|
|
30
30
|
bumble/link.py,sha256=QiiMSCZ0z0ko2oUEMYg6nbq-h5A_3DLN4pjqAx_E-SA,23980
|
|
31
31
|
bumble/pairing.py,sha256=tgPUba6xNxMi-2plm3xfRlzHq-uPRNZEIGWaN0qNGCs,9853
|
|
32
32
|
bumble/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
bumble/rfcomm.py,sha256=rCkYaRNjwQ5HPRTat4CY9ZecU9qWQUi4OCB8_RUKeQc,35685
|
|
34
|
-
bumble/sdp.py,sha256=
|
|
35
|
-
bumble/smp.py,sha256=
|
|
34
|
+
bumble/sdp.py,sha256=_Jp3Ui7dwIm-1t5vvIDBzPOs_gLmFpnZBnPcYtgu6nY,45287
|
|
35
|
+
bumble/smp.py,sha256=PcQj8mDoM8fBc4gKECHoOs0A2ukUAaSZQGdgLj6YzB0,76277
|
|
36
36
|
bumble/snoop.py,sha256=_QfF36eylBW6Snd-_KYOwKaGiM8i_Ed-B5XoFIPt3Dg,5631
|
|
37
|
-
bumble/utils.py,sha256=
|
|
37
|
+
bumble/utils.py,sha256=e0i-4d28-9zP3gYcd1rdNd669rkPnRs5oJCERUEDfxo,15099
|
|
38
38
|
bumble/apps/README.md,sha256=XTwjRAY-EJWDXpl1V8K3Mw8B7kIqzUIUizRjVBVhoIE,1769
|
|
39
39
|
bumble/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
|
-
bumble/apps/bench.py,sha256=
|
|
40
|
+
bumble/apps/bench.py,sha256=wwflVPDw_xaN_duZJF2oCrzAlIuJVR7rEKtVVTmzq1s,52359
|
|
41
41
|
bumble/apps/ble_rpa_tool.py,sha256=ZQtsbfnLPd5qUAkEBPpNgJLRynBBc7q_9cDHKUW2SQ0,1701
|
|
42
42
|
bumble/apps/console.py,sha256=rVR2jmP6Yd76B4zzGPYnpJFtgeYgq19CL6DMSe2-A1M,46093
|
|
43
43
|
bumble/apps/controller_info.py,sha256=pgi6leHpwGdi3-kFUc7uFfuyGPTkNEoOws8cWycQVT0,9249
|
|
@@ -51,7 +51,7 @@ bumble/apps/pair.py,sha256=COU2D7YAIn4lo5iuM0ClObA1zZqQCdrXOcnsiCm0YlQ,17529
|
|
|
51
51
|
bumble/apps/pandora_server.py,sha256=5qaoLCpcZE2KsGO21-7t6Vg4dBjBWbnyOQXwrLhxkuE,1397
|
|
52
52
|
bumble/apps/scan.py,sha256=b6hIppiJqDfR7VFW2wl3-lkPdFvHLqYZKY8VjjNnhls,8366
|
|
53
53
|
bumble/apps/show.py,sha256=8w0-8jLtN6IM6_58pOHbEmE1Rmxm71O48ACrXixC2jk,6218
|
|
54
|
-
bumble/apps/unbond.py,sha256=
|
|
54
|
+
bumble/apps/unbond.py,sha256=LDPWpmgKLMGYDdIFGTdGciFDcUliZ0OmseEbGfJ-MAM,3176
|
|
55
55
|
bumble/apps/usb_probe.py,sha256=zJqrqKSGVYcOntXzgONdluZDE6jfj3IwPNuLqmDPDsU,10351
|
|
56
56
|
bumble/apps/link_relay/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
57
|
bumble/apps/link_relay/link_relay.py,sha256=GOESYPzkMJFrz5VOI_BSmnmgz4Y8EdSLHMWgdA63aDg,10066
|
|
@@ -61,46 +61,46 @@ bumble/apps/speaker/logo.svg,sha256=SQ9XXIqhh07BnGaBZ653nJ7vOslm2Dogdqadhg2MdE4,
|
|
|
61
61
|
bumble/apps/speaker/speaker.css,sha256=nyM5TjzDYkkLwFzsaIOuTSngzSvgDnkLe0Z-fAn1_t4,1234
|
|
62
62
|
bumble/apps/speaker/speaker.html,sha256=kfAZ5oZSFc9ygBFIUuZEn5LUNQnHBvrnuHU6VAptyiU,1188
|
|
63
63
|
bumble/apps/speaker/speaker.js,sha256=DrT831yg3oBXKZ5usnfZjRU9X6Nw3zjIWSkz6sIgVtw,9373
|
|
64
|
-
bumble/apps/speaker/speaker.py,sha256=
|
|
64
|
+
bumble/apps/speaker/speaker.py,sha256=f7cOyVqD6HOiLPCgdcnwN7sakj2SScybVHVTBR6eFwk,24197
|
|
65
65
|
bumble/drivers/__init__.py,sha256=lxqJTghh21rQFThRTurwLysZm385TUcn8ZdpHQSWD88,3196
|
|
66
66
|
bumble/drivers/common.py,sha256=pS783hudolLZAzF8IUWp7g6TXyQsUCEzqCsd1VGeYfQ,1507
|
|
67
|
-
bumble/drivers/intel.py,sha256
|
|
67
|
+
bumble/drivers/intel.py,sha256=-YcJI4ZC_fhHHxWyE8b4eB8V7suOFH1n9uayckGE9Uw,3231
|
|
68
68
|
bumble/drivers/rtk.py,sha256=MMxmUo85VkRhFuhbc9SJEZVL9dnRjmsU9k8djmbUGcA,21369
|
|
69
69
|
bumble/pandora/__init__.py,sha256=5NBVmndeTulANawift0jPT9ISp562wyIHTZ-4uP34Mg,3283
|
|
70
70
|
bumble/pandora/config.py,sha256=KD85n3oRbuvD65sRah2H0gpxEW4YbD7HbYbsxdcpDDA,2388
|
|
71
71
|
bumble/pandora/device.py,sha256=LFqCWrgYkQWrFUSKArsAABXkge8sB2DhvaQoEsC4Jn0,5344
|
|
72
|
-
bumble/pandora/host.py,sha256=
|
|
72
|
+
bumble/pandora/host.py,sha256=d0qGQ769K9SSfBftEJcktTBebXZU6M8MMbh0xLYKwGk,39189
|
|
73
73
|
bumble/pandora/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
74
|
-
bumble/pandora/security.py,sha256
|
|
74
|
+
bumble/pandora/security.py,sha256=YErueKNLsnmcRe6dKo724Ht-buOqmZl2Gauswcc8FW0,21946
|
|
75
75
|
bumble/pandora/utils.py,sha256=Fq4glL0T5cJ2FODoDotmDNdYFOkTOR7DyyL8vkcxp20,3949
|
|
76
76
|
bumble/profiles/__init__.py,sha256=yBGC8Ti5LvZuoh1F42XtfrBilb39T77_yuxESZeX2yI,581
|
|
77
77
|
bumble/profiles/asha_service.py,sha256=J4i5jkJciZWMtTWJ1zGJkEx65DlAEIADqjCRYf_CWNs,7220
|
|
78
|
-
bumble/profiles/bap.py,sha256=
|
|
78
|
+
bumble/profiles/bap.py,sha256=jY0wHBIlc_Qxv6j-3rF_4nI4uM2z4I8WT99Teu4o0S8,46006
|
|
79
79
|
bumble/profiles/battery_service.py,sha256=w-uF4jLoDozJOoykimb2RkrKjVyCke6ts2-h-F1PYyc,2292
|
|
80
80
|
bumble/profiles/cap.py,sha256=6gH7oOnUKjOggMPuB7rtbwj0AneoNmnWzQ_iR3io8e0,1945
|
|
81
81
|
bumble/profiles/csip.py,sha256=wzSpNRCOMWtKw2Yd9OTAzPoFDoQWG-KYwWdA6sUkwiI,10102
|
|
82
|
-
bumble/profiles/device_information_service.py,sha256=
|
|
82
|
+
bumble/profiles/device_information_service.py,sha256=MOMEY9AaMMNOJppJyniaHS-OeuXUdMNd4O9EE5gWd8Y,5657
|
|
83
83
|
bumble/profiles/heart_rate_service.py,sha256=7V2LGcWLp6RurjWxsVgMWr3wPDt5aS9qjNxTbHcOK6o,8575
|
|
84
84
|
bumble/profiles/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
85
85
|
bumble/profiles/vcp.py,sha256=wkbTf2NRCbBtvpXplpNJq4dzXp6JGeaEHeeC1kHqW7s,7897
|
|
86
86
|
bumble/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
87
87
|
bumble/tools/generate_company_id_list.py,sha256=ysbPb3zmxKFBiSQ_MBG2r15-sqR5P_GWT6i0YUTTXOM,1736
|
|
88
|
-
bumble/tools/rtk_fw_download.py,sha256=
|
|
88
|
+
bumble/tools/rtk_fw_download.py,sha256=KEPG-rDrdPGKBzZ78P4s3udLRYT3p7vesGhXvJTWTic,5453
|
|
89
89
|
bumble/tools/rtk_util.py,sha256=TwZhupHQrQYsYHLdRGyzXKd24pwCk8kkzqK1Rj2guco,5087
|
|
90
90
|
bumble/transport/__init__.py,sha256=W_IjqBehWCvjyTghgRYvbbLqDlh2xh7ZRDRvun5iYB0,6830
|
|
91
91
|
bumble/transport/android_emulator.py,sha256=eH8H1aB7MvQ8lpdwVG6SGKg5uwCRb_aPJk8pPwoTXSY,4321
|
|
92
92
|
bumble/transport/android_netsim.py,sha256=SVh-IUZ2bhcIESZFGzOsofybsi4H0qoBRwBieeqUINE,16215
|
|
93
|
-
bumble/transport/common.py,sha256=
|
|
93
|
+
bumble/transport/common.py,sha256=1W8p2dMAlEhmmcS9DFtuM01BNl-LRsNQWcqjq6PfMPc,15697
|
|
94
94
|
bumble/transport/file.py,sha256=eVM2V6Nk2nDAFdE7Rt01ZI3JdTovsH9OEU1gKYPJjpE,2010
|
|
95
95
|
bumble/transport/hci_socket.py,sha256=EdgWi3-O5yvYcH4R4BkPtG79pnUo7GQtXWawuUHDoDQ,6331
|
|
96
96
|
bumble/transport/pty.py,sha256=grTl-yvjMWHflNwuME4ccVqDbk6NIEgQMgH6Y9lf1fU,2732
|
|
97
97
|
bumble/transport/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
98
|
-
bumble/transport/pyusb.py,sha256=
|
|
98
|
+
bumble/transport/pyusb.py,sha256=RV42LSRlMhLx1LOdaF8TY4qePPGlONFaPqta7I5mYTw,11987
|
|
99
99
|
bumble/transport/serial.py,sha256=loQxkeG7uE09enXWg2uGbxi6CeG70wn3kzPbEwULKw4,2446
|
|
100
100
|
bumble/transport/tcp_client.py,sha256=deyUJYpj04QE00Mw_PTU5PHPA6mr1Nui3f5-QCy2zOw,1854
|
|
101
101
|
bumble/transport/tcp_server.py,sha256=hixsSzB-fmzR1yuiHDWd1WhqAia3UA4Cog1Wu6DCLeg,3211
|
|
102
102
|
bumble/transport/udp.py,sha256=di8I6HHACgBx3un-dzAahz9lTIUrh4LdeuYpeoifQEM,2239
|
|
103
|
-
bumble/transport/usb.py,sha256=
|
|
103
|
+
bumble/transport/usb.py,sha256=dFNN-kGI3pMTXeT5Amwu2H6e4J48WAJotG_D18W3RBM,21399
|
|
104
104
|
bumble/transport/vhci.py,sha256=iI2WpighnvIP5zeyJUFSbjEdmCo24CWMdICamIcyJck,2250
|
|
105
105
|
bumble/transport/ws_client.py,sha256=9gqm5jlVT_H6LfwsQwPpky07CINhgOK96ef53SMAxms,1757
|
|
106
106
|
bumble/transport/ws_server.py,sha256=goe4xx7OnZiJy1a00Bg0CXM8uJhsGXbsijMYq2n62bI,3328
|
|
@@ -137,9 +137,9 @@ bumble/vendor/android/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
|
137
137
|
bumble/vendor/android/hci.py,sha256=GZrkhaWmcMt1JpnRhv0NoySGkf2H4lNUV2f_omRZW0I,10741
|
|
138
138
|
bumble/vendor/zephyr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
139
139
|
bumble/vendor/zephyr/hci.py,sha256=d83bC0TvT947eN4roFjLkQefWtHOoNsr4xib2ctSkvA,3195
|
|
140
|
-
bumble-0.0.
|
|
141
|
-
bumble-0.0.
|
|
142
|
-
bumble-0.0.
|
|
143
|
-
bumble-0.0.
|
|
144
|
-
bumble-0.0.
|
|
145
|
-
bumble-0.0.
|
|
140
|
+
bumble-0.0.189.dist-info/LICENSE,sha256=FvaYh4NRWIGgS_OwoBs5gFgkCmAghZ-DYnIGBZPuw-s,12142
|
|
141
|
+
bumble-0.0.189.dist-info/METADATA,sha256=NTCLV4GK4C9ZRJMXmFHSENU-_7HSbRNi1HwxnToJ3wM,5684
|
|
142
|
+
bumble-0.0.189.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
143
|
+
bumble-0.0.189.dist-info/entry_points.txt,sha256=UkNj1KMZDhzOb7O4OU7Jn4YI5KaxJZgQF2GF64BwOlQ,883
|
|
144
|
+
bumble-0.0.189.dist-info/top_level.txt,sha256=tV6JJKaHPYMFiJYiBYFW24PCcfLxTJZdlu6BmH3Cb00,7
|
|
145
|
+
bumble-0.0.189.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|