bumble 0.0.215__py3-none-any.whl → 0.0.217__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/device.py +77 -44
- bumble/host.py +1 -1
- bumble/profiles/hap.py +33 -4
- bumble/transport/android_netsim.py +5 -1
- bumble/transport/serial.py +56 -2
- {bumble-0.0.215.dist-info → bumble-0.0.217.dist-info}/METADATA +1 -1
- {bumble-0.0.215.dist-info → bumble-0.0.217.dist-info}/RECORD +12 -12
- {bumble-0.0.215.dist-info → bumble-0.0.217.dist-info}/WHEEL +0 -0
- {bumble-0.0.215.dist-info → bumble-0.0.217.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.215.dist-info → bumble-0.0.217.dist-info}/licenses/LICENSE +0 -0
- {bumble-0.0.215.dist-info → bumble-0.0.217.dist-info}/top_level.txt +0 -0
bumble/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 0,
|
|
31
|
+
__version__ = version = '0.0.217'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 0, 217)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
bumble/device.py
CHANGED
|
@@ -2169,10 +2169,12 @@ def with_connection_from_handle(function):
|
|
|
2169
2169
|
# Decorator that converts the first argument from a bluetooth address to a connection
|
|
2170
2170
|
def with_connection_from_address(function):
|
|
2171
2171
|
@functools.wraps(function)
|
|
2172
|
-
def wrapper(
|
|
2173
|
-
|
|
2172
|
+
def wrapper(device: Device, address: hci.Address, *args, **kwargs):
|
|
2173
|
+
if connection := device.pending_connections.get(address):
|
|
2174
|
+
return function(device, connection, *args, **kwargs)
|
|
2175
|
+
for connection in device.connections.values():
|
|
2174
2176
|
if connection.peer_address == address:
|
|
2175
|
-
return function(
|
|
2177
|
+
return function(device, connection, *args, **kwargs)
|
|
2176
2178
|
raise ObjectLookupError('no connection for address')
|
|
2177
2179
|
|
|
2178
2180
|
return wrapper
|
|
@@ -2182,11 +2184,13 @@ def with_connection_from_address(function):
|
|
|
2182
2184
|
# connection
|
|
2183
2185
|
def try_with_connection_from_address(function):
|
|
2184
2186
|
@functools.wraps(function)
|
|
2185
|
-
def wrapper(
|
|
2186
|
-
|
|
2187
|
+
def wrapper(device: Device, address: hci.Address, *args, **kwargs):
|
|
2188
|
+
if connection := device.pending_connections.get(address):
|
|
2189
|
+
return function(device, connection, address, *args, **kwargs)
|
|
2190
|
+
for connection in device.connections.values():
|
|
2187
2191
|
if connection.peer_address == address:
|
|
2188
|
-
return function(
|
|
2189
|
-
return function(
|
|
2192
|
+
return function(device, connection, address, *args, **kwargs)
|
|
2193
|
+
return function(device, None, address, *args, **kwargs)
|
|
2190
2194
|
|
|
2191
2195
|
return wrapper
|
|
2192
2196
|
|
|
@@ -2234,7 +2238,7 @@ class Device(utils.CompositeEventEmitter):
|
|
|
2234
2238
|
scan_response_data: bytes
|
|
2235
2239
|
cs_capabilities: ChannelSoundingCapabilities | None = None
|
|
2236
2240
|
connections: dict[int, Connection]
|
|
2237
|
-
|
|
2241
|
+
pending_connections: dict[hci.Address, Connection]
|
|
2238
2242
|
classic_pending_accepts: dict[
|
|
2239
2243
|
hci.Address,
|
|
2240
2244
|
list[asyncio.Future[Union[Connection, tuple[hci.Address, int, int]]]],
|
|
@@ -2356,9 +2360,9 @@ class Device(utils.CompositeEventEmitter):
|
|
|
2356
2360
|
self.le_connecting = False
|
|
2357
2361
|
self.disconnecting = False
|
|
2358
2362
|
self.connections = {} # Connections, by connection handle
|
|
2359
|
-
self.
|
|
2363
|
+
self.pending_connections = (
|
|
2360
2364
|
{}
|
|
2361
|
-
) #
|
|
2365
|
+
) # Pending connections, by BD address (BR/EDR only)
|
|
2362
2366
|
self.sco_links = {} # ScoLinks, by connection handle (BR/EDR only)
|
|
2363
2367
|
self.cis_links = {} # CisLinks, by connection handle (LE only)
|
|
2364
2368
|
self._pending_cis = {} # (CIS_ID, CIG_ID), by CIS_handle
|
|
@@ -3827,7 +3831,17 @@ class Device(utils.CompositeEventEmitter):
|
|
|
3827
3831
|
)
|
|
3828
3832
|
else:
|
|
3829
3833
|
# Save pending connection
|
|
3830
|
-
self.
|
|
3834
|
+
self.pending_connections[peer_address] = Connection(
|
|
3835
|
+
device=self,
|
|
3836
|
+
handle=0,
|
|
3837
|
+
transport=core.PhysicalTransport.BR_EDR,
|
|
3838
|
+
self_address=self.public_address,
|
|
3839
|
+
self_resolvable_address=None,
|
|
3840
|
+
peer_address=peer_address,
|
|
3841
|
+
peer_resolvable_address=None,
|
|
3842
|
+
role=hci.Role.CENTRAL,
|
|
3843
|
+
parameters=Connection.Parameters(0, 0, 0),
|
|
3844
|
+
)
|
|
3831
3845
|
|
|
3832
3846
|
# TODO: allow passing other settings
|
|
3833
3847
|
result = await self.send_command(
|
|
@@ -3880,7 +3894,7 @@ class Device(utils.CompositeEventEmitter):
|
|
|
3880
3894
|
self.le_connecting = False
|
|
3881
3895
|
self.connect_own_address_type = None
|
|
3882
3896
|
else:
|
|
3883
|
-
self.
|
|
3897
|
+
self.pending_connections.pop(peer_address, None)
|
|
3884
3898
|
|
|
3885
3899
|
async def accept(
|
|
3886
3900
|
self,
|
|
@@ -3978,7 +3992,17 @@ class Device(utils.CompositeEventEmitter):
|
|
|
3978
3992
|
# Even if we requested a role switch in the hci.HCI_Accept_Connection_Request
|
|
3979
3993
|
# command, this connection is still considered Peripheral until an eventual
|
|
3980
3994
|
# role change event.
|
|
3981
|
-
self.
|
|
3995
|
+
self.pending_connections[peer_address] = Connection(
|
|
3996
|
+
device=self,
|
|
3997
|
+
handle=0,
|
|
3998
|
+
transport=core.PhysicalTransport.BR_EDR,
|
|
3999
|
+
self_address=self.public_address,
|
|
4000
|
+
self_resolvable_address=None,
|
|
4001
|
+
peer_address=peer_address,
|
|
4002
|
+
peer_resolvable_address=None,
|
|
4003
|
+
role=hci.Role.PERIPHERAL,
|
|
4004
|
+
parameters=Connection.Parameters(0, 0, 0),
|
|
4005
|
+
)
|
|
3982
4006
|
|
|
3983
4007
|
try:
|
|
3984
4008
|
# Accept connection request
|
|
@@ -3996,7 +4020,7 @@ class Device(utils.CompositeEventEmitter):
|
|
|
3996
4020
|
finally:
|
|
3997
4021
|
self.remove_listener(self.EVENT_CONNECTION, on_connection)
|
|
3998
4022
|
self.remove_listener(self.EVENT_CONNECTION_FAILURE, on_connection_failure)
|
|
3999
|
-
self.
|
|
4023
|
+
self.pending_connections.pop(peer_address, None)
|
|
4000
4024
|
|
|
4001
4025
|
@asynccontextmanager
|
|
4002
4026
|
async def connect_as_gatt(self, peer_address: Union[hci.Address, str]):
|
|
@@ -5441,29 +5465,27 @@ class Device(utils.CompositeEventEmitter):
|
|
|
5441
5465
|
connection_handle: int,
|
|
5442
5466
|
peer_address: hci.Address,
|
|
5443
5467
|
) -> None:
|
|
5444
|
-
|
|
5468
|
+
if connection := self.pending_connections.pop(peer_address, None):
|
|
5469
|
+
connection.handle = connection_handle
|
|
5470
|
+
else:
|
|
5471
|
+
# Create a new connection
|
|
5472
|
+
connection = Connection(
|
|
5473
|
+
device=self,
|
|
5474
|
+
handle=connection_handle,
|
|
5475
|
+
transport=PhysicalTransport.BR_EDR,
|
|
5476
|
+
self_address=self.public_address,
|
|
5477
|
+
self_resolvable_address=None,
|
|
5478
|
+
peer_address=peer_address,
|
|
5479
|
+
peer_resolvable_address=None,
|
|
5480
|
+
role=hci.Role.PERIPHERAL,
|
|
5481
|
+
parameters=Connection.Parameters(0.0, 0, 0.0),
|
|
5482
|
+
)
|
|
5445
5483
|
|
|
5446
|
-
logger.debug(
|
|
5447
|
-
f'*** Connection: [0x{connection_handle:04X}] '
|
|
5448
|
-
f'{peer_address} {hci.HCI_Constant.role_name(connection_role)}'
|
|
5449
|
-
)
|
|
5484
|
+
logger.debug('*** %s', connection)
|
|
5450
5485
|
if connection_handle in self.connections:
|
|
5451
5486
|
logger.warning(
|
|
5452
5487
|
'new connection reuses the same handle as a previous connection'
|
|
5453
5488
|
)
|
|
5454
|
-
|
|
5455
|
-
# Create a new connection
|
|
5456
|
-
connection = Connection(
|
|
5457
|
-
device=self,
|
|
5458
|
-
handle=connection_handle,
|
|
5459
|
-
transport=PhysicalTransport.BR_EDR,
|
|
5460
|
-
self_address=self.public_address,
|
|
5461
|
-
self_resolvable_address=None,
|
|
5462
|
-
peer_address=peer_address,
|
|
5463
|
-
peer_resolvable_address=None,
|
|
5464
|
-
role=connection_role,
|
|
5465
|
-
parameters=Connection.Parameters(0.0, 0, 0.0),
|
|
5466
|
-
)
|
|
5467
5489
|
self.connections[connection_handle] = connection
|
|
5468
5490
|
|
|
5469
5491
|
self.emit(self.EVENT_CONNECTION, connection)
|
|
@@ -5618,7 +5640,9 @@ class Device(utils.CompositeEventEmitter):
|
|
|
5618
5640
|
|
|
5619
5641
|
# FIXME: Explore a delegate-model for BR/EDR wait connection #56.
|
|
5620
5642
|
@host_event_handler
|
|
5621
|
-
def on_connection_request(
|
|
5643
|
+
def on_connection_request(
|
|
5644
|
+
self, bd_addr: hci.Address, class_of_device: int, link_type: int
|
|
5645
|
+
):
|
|
5622
5646
|
logger.debug(f'*** Connection request: {bd_addr}')
|
|
5623
5647
|
|
|
5624
5648
|
# Handle SCO request.
|
|
@@ -5647,7 +5671,17 @@ class Device(utils.CompositeEventEmitter):
|
|
|
5647
5671
|
# device configuration is set to accept any incoming connection
|
|
5648
5672
|
elif self.classic_accept_any:
|
|
5649
5673
|
# Save pending connection
|
|
5650
|
-
self.
|
|
5674
|
+
self.pending_connections[bd_addr] = Connection(
|
|
5675
|
+
device=self,
|
|
5676
|
+
handle=0,
|
|
5677
|
+
transport=core.PhysicalTransport.BR_EDR,
|
|
5678
|
+
self_address=self.public_address,
|
|
5679
|
+
self_resolvable_address=None,
|
|
5680
|
+
peer_address=bd_addr,
|
|
5681
|
+
peer_resolvable_address=None,
|
|
5682
|
+
role=hci.Role.PERIPHERAL,
|
|
5683
|
+
parameters=Connection.Parameters(0, 0, 0),
|
|
5684
|
+
)
|
|
5651
5685
|
|
|
5652
5686
|
self.host.send_command_sync(
|
|
5653
5687
|
hci.HCI_Accept_Connection_Request_Command(
|
|
@@ -5958,7 +5992,7 @@ class Device(utils.CompositeEventEmitter):
|
|
|
5958
5992
|
@host_event_handler
|
|
5959
5993
|
@try_with_connection_from_address
|
|
5960
5994
|
def on_remote_name(
|
|
5961
|
-
self, connection: Connection, address: hci.Address, remote_name: bytes
|
|
5995
|
+
self, connection: Optional[Connection], address: hci.Address, remote_name: bytes
|
|
5962
5996
|
):
|
|
5963
5997
|
# Try to decode the name
|
|
5964
5998
|
try:
|
|
@@ -5977,7 +6011,7 @@ class Device(utils.CompositeEventEmitter):
|
|
|
5977
6011
|
@host_event_handler
|
|
5978
6012
|
@try_with_connection_from_address
|
|
5979
6013
|
def on_remote_name_failure(
|
|
5980
|
-
self, connection: Connection, address: hci.Address, error: int
|
|
6014
|
+
self, connection: Optional[Connection], address: hci.Address, error: int
|
|
5981
6015
|
):
|
|
5982
6016
|
if connection:
|
|
5983
6017
|
connection.emit(connection.EVENT_REMOTE_NAME_FAILURE, error)
|
|
@@ -6409,21 +6443,20 @@ class Device(utils.CompositeEventEmitter):
|
|
|
6409
6443
|
|
|
6410
6444
|
# [Classic only]
|
|
6411
6445
|
@host_event_handler
|
|
6412
|
-
@
|
|
6446
|
+
@with_connection_from_address
|
|
6413
6447
|
def on_role_change(
|
|
6414
|
-
self,
|
|
6448
|
+
self,
|
|
6449
|
+
connection: Connection,
|
|
6450
|
+
new_role: hci.Role,
|
|
6415
6451
|
):
|
|
6416
|
-
|
|
6417
|
-
|
|
6418
|
-
connection.emit(connection.EVENT_ROLE_CHANGE, new_role)
|
|
6419
|
-
else:
|
|
6420
|
-
self.connection_roles[peer_address] = new_role
|
|
6452
|
+
connection.role = new_role
|
|
6453
|
+
connection.emit(connection.EVENT_ROLE_CHANGE, new_role)
|
|
6421
6454
|
|
|
6422
6455
|
# [Classic only]
|
|
6423
6456
|
@host_event_handler
|
|
6424
6457
|
@try_with_connection_from_address
|
|
6425
6458
|
def on_role_change_failure(
|
|
6426
|
-
self, connection: Connection, address: hci.Address, error: int
|
|
6459
|
+
self, connection: Optional[Connection], address: hci.Address, error: int
|
|
6427
6460
|
):
|
|
6428
6461
|
if connection:
|
|
6429
6462
|
connection.emit(connection.EVENT_ROLE_CHANGE_FAILURE, error)
|
bumble/host.py
CHANGED
|
@@ -550,7 +550,7 @@ class Host(utils.EventEmitter):
|
|
|
550
550
|
logger.debug(
|
|
551
551
|
'HCI LE flow control: '
|
|
552
552
|
f'le_acl_data_packet_length={le_acl_data_packet_length},'
|
|
553
|
-
f'total_num_le_acl_data_packets={total_num_le_acl_data_packets}'
|
|
553
|
+
f'total_num_le_acl_data_packets={total_num_le_acl_data_packets},'
|
|
554
554
|
f'iso_data_packet_length={iso_data_packet_length},'
|
|
555
555
|
f'total_num_iso_data_packets={total_num_iso_data_packets}'
|
|
556
556
|
)
|
bumble/profiles/hap.py
CHANGED
|
@@ -273,12 +273,19 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
273
273
|
def on_disconnection(_reason) -> None:
|
|
274
274
|
self.currently_connected_clients.discard(connection)
|
|
275
275
|
|
|
276
|
+
@connection.on(connection.EVENT_CONNECTION_ATT_MTU_UPDATE)
|
|
277
|
+
def on_mtu_update(*_: Any) -> None:
|
|
278
|
+
self.on_incoming_connection(connection)
|
|
279
|
+
|
|
280
|
+
@connection.on(connection.EVENT_CONNECTION_ENCRYPTION_CHANGE)
|
|
281
|
+
def on_encryption_change(*_: Any) -> None:
|
|
282
|
+
self.on_incoming_connection(connection)
|
|
283
|
+
|
|
276
284
|
@connection.on(connection.EVENT_PAIRING)
|
|
277
285
|
def on_pairing(*_: Any) -> None:
|
|
278
|
-
self.
|
|
286
|
+
self.on_incoming_connection(connection)
|
|
279
287
|
|
|
280
|
-
|
|
281
|
-
self.on_incoming_paired_connection(connection)
|
|
288
|
+
self.on_incoming_connection(connection)
|
|
282
289
|
|
|
283
290
|
self.hearing_aid_features_characteristic = gatt.Characteristic(
|
|
284
291
|
uuid=gatt.GATT_HEARING_AID_FEATURES_CHARACTERISTIC,
|
|
@@ -315,9 +322,30 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
315
322
|
]
|
|
316
323
|
)
|
|
317
324
|
|
|
318
|
-
def
|
|
325
|
+
def on_incoming_connection(self, connection: Connection):
|
|
319
326
|
'''Setup initial operations to handle a remote bonded HAP device'''
|
|
320
327
|
# TODO Should we filter on HAP device only ?
|
|
328
|
+
|
|
329
|
+
if not connection.is_encrypted:
|
|
330
|
+
logging.debug(f'HAS: {connection.peer_address} is not encrypted')
|
|
331
|
+
return
|
|
332
|
+
|
|
333
|
+
if not connection.peer_resolvable_address:
|
|
334
|
+
logging.debug(f'HAS: {connection.peer_address} is not paired')
|
|
335
|
+
return
|
|
336
|
+
|
|
337
|
+
if connection.att_mtu < 49:
|
|
338
|
+
logging.debug(
|
|
339
|
+
f'HAS: {connection.peer_address} invalid MTU={connection.att_mtu}'
|
|
340
|
+
)
|
|
341
|
+
return
|
|
342
|
+
|
|
343
|
+
if connection.peer_address in self.currently_connected_clients:
|
|
344
|
+
logging.debug(
|
|
345
|
+
f'HAS: Already connected to {connection.peer_address} nothing to do'
|
|
346
|
+
)
|
|
347
|
+
return
|
|
348
|
+
|
|
321
349
|
self.currently_connected_clients.add(connection)
|
|
322
350
|
if (
|
|
323
351
|
connection.peer_address
|
|
@@ -457,6 +485,7 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
457
485
|
connection,
|
|
458
486
|
self.hearing_aid_preset_control_point,
|
|
459
487
|
value=op_list[0].to_bytes(len(op_list) == 1),
|
|
488
|
+
force=True, # TODO GATT notification subscription should be persistent
|
|
460
489
|
)
|
|
461
490
|
# Remove item once sent, and keep the non sent item in the list
|
|
462
491
|
op_list.pop(0)
|
|
@@ -131,7 +131,11 @@ def publish_grpc_port(grpc_port: int, instance_number: int) -> bool:
|
|
|
131
131
|
|
|
132
132
|
def cleanup():
|
|
133
133
|
logger.debug("removing .ini file")
|
|
134
|
-
|
|
134
|
+
try:
|
|
135
|
+
ini_file.unlink()
|
|
136
|
+
except OSError as error:
|
|
137
|
+
# Don't log at exception level, since this may happen normally.
|
|
138
|
+
logger.debug(f'failed to remove .ini file ({error})')
|
|
135
139
|
|
|
136
140
|
atexit.register(cleanup)
|
|
137
141
|
return True
|
bumble/transport/serial.py
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
# -----------------------------------------------------------------------------
|
|
18
18
|
import asyncio
|
|
19
19
|
import logging
|
|
20
|
+
from typing import Optional
|
|
20
21
|
|
|
21
22
|
import serial_asyncio
|
|
22
23
|
|
|
@@ -28,25 +29,56 @@ from bumble.transport.common import StreamPacketSink, StreamPacketSource, Transp
|
|
|
28
29
|
logger = logging.getLogger(__name__)
|
|
29
30
|
|
|
30
31
|
|
|
32
|
+
# -----------------------------------------------------------------------------
|
|
33
|
+
# Constants
|
|
34
|
+
# -----------------------------------------------------------------------------
|
|
35
|
+
DEFAULT_POST_OPEN_DELAY = 0.5 # in seconds
|
|
36
|
+
|
|
37
|
+
# -----------------------------------------------------------------------------
|
|
38
|
+
# Classes and Functions
|
|
39
|
+
# -----------------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# -----------------------------------------------------------------------------
|
|
43
|
+
class SerialPacketSource(StreamPacketSource):
|
|
44
|
+
def __init__(self) -> None:
|
|
45
|
+
super().__init__()
|
|
46
|
+
self._ready = asyncio.Event()
|
|
47
|
+
|
|
48
|
+
async def wait_until_ready(self) -> None:
|
|
49
|
+
await self._ready.wait()
|
|
50
|
+
|
|
51
|
+
def connection_made(self, transport: asyncio.BaseTransport) -> None:
|
|
52
|
+
logger.debug('connection made')
|
|
53
|
+
self._ready.set()
|
|
54
|
+
|
|
55
|
+
def connection_lost(self, exc: Optional[Exception]) -> None:
|
|
56
|
+
logger.debug('connection lost')
|
|
57
|
+
self.on_transport_lost()
|
|
58
|
+
|
|
59
|
+
|
|
31
60
|
# -----------------------------------------------------------------------------
|
|
32
61
|
async def open_serial_transport(spec: str) -> Transport:
|
|
33
62
|
'''
|
|
34
63
|
Open a serial port transport.
|
|
35
64
|
The parameter string has this syntax:
|
|
36
|
-
<device-path>[,<speed>][,rtscts][,dsrdtr]
|
|
65
|
+
<device-path>[,<speed>][,rtscts][,dsrdtr][,delay]
|
|
37
66
|
When <speed> is omitted, the default value of 1000000 is used
|
|
38
67
|
When "rtscts" is specified, RTS/CTS hardware flow control is enabled
|
|
39
68
|
When "dsrdtr" is specified, DSR/DTR hardware flow control is enabled
|
|
69
|
+
When "delay" is specified, a short delay is added after opening the port
|
|
40
70
|
|
|
41
71
|
Examples:
|
|
42
72
|
/dev/tty.usbmodem0006839912172
|
|
43
73
|
/dev/tty.usbmodem0006839912172,1000000
|
|
44
74
|
/dev/tty.usbmodem0006839912172,rtscts
|
|
75
|
+
/dev/tty.usbmodem0006839912172,rtscts,delay
|
|
45
76
|
'''
|
|
46
77
|
|
|
47
78
|
speed = 1000000
|
|
48
79
|
rtscts = False
|
|
49
80
|
dsrdtr = False
|
|
81
|
+
delay = 0.0
|
|
50
82
|
if ',' in spec:
|
|
51
83
|
parts = spec.split(',')
|
|
52
84
|
device = parts[0]
|
|
@@ -55,13 +87,16 @@ async def open_serial_transport(spec: str) -> Transport:
|
|
|
55
87
|
rtscts = True
|
|
56
88
|
elif part == 'dsrdtr':
|
|
57
89
|
dsrdtr = True
|
|
90
|
+
elif part == 'delay':
|
|
91
|
+
delay = DEFAULT_POST_OPEN_DELAY
|
|
58
92
|
elif part.isnumeric():
|
|
59
93
|
speed = int(part)
|
|
60
94
|
else:
|
|
61
95
|
device = spec
|
|
96
|
+
|
|
62
97
|
serial_transport, packet_source = await serial_asyncio.create_serial_connection(
|
|
63
98
|
asyncio.get_running_loop(),
|
|
64
|
-
|
|
99
|
+
SerialPacketSource,
|
|
65
100
|
device,
|
|
66
101
|
baudrate=speed,
|
|
67
102
|
rtscts=rtscts,
|
|
@@ -69,4 +104,23 @@ async def open_serial_transport(spec: str) -> Transport:
|
|
|
69
104
|
)
|
|
70
105
|
packet_sink = StreamPacketSink(serial_transport)
|
|
71
106
|
|
|
107
|
+
logger.debug('waiting for the port to be ready')
|
|
108
|
+
await packet_source.wait_until_ready()
|
|
109
|
+
logger.debug('port is ready')
|
|
110
|
+
|
|
111
|
+
# Try to assert DTR
|
|
112
|
+
assert serial_transport.serial is not None
|
|
113
|
+
try:
|
|
114
|
+
serial_transport.serial.dtr = True
|
|
115
|
+
logger.debug(
|
|
116
|
+
f"DSR={serial_transport.serial.dsr}, DTR={serial_transport.serial.dtr}"
|
|
117
|
+
)
|
|
118
|
+
except Exception as e:
|
|
119
|
+
logger.warning(f'could not assert DTR: {e}')
|
|
120
|
+
|
|
121
|
+
# Wait a bit after opening the port, if requested
|
|
122
|
+
if delay > 0.0:
|
|
123
|
+
logger.debug(f'waiting {delay} seconds after opening the port')
|
|
124
|
+
await asyncio.sleep(delay)
|
|
125
|
+
|
|
72
126
|
return Transport(packet_source, packet_sink)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
bumble/__init__.py,sha256=Q8jkz6rgl95IMAeInQVt_2GLoJl3DcEP2cxtrQ-ho5c,110
|
|
2
|
-
bumble/_version.py,sha256=
|
|
2
|
+
bumble/_version.py,sha256=PoO2jYBkVti2LSUuEHv8sargBSqX0YyvJ9djrfZmGJs,708
|
|
3
3
|
bumble/a2dp.py,sha256=sVo3w6qSsGm7Ttsqu4zeTO_Gfo63a7STTlJnaq8iJ-M,32031
|
|
4
4
|
bumble/at.py,sha256=u93DzB5Ghrxks_ufuUqoYV2RUSowLNLMDhq_j9GrCBc,3108
|
|
5
5
|
bumble/att.py,sha256=vS1dUwiuUgNU6PztARg_qPB_olLOWsAxFz6DZGX8zII,33423
|
|
@@ -15,7 +15,7 @@ bumble/controller.py,sha256=oIo6_3Y2_lhMPn0MUfEEN8997ry1blzT2rTUQabQwv8,68282
|
|
|
15
15
|
bumble/core.py,sha256=QojIUs4nP9qo_r-FWPVxHrCdVSg6CaIzHf6GVPTuu9s,94583
|
|
16
16
|
bumble/data_types.py,sha256=jLELcRiUcvRc4JcEo6vMO9kZmumZ9WuibFN-AK7ZYbc,32831
|
|
17
17
|
bumble/decoder.py,sha256=0-VNWZT-u7lvK3qBpAuYT0M6Rz_bMgMi4CjfUXX_6RM,9728
|
|
18
|
-
bumble/device.py,sha256=
|
|
18
|
+
bumble/device.py,sha256=pV8krw94d42c0hml_XG8v0hSjb7DXLwgs5U2sgIbXNc,251491
|
|
19
19
|
bumble/gap.py,sha256=j5mevt__i_fSdIc_B3x7YvCJLeCc7bVq8omRphxwXNw,2144
|
|
20
20
|
bumble/gatt.py,sha256=dBd-opQVUumlLPGw7EYZM5DF-ssnym3LsxhskAJMhig,34552
|
|
21
21
|
bumble/gatt_adapters.py,sha256=9uN2uXGIdlvNeSvv3nfwxCEa15uPfm5DVLR5bog_knI,13190
|
|
@@ -25,7 +25,7 @@ bumble/hci.py,sha256=2yEJnR6JBtxK6ghituuXCbSalifevnTqvPvnCjyrtAo,327200
|
|
|
25
25
|
bumble/helpers.py,sha256=WFyikseIRdXUqqeOplNlmd0giOegahlXv5e324ax9ck,12611
|
|
26
26
|
bumble/hfp.py,sha256=0ktRzzRSSwGVcmw_jZlayYjvPUGhzlWZY5fVuSH6FcE,76680
|
|
27
27
|
bumble/hid.py,sha256=UCPGHw-jm4i4Akk9pXVEL8_i6EdOwaOuqv2Xd_8EhXo,21054
|
|
28
|
-
bumble/host.py,sha256=
|
|
28
|
+
bumble/host.py,sha256=46fwcskNlfHyW8Ejo5wp8rHtMBZSMkR4URSdekKLPzg,68019
|
|
29
29
|
bumble/keys.py,sha256=VCOrtuw-xF_4Oa5Qt-ECRKaTqabL_GbwdQUKoZX20II,13416
|
|
30
30
|
bumble/l2cap.py,sha256=PZQnZQFB_GJZCCFuPpAsTuYz4E3WTgimDUAk83DUUtE,80758
|
|
31
31
|
bumble/link.py,sha256=O-T9fCJokvpLpTvIMAboEQbT3Sjg8L2ivSWSBH43fP0,14470
|
|
@@ -100,7 +100,7 @@ bumble/profiles/device_information_service.py,sha256=oQ4bWPq-LxlJth4H39H8xc06ulj
|
|
|
100
100
|
bumble/profiles/gap.py,sha256=Fd-J2_d6TdWDyBPDmvEykQPYzkE_T9UGNoiP5uQ6FJg,4026
|
|
101
101
|
bumble/profiles/gatt_service.py,sha256=WVAuW9q-01jmpjpUVG7Gs4vZE_CSLAo51FSK5HDE4tA,6697
|
|
102
102
|
bumble/profiles/gmap.py,sha256=jNsPobH_lSDZQ4-jwlDRhNfpPWPsXcWFJbCCXGTWZQk,7327
|
|
103
|
-
bumble/profiles/hap.py,sha256=
|
|
103
|
+
bumble/profiles/hap.py,sha256=yU-G12ykmj6NVD4f5M1IHV9FAiG83Cy7Dx-3nkI_rzY,26536
|
|
104
104
|
bumble/profiles/heart_rate_service.py,sha256=VB2CKSG2p5GDb5C_q1elpwzKEIIR7slrJfgf4kdTu30,9252
|
|
105
105
|
bumble/profiles/le_audio.py,sha256=w8Ui2AKvt_tDpRXY8AZjlYR-P90caRahBWM3KJ97nRw,5829
|
|
106
106
|
bumble/profiles/mcp.py,sha256=gWB8FqVi7wA8zBsPrh__p_57u4EHwVhA10_YdJXR40c,17763
|
|
@@ -118,14 +118,14 @@ bumble/tools/rtk_fw_download.py,sha256=kuJ2q-75Troc9hCrow0q5zKSMsVhocMeWHKvfdg6H
|
|
|
118
118
|
bumble/tools/rtk_util.py,sha256=4kdaHON_pg2HElzBRaStolqvEJVWPd0eZPUyAQWAqxc,5726
|
|
119
119
|
bumble/transport/__init__.py,sha256=Dk84_3nAC24jY5zcCWVhjC2RxjJahKTz4zChygAqlvs,7027
|
|
120
120
|
bumble/transport/android_emulator.py,sha256=axEdFBj17c0dOD5lMqJjiULInG_SQVx5W7ptjyLtRJs,4281
|
|
121
|
-
bumble/transport/android_netsim.py,sha256=
|
|
121
|
+
bumble/transport/android_netsim.py,sha256=8C2kUITCl7L1ggl5FPwWcFq4It8e9O3esEpMjRaYkkw,17563
|
|
122
122
|
bumble/transport/common.py,sha256=C0wurvCvcEX4r6F0cWbD2x1GhamJwJoyYmYJ21pU04Q,16770
|
|
123
123
|
bumble/transport/file.py,sha256=aqJD5US5TVl01dOb42rV_0OzuvFsBDDlqzipyrYA4q4,2026
|
|
124
124
|
bumble/transport/hci_socket.py,sha256=2PKQ43oDjayKDklx9sF98hSeyNmvTSUOWx_ooPWTjd0,6345
|
|
125
125
|
bumble/transport/pty.py,sha256=yzItc5ZO7WkHZKnAeEK-1XEyY4BWot4ZAMFzQvRiSQ4,2747
|
|
126
126
|
bumble/transport/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
127
127
|
bumble/transport/pyusb.py,sha256=x1uXCVSs-h0dxhOuJ60RkmuuYrcTrxDngFkW8cWEPc4,16187
|
|
128
|
-
bumble/transport/serial.py,sha256=
|
|
128
|
+
bumble/transport/serial.py,sha256=lQsdpv3VHKJwrAgHWnft2pNEzevEHHVutA2SvQNSCpY,4343
|
|
129
129
|
bumble/transport/tcp_client.py,sha256=YM7Y9CN0fBSGSb9dPiOAXAUC9R1fRRwYG4HiP2rvDyc,1883
|
|
130
130
|
bumble/transport/tcp_server.py,sha256=7ZPk097pKbMJBvyTRSrJXla4RDU6SBJ-DeQmSK54mHM,3755
|
|
131
131
|
bumble/transport/udp.py,sha256=_3mePVr9ALzZbOfnlMwcaaMnnLkd5kxhw5-BxkeCSMU,2281
|
|
@@ -175,9 +175,9 @@ bumble/vendor/android/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
|
175
175
|
bumble/vendor/android/hci.py,sha256=LcV4_OBpzoLtpSiP2su7F4r3bDrHWxcQPR4OGnMVXDk,10485
|
|
176
176
|
bumble/vendor/zephyr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
177
177
|
bumble/vendor/zephyr/hci.py,sha256=ysct40uIVohaKKLrWjcWo-7YqozU17xGia2dWeHoMoI,3435
|
|
178
|
-
bumble-0.0.
|
|
179
|
-
bumble-0.0.
|
|
180
|
-
bumble-0.0.
|
|
181
|
-
bumble-0.0.
|
|
182
|
-
bumble-0.0.
|
|
183
|
-
bumble-0.0.
|
|
178
|
+
bumble-0.0.217.dist-info/licenses/LICENSE,sha256=FvaYh4NRWIGgS_OwoBs5gFgkCmAghZ-DYnIGBZPuw-s,12142
|
|
179
|
+
bumble-0.0.217.dist-info/METADATA,sha256=Mdy5v7BSROxcolAFXgbeSX1fX0lOAQW319HWJNcwicg,6155
|
|
180
|
+
bumble-0.0.217.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
181
|
+
bumble-0.0.217.dist-info/entry_points.txt,sha256=mX5dzixNMRo4CTAEQqiYTr-JIaWF62TYrRvJOstjjL8,1081
|
|
182
|
+
bumble-0.0.217.dist-info/top_level.txt,sha256=tV6JJKaHPYMFiJYiBYFW24PCcfLxTJZdlu6BmH3Cb00,7
|
|
183
|
+
bumble-0.0.217.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|