bumble 0.0.188__py3-none-any.whl → 0.0.190__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/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 +25 -18
- bumble/hid.py +1 -0
- bumble/keys.py +4 -4
- bumble/pandora/host.py +22 -18
- 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/tcp_server.py +24 -5
- bumble/transport/usb.py +1 -1
- bumble/utils.py +10 -8
- {bumble-0.0.188.dist-info → bumble-0.0.190.dist-info}/METADATA +10 -10
- {bumble-0.0.188.dist-info → bumble-0.0.190.dist-info}/RECORD +35 -35
- {bumble-0.0.188.dist-info → bumble-0.0.190.dist-info}/LICENSE +0 -0
- {bumble-0.0.188.dist-info → bumble-0.0.190.dist-info}/WHEEL +0 -0
- {bumble-0.0.188.dist-info → bumble-0.0.190.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.188.dist-info → bumble-0.0.190.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/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.
|
|
@@ -815,11 +820,11 @@ class HfProtocol(pyee.EventEmitter):
|
|
|
815
820
|
return calls
|
|
816
821
|
|
|
817
822
|
async def update_ag_indicator(self, index: int, value: int):
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
)
|
|
823
|
+
# CIEV is in 1-index, while ag_indicators is in 0-index.
|
|
824
|
+
ag_indicator = self.ag_indicators[index - 1]
|
|
825
|
+
ag_indicator.current_status = value
|
|
826
|
+
self.emit('ag_indicator', ag_indicator)
|
|
827
|
+
logger.info(f"AG indicator updated: {ag_indicator.description}, {value}")
|
|
823
828
|
|
|
824
829
|
async def handle_unsolicited(self):
|
|
825
830
|
"""Handle unsolicited result codes sent by the audio gateway."""
|
|
@@ -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
|
@@ -287,9 +287,9 @@ class HostService(HostServicer):
|
|
|
287
287
|
self.log.debug(f"WaitDisconnection: {connection_handle}")
|
|
288
288
|
|
|
289
289
|
if connection := self.device.lookup_connection(connection_handle):
|
|
290
|
-
disconnection_future: asyncio.Future[
|
|
291
|
-
|
|
292
|
-
|
|
290
|
+
disconnection_future: asyncio.Future[None] = (
|
|
291
|
+
asyncio.get_running_loop().create_future()
|
|
292
|
+
)
|
|
293
293
|
|
|
294
294
|
def on_disconnection(_: None) -> None:
|
|
295
295
|
disconnection_future.set_result(None)
|
|
@@ -370,9 +370,9 @@ class HostService(HostServicer):
|
|
|
370
370
|
scan_response_data=scan_response_data,
|
|
371
371
|
)
|
|
372
372
|
|
|
373
|
-
pending_connection: asyncio.Future[
|
|
374
|
-
|
|
375
|
-
|
|
373
|
+
pending_connection: asyncio.Future[bumble.device.Connection] = (
|
|
374
|
+
asyncio.get_running_loop().create_future()
|
|
375
|
+
)
|
|
376
376
|
|
|
377
377
|
if request.connectable:
|
|
378
378
|
|
|
@@ -516,9 +516,9 @@ class HostService(HostServicer):
|
|
|
516
516
|
await asyncio.sleep(1)
|
|
517
517
|
continue
|
|
518
518
|
|
|
519
|
-
pending_connection: asyncio.Future[
|
|
520
|
-
|
|
521
|
-
|
|
519
|
+
pending_connection: asyncio.Future[bumble.device.Connection] = (
|
|
520
|
+
asyncio.get_running_loop().create_future()
|
|
521
|
+
)
|
|
522
522
|
|
|
523
523
|
self.log.debug('Wait for LE connection...')
|
|
524
524
|
connection = await pending_connection
|
|
@@ -563,12 +563,14 @@ class HostService(HostServicer):
|
|
|
563
563
|
legacy=request.legacy,
|
|
564
564
|
active=not request.passive,
|
|
565
565
|
own_address_type=request.own_address_type,
|
|
566
|
-
scan_interval=
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
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
|
+
),
|
|
572
574
|
scanning_phys=scanning_phys,
|
|
573
575
|
)
|
|
574
576
|
|
|
@@ -782,9 +784,11 @@ class HostService(HostServicer):
|
|
|
782
784
|
*struct.pack('<H', dt.peripheral_connection_interval_min),
|
|
783
785
|
*struct.pack(
|
|
784
786
|
'<H',
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
787
|
+
(
|
|
788
|
+
dt.peripheral_connection_interval_max
|
|
789
|
+
if dt.peripheral_connection_interval_max
|
|
790
|
+
else dt.peripheral_connection_interval_min
|
|
791
|
+
),
|
|
788
792
|
),
|
|
789
793
|
]
|
|
790
794
|
),
|
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/tcp_server.py
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
import asyncio
|
|
20
20
|
import logging
|
|
21
|
+
import socket
|
|
21
22
|
|
|
22
23
|
from .common import Transport, StreamPacketSource
|
|
23
24
|
|
|
@@ -28,6 +29,12 @@ logger = logging.getLogger(__name__)
|
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
# -----------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
# A pass-through function to ease mock testing.
|
|
34
|
+
async def _create_server(*args, **kw_args):
|
|
35
|
+
await asyncio.get_running_loop().create_server(*args, **kw_args)
|
|
36
|
+
|
|
37
|
+
|
|
31
38
|
async def open_tcp_server_transport(spec: str) -> Transport:
|
|
32
39
|
'''
|
|
33
40
|
Open a TCP server transport.
|
|
@@ -38,7 +45,22 @@ async def open_tcp_server_transport(spec: str) -> Transport:
|
|
|
38
45
|
|
|
39
46
|
Example: _:9001
|
|
40
47
|
'''
|
|
48
|
+
local_host, local_port = spec.split(':')
|
|
49
|
+
return await _open_tcp_server_transport_impl(
|
|
50
|
+
host=local_host if local_host != '_' else None, port=int(local_port)
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
async def open_tcp_server_transport_with_socket(sock: socket.socket) -> Transport:
|
|
55
|
+
'''
|
|
56
|
+
Open a TCP server transport with an existing socket.
|
|
57
|
+
|
|
58
|
+
One reason to use this variant is to let python pick an unused port.
|
|
59
|
+
'''
|
|
60
|
+
return await _open_tcp_server_transport_impl(sock=sock)
|
|
61
|
+
|
|
41
62
|
|
|
63
|
+
async def _open_tcp_server_transport_impl(**kwargs) -> Transport:
|
|
42
64
|
class TcpServerTransport(Transport):
|
|
43
65
|
async def close(self):
|
|
44
66
|
await super().close()
|
|
@@ -77,13 +99,10 @@ async def open_tcp_server_transport(spec: str) -> Transport:
|
|
|
77
99
|
else:
|
|
78
100
|
logger.debug('no client, dropping packet')
|
|
79
101
|
|
|
80
|
-
local_host, local_port = spec.split(':')
|
|
81
102
|
packet_source = StreamPacketSource()
|
|
82
103
|
packet_sink = TcpServerPacketSink()
|
|
83
|
-
await
|
|
84
|
-
lambda: TcpServerProtocol(packet_source, packet_sink),
|
|
85
|
-
host=local_host if local_host != '_' else None,
|
|
86
|
-
port=int(local_port),
|
|
104
|
+
await _create_server(
|
|
105
|
+
lambda: TcpServerProtocol(packet_source, packet_sink), **kwargs
|
|
87
106
|
)
|
|
88
107
|
|
|
89
108
|
return TcpServerTransport(packet_source, packet_sink)
|
bumble/transport/usb.py
CHANGED
|
@@ -449,7 +449,7 @@ async def open_usb_transport(spec: str) -> Transport:
|
|
|
449
449
|
# Look for the first interface with the right class and endpoints
|
|
450
450
|
def find_endpoints(device):
|
|
451
451
|
# pylint: disable-next=too-many-nested-blocks
|
|
452
|
-
for
|
|
452
|
+
for configuration_index, configuration in enumerate(device):
|
|
453
453
|
interface = None
|
|
454
454
|
for interface in configuration:
|
|
455
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.190
|
|
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=lIV0i6X65UjykL3W2hVxyK2omTPh4jNlE5Ya4uSriLA,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=hc7IVZxsb7skfWrxWPyt0BXFQRMh9a7mdv--A9k5aNg,41865
|
|
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,7 +61,7 @@ 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
67
|
bumble/drivers/intel.py,sha256=-YcJI4ZC_fhHHxWyE8b4eB8V7suOFH1n9uayckGE9Uw,3231
|
|
@@ -69,28 +69,28 @@ 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
|
|
@@ -98,9 +98,9 @@ bumble/transport/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
98
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
|
-
bumble/transport/tcp_server.py,sha256=
|
|
101
|
+
bumble/transport/tcp_server.py,sha256=qcpTeLFSkDWvqHEjYxtZ75wYvAKxa3LiwHJwT5bhn88,3778
|
|
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.190.dist-info/LICENSE,sha256=FvaYh4NRWIGgS_OwoBs5gFgkCmAghZ-DYnIGBZPuw-s,12142
|
|
141
|
+
bumble-0.0.190.dist-info/METADATA,sha256=3toWetMEz1r3wfytRfmK4DjkdzspHLbhVbagGQxyJBk,5684
|
|
142
|
+
bumble-0.0.190.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
143
|
+
bumble-0.0.190.dist-info/entry_points.txt,sha256=UkNj1KMZDhzOb7O4OU7Jn4YI5KaxJZgQF2GF64BwOlQ,883
|
|
144
|
+
bumble-0.0.190.dist-info/top_level.txt,sha256=tV6JJKaHPYMFiJYiBYFW24PCcfLxTJZdlu6BmH3Cb00,7
|
|
145
|
+
bumble-0.0.190.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|