mirror of
https://github.com/google/bumble.git
synced 2026-04-16 00:25:31 +00:00
Merge pull request #502 from google/gbg/extended-advertising-termination-reverse
support out of order advertising set termination / connection events
This commit is contained in:
@@ -1856,6 +1856,7 @@ class Device(CompositeEventEmitter):
|
||||
|
||||
# Extended advertising.
|
||||
self.extended_advertising_sets: Dict[int, AdvertisingSet] = {}
|
||||
self.connecting_extended_advertising_sets: Dict[int, AdvertisingSet] = {}
|
||||
|
||||
# Legacy advertising.
|
||||
# The advertising and scan response data, as well as the advertising interval
|
||||
@@ -4009,14 +4010,28 @@ class Device(CompositeEventEmitter):
|
||||
)
|
||||
return
|
||||
|
||||
if not (connection := self.lookup_connection(connection_handle)):
|
||||
logger.warning(f'no connection for handle 0x{connection_handle:04x}')
|
||||
if connection := self.lookup_connection(connection_handle):
|
||||
# We have already received the connection complete event.
|
||||
self._complete_le_extended_advertising_connection(
|
||||
connection, advertising_set
|
||||
)
|
||||
return
|
||||
|
||||
# Associate the connection handle with the advertising set, the connection
|
||||
# will complete later.
|
||||
logger.debug(
|
||||
f'the connection with handle {connection_handle:04X} will complete later'
|
||||
)
|
||||
self.connecting_extended_advertising_sets[connection_handle] = advertising_set
|
||||
|
||||
def _complete_le_extended_advertising_connection(
|
||||
self, connection: Connection, advertising_set: AdvertisingSet
|
||||
) -> None:
|
||||
# Update the connection address.
|
||||
connection.self_address = (
|
||||
advertising_set.random_address
|
||||
if advertising_set.advertising_parameters.own_address_type
|
||||
if advertising_set.random_address is not None
|
||||
and advertising_set.advertising_parameters.own_address_type
|
||||
in (OwnAddressType.RANDOM, OwnAddressType.RESOLVABLE_OR_RANDOM)
|
||||
else self.public_address
|
||||
)
|
||||
@@ -4147,6 +4162,16 @@ class Device(CompositeEventEmitter):
|
||||
if role == HCI_CENTRAL_ROLE or not self.supports_le_extended_advertising:
|
||||
# We can emit now, we have all the info we need
|
||||
self._emit_le_connection(connection)
|
||||
return
|
||||
|
||||
if role == HCI_PERIPHERAL_ROLE and self.supports_le_extended_advertising:
|
||||
if advertising_set := self.connecting_extended_advertising_sets.pop(
|
||||
connection_handle, None
|
||||
):
|
||||
# We have already received the advertising set termination event.
|
||||
self._complete_le_extended_advertising_connection(
|
||||
connection, advertising_set
|
||||
)
|
||||
|
||||
@host_event_handler
|
||||
def on_connection_failure(self, transport, peer_address, error_code):
|
||||
|
||||
@@ -787,6 +787,10 @@ class Host(AbortableEventEmitter):
|
||||
# Just use the same implementation as for the non-enhanced event for now
|
||||
self.on_hci_le_connection_complete_event(event)
|
||||
|
||||
def on_hci_le_enhanced_connection_complete_v2_event(self, event):
|
||||
# Just use the same implementation as for the v1 event for now
|
||||
self.on_hci_le_enhanced_connection_complete_event(event)
|
||||
|
||||
def on_hci_connection_complete_event(self, event):
|
||||
if event.status == hci.HCI_SUCCESS:
|
||||
# Create/update the connection
|
||||
|
||||
@@ -301,9 +301,7 @@ async def test_legacy_advertising_connection(own_address_type):
|
||||
else:
|
||||
assert device.lookup_connection(0x0001).self_address == device.random_address
|
||||
|
||||
# For unknown reason, read_phy() in on_connection() would be killed at the end of
|
||||
# test, so we force scheduling here to avoid an warning.
|
||||
await asyncio.sleep(0.0001)
|
||||
await async_barrier()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -384,9 +382,41 @@ async def test_extended_advertising_connection(own_address_type):
|
||||
else:
|
||||
assert device.lookup_connection(0x0001).self_address == device.random_address
|
||||
|
||||
# For unknown reason, read_phy() in on_connection() would be killed at the end of
|
||||
# test, so we force scheduling here to avoid an warning.
|
||||
await asyncio.sleep(0.0001)
|
||||
await async_barrier()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@pytest.mark.parametrize(
|
||||
'own_address_type,',
|
||||
(OwnAddressType.PUBLIC, OwnAddressType.RANDOM),
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_extended_advertising_connection_out_of_order(own_address_type):
|
||||
device = Device(host=mock.AsyncMock(spec=Host))
|
||||
peer_address = Address('F0:F1:F2:F3:F4:F5')
|
||||
advertising_set = await device.create_advertising_set(
|
||||
advertising_parameters=AdvertisingParameters(own_address_type=own_address_type)
|
||||
)
|
||||
device.on_advertising_set_termination(
|
||||
HCI_SUCCESS,
|
||||
advertising_set.advertising_handle,
|
||||
0x0001,
|
||||
0,
|
||||
)
|
||||
device.on_connection(
|
||||
0x0001,
|
||||
BT_LE_TRANSPORT,
|
||||
peer_address,
|
||||
BT_PERIPHERAL_ROLE,
|
||||
ConnectionParameters(0, 0, 0),
|
||||
)
|
||||
|
||||
if own_address_type == OwnAddressType.PUBLIC:
|
||||
assert device.lookup_connection(0x0001).self_address == device.public_address
|
||||
else:
|
||||
assert device.lookup_connection(0x0001).self_address == device.random_address
|
||||
|
||||
await async_barrier()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user